mirror of
https://github.com/ckaczor/azuredatastudio.git
synced 2026-04-01 01:20:31 -04:00
Revert "Revert "Merge from vscode ada4bddb8edc69eea6ebaaa0e88c5f903cbd43d8 (#5529)" (#5553)" (#5562)
This reverts commit c9a4f8f664.
This commit is contained in:
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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 };
|
||||
}
|
||||
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@@ -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
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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,
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@@ -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, {});
|
||||
}
|
||||
|
||||
@@ -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';
|
||||
|
||||
@@ -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,
|
||||
@@ -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
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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];
|
||||
|
||||
@@ -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);
|
||||
}));
|
||||
}
|
||||
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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[] = [];
|
||||
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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';
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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}}
|
||||
|
||||
@@ -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,
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
@@ -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> {
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
@@ -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';
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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 });
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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();
|
||||
});
|
||||
});
|
||||
|
||||
@@ -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());
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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 };
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -52,6 +52,7 @@ export class PerfviewInput extends ResourceEditorInput {
|
||||
localize('name', "Startup Performance"),
|
||||
null,
|
||||
PerfviewInput.Uri,
|
||||
undefined,
|
||||
textModelResolverService
|
||||
);
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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();
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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';
|
||||
|
||||
@@ -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', () => {
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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 }
|
||||
});
|
||||
}
|
||||
|
||||
@@ -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';
|
||||
|
||||
@@ -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[] {
|
||||
|
||||
@@ -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
|
||||
};
|
||||
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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}`;
|
||||
}
|
||||
|
||||
@@ -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');
|
||||
|
||||
@@ -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
|
||||
}]
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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: [{
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
@@ -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`,
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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));
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@@ -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' });
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -47,7 +47,7 @@ export interface WebviewContentOptions {
|
||||
|
||||
export interface Webview {
|
||||
|
||||
contents: string;
|
||||
html: string;
|
||||
options: WebviewContentOptions;
|
||||
initialScrollProgress: number;
|
||||
state: string | undefined;
|
||||
|
||||
@@ -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() {
|
||||
|
||||
@@ -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__
|
||||
|
||||
Reference in New Issue
Block a user