mirror of
https://github.com/ckaczor/azuredatastudio.git
synced 2026-02-15 18:46:36 -05:00
Merge from vscode 8df646d3c5477b02737fc10343fa7cf0cc3f606b
This commit is contained in:
@@ -20,7 +20,7 @@ import { IContextKeyService } from 'vs/platform/contextkey/common/contextkey';
|
||||
import { WorkbenchAsyncDataTree, IListService } from 'vs/platform/list/browser/listService';
|
||||
import { IThemeService } from 'vs/platform/theme/common/themeService';
|
||||
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
|
||||
import { PANEL_BACKGROUND } from 'vs/workbench/common/theme';
|
||||
import { IColorMapping } from 'vs/platform/theme/common/styler';
|
||||
|
||||
export const COMMENTS_VIEW_ID = 'workbench.panel.comments';
|
||||
export const COMMENTS_VIEW_TITLE = 'Comments';
|
||||
@@ -149,10 +149,15 @@ export class CommentNodeRenderer implements IListRenderer<ITreeNode<CommentNode>
|
||||
}
|
||||
}
|
||||
|
||||
export interface ICommentsListOptions {
|
||||
overrideStyles?: IColorMapping;
|
||||
}
|
||||
|
||||
export class CommentsList extends WorkbenchAsyncDataTree<any, any> {
|
||||
constructor(
|
||||
labels: ResourceLabels,
|
||||
container: HTMLElement,
|
||||
options: ICommentsListOptions,
|
||||
@IContextKeyService contextKeyService: IContextKeyService,
|
||||
@IListService listService: IListService,
|
||||
@IThemeService themeService: IThemeService,
|
||||
@@ -202,9 +207,7 @@ export class CommentsList extends WorkbenchAsyncDataTree<any, any> {
|
||||
collapseByDefault: () => {
|
||||
return false;
|
||||
},
|
||||
overrideStyles: {
|
||||
listBackground: PANEL_BACKGROUND
|
||||
}
|
||||
overrideStyles: options.overrideStyles
|
||||
},
|
||||
contextKeyService,
|
||||
listService,
|
||||
|
||||
@@ -149,7 +149,7 @@ export class CommentsPanel extends ViewPane {
|
||||
|
||||
private createTree(): void {
|
||||
this.treeLabels = this._register(this.instantiationService.createInstance(ResourceLabels, this));
|
||||
this.tree = this._register(this.instantiationService.createInstance(CommentsList, this.treeLabels, this.treeContainer));
|
||||
this.tree = this._register(this.instantiationService.createInstance(CommentsList, this.treeLabels, this.treeContainer, { overrideStyles: { listBackground: this.getBackgroundColor() } }));
|
||||
|
||||
const commentsNavigator = this._register(ResourceNavigator.createTreeResourceNavigator(this.tree, { openOnFocus: true }));
|
||||
this._register(commentsNavigator.onDidOpenResource(e => {
|
||||
|
||||
@@ -13,7 +13,7 @@ import { generateUuid } from 'vs/base/common/uuid';
|
||||
import * as nls from 'vs/nls';
|
||||
import { IConfigurationService } from 'vs/platform/configuration/common/configuration';
|
||||
import { IContextKey, IContextKeyService } from 'vs/platform/contextkey/common/contextkey';
|
||||
import { IEditorOptions, ITextEditorOptions } from 'vs/platform/editor/common/editor';
|
||||
import { EditorActivation, IEditorOptions, ITextEditorOptions } from 'vs/platform/editor/common/editor';
|
||||
import { FileOperation, IFileService } from 'vs/platform/files/common/files';
|
||||
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
|
||||
import { IQuickInputService, IQuickPickItem } from 'vs/platform/quickinput/common/quickInput';
|
||||
@@ -21,16 +21,16 @@ import * as colorRegistry from 'vs/platform/theme/common/colorRegistry';
|
||||
import { registerThemingParticipant } from 'vs/platform/theme/common/themeService';
|
||||
import { EditorServiceImpl } from 'vs/workbench/browser/parts/editor/editor';
|
||||
import { IWorkbenchContribution } from 'vs/workbench/common/contributions';
|
||||
import { EditorInput, EditorOptions, IEditorInput, IEditorPane, GroupIdentifier } from 'vs/workbench/common/editor';
|
||||
import { EditorInput, EditorOptions, GroupIdentifier, IEditorInput, IEditorPane } from 'vs/workbench/common/editor';
|
||||
import { DiffEditorInput } from 'vs/workbench/common/editor/diffEditorInput';
|
||||
import { webviewEditorsExtensionPoint } from 'vs/workbench/contrib/customEditor/browser/extensionPoint';
|
||||
import { CONTEXT_CUSTOM_EDITORS, CONTEXT_FOCUSED_CUSTOM_EDITOR_IS_EDITABLE, CustomEditorInfo, CustomEditorInfoCollection, CustomEditorPriority, CustomEditorSelector, ICustomEditorService } from 'vs/workbench/contrib/customEditor/common/customEditor';
|
||||
import { CustomEditorModelManager } from 'vs/workbench/contrib/customEditor/common/customEditorModelManager';
|
||||
import { FileEditorInput } from 'vs/workbench/contrib/files/common/editors/fileEditorInput';
|
||||
import { IWebviewService, webviewHasOwnEditFunctionsContext } from 'vs/workbench/contrib/webview/browser/webview';
|
||||
import { IEditorGroup, IEditorGroupsService } from 'vs/workbench/services/editor/common/editorGroupsService';
|
||||
import { IEditorService, IOpenEditorOverride } from 'vs/workbench/services/editor/common/editorService';
|
||||
import { CustomEditorInput } from './customEditorInput';
|
||||
import { FileEditorInput } from 'vs/workbench/contrib/files/common/editors/fileEditorInput';
|
||||
|
||||
export const defaultEditorId = 'default';
|
||||
|
||||
@@ -284,6 +284,10 @@ export class CustomEditorService extends Disposable implements ICustomEditorServ
|
||||
): Promise<IEditorPane | undefined> {
|
||||
const targetGroup = group || this.editorGroupService.activeGroup;
|
||||
|
||||
if (options && typeof options.activation === 'undefined') {
|
||||
options = { ...options, activation: options.preserveFocus ? EditorActivation.RESTORE : undefined };
|
||||
}
|
||||
|
||||
// Try to replace existing editors for resource
|
||||
const existingEditors = targetGroup.editors.filter(editor => editor.resource && isEqual(editor.resource, resource));
|
||||
if (existingEditors.length) {
|
||||
@@ -454,7 +458,11 @@ export class CustomEditorContribution extends Disposable implements IWorkbenchCo
|
||||
const existingEditorForResource = group.editors.find(editor => isEqual(resource, editor.resource));
|
||||
if (existingEditorForResource) {
|
||||
return {
|
||||
override: this.editorService.openEditor(existingEditorForResource, { ...options, ignoreOverrides: true }, group)
|
||||
override: this.editorService.openEditor(existingEditorForResource, {
|
||||
...options,
|
||||
ignoreOverrides: true,
|
||||
activation: options?.preserveFocus ? EditorActivation.RESTORE : undefined,
|
||||
}, group)
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@@ -96,6 +96,7 @@ const VIEW_CONTAINER: ViewContainer = Registry.as<IViewContainersRegistry>(ViewE
|
||||
id: OpenDebugPanelAction.ID,
|
||||
keybindings: openPanelKb
|
||||
},
|
||||
order: 3,
|
||||
hideIfEmpty: true
|
||||
}, ViewContainerLocation.Panel);
|
||||
|
||||
|
||||
@@ -234,7 +234,7 @@ export class DebugSession implements IDebugSession {
|
||||
|
||||
this.initialized = true;
|
||||
this._onDidChangeState.fire();
|
||||
this.model.setExceptionBreakpoints(this.raw!.capabilities.exceptionBreakpointFilters || []);
|
||||
this.model.setExceptionBreakpoints((this.raw && this.raw.capabilities.exceptionBreakpointFilters) || []);
|
||||
} catch (err) {
|
||||
this.initialized = true;
|
||||
this._onDidChangeState.fire();
|
||||
|
||||
@@ -208,9 +208,20 @@ export class Repl extends ViewPane implements IHistoryNavigationWidget {
|
||||
}));
|
||||
this._register(this.configurationService.onDidChangeConfiguration(e => {
|
||||
if (e.affectsConfiguration('debug.console.lineHeight') || e.affectsConfiguration('debug.console.fontSize') || e.affectsConfiguration('debug.console.fontFamily')) {
|
||||
this.onDidFontChange();
|
||||
this.onDidStyleChange();
|
||||
}
|
||||
}));
|
||||
|
||||
this._register(this.themeService.onDidColorThemeChange(e => {
|
||||
this.onDidStyleChange();
|
||||
}));
|
||||
|
||||
this._register(this.viewDescriptorService.onDidChangeLocation(e => {
|
||||
if (e.views.some(v => v.id === this.id)) {
|
||||
this.onDidStyleChange();
|
||||
}
|
||||
}));
|
||||
|
||||
this._register(this.editorService.onDidActiveEditorChange(() => {
|
||||
this.setMode();
|
||||
}));
|
||||
@@ -253,14 +264,15 @@ export class Repl extends ViewPane implements IHistoryNavigationWidget {
|
||||
}
|
||||
}
|
||||
|
||||
private onDidFontChange(): void {
|
||||
private onDidStyleChange(): void {
|
||||
if (this.styleElement) {
|
||||
const debugConsole = this.configurationService.getValue<IDebugConfiguration>('debug').console;
|
||||
const fontSize = debugConsole.fontSize;
|
||||
const fontFamily = debugConsole.fontFamily === 'default' ? 'var(--monaco-monospace-font)' : debugConsole.fontFamily;
|
||||
const lineHeight = debugConsole.lineHeight ? `${debugConsole.lineHeight}px` : '1.4em';
|
||||
const backgroundColor = this.themeService.getColorTheme().getColor(this.getBackgroundColor());
|
||||
|
||||
// Set the font size, font family, line height and align the twistie to be centered
|
||||
// Set the font size, font family, line height and align the twistie to be centered, and input theme color
|
||||
this.styleElement.innerHTML = `
|
||||
.repl .repl-tree .expression {
|
||||
font-size: ${fontSize}px;
|
||||
@@ -274,6 +286,10 @@ export class Repl extends ViewPane implements IHistoryNavigationWidget {
|
||||
.repl .repl-tree .monaco-tl-twistie {
|
||||
background-position-y: calc(100% - ${fontSize * 1.4 / 2 - 8}px);
|
||||
}
|
||||
|
||||
.repl .repl-input-wrapper .monaco-editor .lines-content {
|
||||
background-color: ${backgroundColor};
|
||||
}
|
||||
`;
|
||||
|
||||
this.tree.rerender();
|
||||
@@ -510,7 +526,7 @@ export class Repl extends ViewPane implements IHistoryNavigationWidget {
|
||||
// Make sure to select the session if debugging is already active
|
||||
this.selectSession();
|
||||
this.styleElement = dom.createStyleSheet(this.container);
|
||||
this.onDidFontChange();
|
||||
this.onDidStyleChange();
|
||||
}
|
||||
|
||||
private createReplInput(container: HTMLElement): void {
|
||||
|
||||
@@ -80,8 +80,11 @@ export class VariablesView extends ViewPane {
|
||||
if (stackFrame) {
|
||||
const scopes = await stackFrame.getScopes();
|
||||
// Expand the first scope if it is not expensive and if there is no expansion state (all are collapsed)
|
||||
if (scopes.every(s => this.tree.getNode(s).collapsed) && scopes.length > 0 && !scopes[0].expensive) {
|
||||
this.tree.expand(scopes[0]);
|
||||
if (scopes.every(s => this.tree.getNode(s).collapsed) && scopes.length > 0) {
|
||||
const toExpand = scopes.filter(s => !s.expensive).shift();
|
||||
if (toExpand) {
|
||||
this.tree.expand(toExpand);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -305,9 +305,19 @@ export class StackFrame implements IStackFrame {
|
||||
getScopes(): Promise<IScope[]> {
|
||||
if (!this.scopes) {
|
||||
this.scopes = this.thread.session.scopes(this.frameId, this.thread.threadId).then(response => {
|
||||
return response && response.body && response.body.scopes ?
|
||||
response.body.scopes.map((rs, index) => new Scope(this, index, rs.name, rs.variablesReference, rs.expensive, rs.namedVariables, rs.indexedVariables,
|
||||
rs.line && rs.column && rs.endLine && rs.endColumn ? new Range(rs.line, rs.column, rs.endLine, rs.endColumn) : undefined)) : [];
|
||||
if (!response || !response.body || !response.body.scopes) {
|
||||
return [];
|
||||
}
|
||||
|
||||
const scopeNameIndexes = new Map<string, number>();
|
||||
return response.body.scopes.map(rs => {
|
||||
const previousIndex = scopeNameIndexes.get(rs.name);
|
||||
const index = typeof previousIndex === 'number' ? previousIndex + 1 : 0;
|
||||
scopeNameIndexes.set(rs.name, index);
|
||||
return new Scope(this, index, rs.name, rs.variablesReference, rs.expensive, rs.namedVariables, rs.indexedVariables,
|
||||
rs.line && rs.column && rs.endLine && rs.endColumn ? new Range(rs.line, rs.column, rs.endLine, rs.endColumn) : undefined);
|
||||
|
||||
});
|
||||
}, err => [new ErrorScope(this, 0, err.message)]);
|
||||
}
|
||||
|
||||
|
||||
@@ -48,12 +48,10 @@ export class InstallExtensionQuickAccessProvider extends PickerQuickAccessProvid
|
||||
}
|
||||
|
||||
// Extension name typed: offer to search it
|
||||
else {
|
||||
return [genericSearchPickItem];
|
||||
}
|
||||
return [genericSearchPickItem];
|
||||
}
|
||||
|
||||
protected async getPicksForExtensionId(filter: string, fallback: IPickerQuickAccessItem, token: CancellationToken): Promise<Array<IPickerQuickAccessItem | IQuickPickSeparator>> {
|
||||
private async getPicksForExtensionId(filter: string, fallback: IPickerQuickAccessItem, token: CancellationToken): Promise<Array<IPickerQuickAccessItem | IQuickPickSeparator>> {
|
||||
try {
|
||||
const galleryResult = await this.galleryService.query({ names: [filter], pageSize: 1 }, token);
|
||||
if (token.isCancellationRequested) {
|
||||
@@ -63,12 +61,12 @@ export class InstallExtensionQuickAccessProvider extends PickerQuickAccessProvid
|
||||
const galleryExtension = galleryResult.firstPage[0];
|
||||
if (!galleryExtension) {
|
||||
return [fallback];
|
||||
} else {
|
||||
return [{
|
||||
label: localize('install', "Press Enter to install extension '{0}'.", filter),
|
||||
accept: () => this.installExtension(galleryExtension, filter)
|
||||
}];
|
||||
}
|
||||
|
||||
return [{
|
||||
label: localize('install', "Press Enter to install extension '{0}'.", filter),
|
||||
accept: () => this.installExtension(galleryExtension, filter)
|
||||
}];
|
||||
} catch (error) {
|
||||
if (token.isCancellationRequested) {
|
||||
return []; // expected error
|
||||
|
||||
@@ -46,6 +46,7 @@ import { IFilesConfigurationService } from 'vs/workbench/services/filesConfigura
|
||||
import { IWorkingCopyService, IWorkingCopy } from 'vs/workbench/services/workingCopy/common/workingCopyService';
|
||||
import { sequence } from 'vs/base/common/async';
|
||||
import { IWorkingCopyFileService } from 'vs/workbench/services/workingCopy/common/workingCopyFileService';
|
||||
import { once } from 'vs/base/common/functional';
|
||||
|
||||
export const NEW_FILE_COMMAND_ID = 'explorer.newFile';
|
||||
export const NEW_FILE_LABEL = nls.localize('newFile', "New File");
|
||||
@@ -519,9 +520,10 @@ export class GlobalCompareResourcesAction extends Action {
|
||||
return undefined;
|
||||
});
|
||||
|
||||
once(this.quickOpenService.onHide)((() => toDispose.dispose()));
|
||||
|
||||
// Bring up quick open
|
||||
await this.quickOpenService.show('', { autoFocus: { autoFocusSecondEntry: true } });
|
||||
toDispose.dispose(); // make sure to unbind if quick open is closing
|
||||
} else {
|
||||
this.notificationService.info(nls.localize('openFileToCompare', "Open a file first to compare it with another file."));
|
||||
}
|
||||
|
||||
@@ -112,6 +112,7 @@ const VIEW_CONTAINER: ViewContainer = Registry.as<IViewContainersRegistry>(ViewC
|
||||
id: Constants.MARKERS_CONTAINER_ID,
|
||||
name: Messages.MARKERS_PANEL_TITLE_PROBLEMS,
|
||||
hideIfEmpty: true,
|
||||
order: 0,
|
||||
ctorDescriptor: new SyncDescriptor(ViewPaneContainer, [Constants.MARKERS_CONTAINER_ID, Constants.MARKERS_VIEW_STORAGE_ID, { mergeViewWithContainerWhenSingleView: true, donotShowContainerTitleWhenMergedWithContainer: true }]),
|
||||
focusCommand: {
|
||||
id: ToggleMarkersPanelAction.ID, keybindings: {
|
||||
@@ -122,6 +123,7 @@ const VIEW_CONTAINER: ViewContainer = Registry.as<IViewContainersRegistry>(ViewC
|
||||
|
||||
Registry.as<IViewsRegistry>(ViewContainerExtensions.ViewsRegistry).registerViews([{
|
||||
id: Constants.MARKERS_VIEW_ID,
|
||||
containerIcon: 'codicon-warning',
|
||||
name: Messages.MARKERS_PANEL_TITLE_PROBLEMS,
|
||||
canToggleVisibility: false,
|
||||
canMoveView: true,
|
||||
|
||||
@@ -201,6 +201,7 @@ export class NotebookEditor extends BaseEditor implements INotebookEditor {
|
||||
mouseSupport: true,
|
||||
multipleSelectionSupport: false,
|
||||
enableKeyboardNavigation: true,
|
||||
additionalScrollHeight: 0,
|
||||
overrideStyles: {
|
||||
listBackground: editorBackground,
|
||||
listActiveSelectionBackground: editorBackground,
|
||||
@@ -419,6 +420,7 @@ export class NotebookEditor extends BaseEditor implements INotebookEditor {
|
||||
DOM.toggleClass(this.rootElement, 'mid-width', dimension.width < 1000 && dimension.width >= 600);
|
||||
DOM.toggleClass(this.rootElement, 'narrow-width', dimension.width < 600);
|
||||
DOM.size(this.body, dimension.width, dimension.height);
|
||||
this.list?.updateOptions({ additionalScrollHeight: dimension.height });
|
||||
this.list?.layout(dimension.height, dimension.width);
|
||||
this.eventDispatcher?.emit([new NotebookLayoutChangedEvent({ width: true, fontInfo: true }, this.getLayoutInfo())]);
|
||||
}
|
||||
@@ -742,6 +744,13 @@ export const focusedCellIndicator = registerColor('notebook.focusedCellIndicator
|
||||
hc: new Color(new RGBA(0, 73, 122))
|
||||
}, nls.localize('notebook.focusedCellIndicator', "The color of the focused notebook cell indicator."));
|
||||
|
||||
export const notebookOutputContainerColor = registerColor('notebook.outputContainerBackgroundColor', {
|
||||
dark: new Color(new RGBA(255, 255, 255, 0.06)),
|
||||
light: new Color(new RGBA(228, 230, 241)),
|
||||
hc: null
|
||||
}
|
||||
, nls.localize('notebook.outputContainerBackgroundColor', "The Color of the notebook output container background."));
|
||||
|
||||
|
||||
registerThemingParticipant((theme, collector) => {
|
||||
const color = getExtraColor(theme, embeddedEditorBackground, { dark: 'rgba(0, 0, 0, .4)', extra_dark: 'rgba(200, 235, 255, .064)', light: '#f4f4f4', hc: null });
|
||||
@@ -776,10 +785,10 @@ registerThemingParticipant((theme, collector) => {
|
||||
collector.addRule(`.monaco-workbench .part.editor > .content .notebook-editor blockquote { border-color: ${quoteBorder}; }`);
|
||||
}
|
||||
|
||||
const inactiveListItem = theme.getColor('list.inactiveSelectionBackground');
|
||||
const containerBackground = theme.getColor(notebookOutputContainerColor);
|
||||
|
||||
if (inactiveListItem) {
|
||||
collector.addRule(`.monaco-workbench .part.editor > .content .notebook-editor .output { background-color: ${inactiveListItem}; }`);
|
||||
if (containerBackground) {
|
||||
collector.addRule(`.monaco-workbench .part.editor > .content .notebook-editor .output { background-color: ${containerBackground}; }`);
|
||||
}
|
||||
|
||||
const focusedCellIndicatorColor = theme.getColor(focusedCellIndicator);
|
||||
|
||||
@@ -94,9 +94,13 @@ abstract class AbstractCellRenderer {
|
||||
horizontalHasArrows: false,
|
||||
alwaysConsumeMouseWheel: false
|
||||
},
|
||||
overviewRulerLanes: 3,
|
||||
renderLineHighlightOnlyWhenFocus: true,
|
||||
overviewRulerLanes: 0,
|
||||
selectOnLineNumbers: false,
|
||||
lineNumbers: 'off',
|
||||
lineDecorationsWidth: 0,
|
||||
glyphMargin: false,
|
||||
fixedOverflowWidgets: false,
|
||||
lineNumbersMinChars: 1,
|
||||
minimap: { enabled: false },
|
||||
};
|
||||
}
|
||||
|
||||
@@ -15,6 +15,7 @@ import { IQuickInputService, IQuickPickItem } from 'vs/platform/quickinput/commo
|
||||
import { INotebookService } from 'vs/workbench/contrib/notebook/browser/notebookService';
|
||||
import { CodeCellViewModel } from 'vs/workbench/contrib/notebook/browser/viewModel/codeCellViewModel';
|
||||
import { EDITOR_TOP_PADDING, EDITOR_BOTTOM_PADDING } from 'vs/workbench/contrib/notebook/browser/constants';
|
||||
import { IModeService } from 'vs/editor/common/services/modeService';
|
||||
|
||||
interface IMimeTypeRenderer extends IQuickPickItem {
|
||||
index: number;
|
||||
@@ -28,7 +29,8 @@ export class CodeCell extends Disposable {
|
||||
private viewCell: CodeCellViewModel,
|
||||
private templateData: CellRenderTemplate,
|
||||
@INotebookService private notebookService: INotebookService,
|
||||
@IQuickInputService private readonly quickInputService: IQuickInputService
|
||||
@IQuickInputService private readonly quickInputService: IQuickInputService,
|
||||
@IModeService private readonly _modeService: IModeService
|
||||
) {
|
||||
super();
|
||||
|
||||
@@ -85,6 +87,11 @@ export class CodeCell extends Disposable {
|
||||
templateData.editor?.updateOptions({ readOnly: !(viewCell.getEvaluatedMetadata(notebookEditor.viewModel?.metadata).editable) });
|
||||
}));
|
||||
|
||||
this._register(viewCell.onDidChangeLanguage((e) => {
|
||||
const mode = this._modeService.create(e);
|
||||
templateData.editor?.getModel()?.setMode(mode.languageIdentifier);
|
||||
}));
|
||||
|
||||
let cellWidthResizeObserver = getResizesObserver(templateData.editorContainer!, {
|
||||
width: width,
|
||||
height: totalHeight
|
||||
|
||||
@@ -34,6 +34,8 @@ export abstract class BaseCellViewModel extends Disposable {
|
||||
public readonly onDidChangeCursorSelection: Event<void> = this._onDidChangeCursorSelection.event;
|
||||
protected readonly _onDidChangeMetadata: Emitter<NotebookCellMetadata | undefined> = this._register(new Emitter<NotebookCellMetadata | undefined>());
|
||||
public readonly onDidChangeMetadata: Event<NotebookCellMetadata | undefined> = this._onDidChangeMetadata.event;
|
||||
protected readonly _onDidChangeLanguage: Emitter<string> = this._register(new Emitter<string>());
|
||||
public readonly onDidChangeLanguage: Event<string> = this._onDidChangeLanguage.event;
|
||||
get handle() {
|
||||
return this.cell.handle;
|
||||
}
|
||||
@@ -100,6 +102,10 @@ export abstract class BaseCellViewModel extends Disposable {
|
||||
constructor(readonly viewType: string, readonly notebookHandle: number, readonly cell: ICell, public id: string) {
|
||||
super();
|
||||
|
||||
this._register(cell.onDidChangeLanguage((e) => {
|
||||
this._onDidChangeLanguage.fire(e);
|
||||
}));
|
||||
|
||||
this._register(cell.onDidChangeMetadata((e) => {
|
||||
this._onDidChangeMetadata.fire(e);
|
||||
}));
|
||||
|
||||
@@ -89,6 +89,12 @@ export class CodeCellViewModel extends BaseCellViewModel implements ICellViewMod
|
||||
this.layoutChange({ outerWidth: e.value.width, font: e.value.fontInfo });
|
||||
}
|
||||
}));
|
||||
|
||||
this._register(this.onDidChangeLanguage((e) => {
|
||||
if (this._textModel && !this._textModel.isDisposed()) {
|
||||
|
||||
}
|
||||
}));
|
||||
}
|
||||
|
||||
layoutChange(state: CodeCellLayoutChangeEvent) {
|
||||
|
||||
@@ -18,6 +18,9 @@ export class NotebookCellTextModel implements ICell {
|
||||
private _onDidChangeMetadata = new Emitter<NotebookCellMetadata | undefined>();
|
||||
onDidChangeMetadata: Event<NotebookCellMetadata | undefined> = this._onDidChangeMetadata.event;
|
||||
|
||||
private _onDidChangeLanguage = new Emitter<string>();
|
||||
onDidChangeLanguage: Event<string> = this._onDidChangeLanguage.event;
|
||||
|
||||
private _outputs: IOutput[];
|
||||
|
||||
get outputs(): IOutput[] {
|
||||
@@ -44,13 +47,22 @@ export class NotebookCellTextModel implements ICell {
|
||||
this._onDidChangeMetadata.fire(this._metadata);
|
||||
}
|
||||
|
||||
get language() {
|
||||
return this._language;
|
||||
}
|
||||
|
||||
set language(newLanguage: string) {
|
||||
this._language = newLanguage;
|
||||
this._onDidChangeLanguage.fire(newLanguage);
|
||||
}
|
||||
|
||||
private _buffer: PieceTreeTextBufferFactory | null = null;
|
||||
|
||||
constructor(
|
||||
readonly uri: URI,
|
||||
public handle: number,
|
||||
private _source: string[],
|
||||
public language: string,
|
||||
private _language: string,
|
||||
public cellKind: CellKind,
|
||||
outputs: IOutput[],
|
||||
metadata: NotebookCellMetadata | undefined
|
||||
|
||||
@@ -24,6 +24,7 @@ export class NotebookTextModel extends Disposable implements INotebookTextModel
|
||||
languages: string[] = [];
|
||||
metadata: NotebookDocumentMetadata | undefined = { editable: true };
|
||||
renderers = new Set<number>();
|
||||
private _isUntitled: boolean | undefined = undefined;
|
||||
|
||||
constructor(
|
||||
public handle: number,
|
||||
@@ -36,6 +37,11 @@ export class NotebookTextModel extends Disposable implements INotebookTextModel
|
||||
|
||||
updateLanguages(languages: string[]) {
|
||||
this.languages = languages;
|
||||
|
||||
// TODO@rebornix metadata: default language for cell
|
||||
if (this._isUntitled && languages.length && this.cells.length) {
|
||||
this.cells[0].language = languages[0];
|
||||
}
|
||||
}
|
||||
|
||||
updateNotebookMetadata(metadata: NotebookDocumentMetadata) {
|
||||
@@ -57,7 +63,27 @@ export class NotebookTextModel extends Disposable implements INotebookTextModel
|
||||
});
|
||||
}
|
||||
|
||||
insertTemplateCell(cell: NotebookCellTextModel) {
|
||||
if (this.cells.length > 0 || this._isUntitled !== undefined) {
|
||||
return;
|
||||
}
|
||||
|
||||
this._isUntitled = true;
|
||||
this.cells = [cell];
|
||||
|
||||
let dirtyStateListener = cell.onDidChangeContent(() => {
|
||||
this._isUntitled = false;
|
||||
this._onDidChangeContent.fire();
|
||||
});
|
||||
|
||||
this._cellListeners.set(cell.handle, dirtyStateListener);
|
||||
this._onDidChangeContent.fire();
|
||||
return;
|
||||
}
|
||||
|
||||
insertNewCell(index: number, cell: NotebookCellTextModel): void {
|
||||
this._isUntitled = false;
|
||||
|
||||
this._mapping.set(cell.handle, cell);
|
||||
this.cells.splice(index, 0, cell);
|
||||
let dirtyStateListener = cell.onDidChangeContent(() => {
|
||||
@@ -70,6 +96,8 @@ export class NotebookTextModel extends Disposable implements INotebookTextModel
|
||||
}
|
||||
|
||||
removeCell(index: number) {
|
||||
this._isUntitled = false;
|
||||
|
||||
let cell = this.cells[index];
|
||||
this._cellListeners.get(cell.handle)?.dispose();
|
||||
this._cellListeners.delete(cell.handle);
|
||||
@@ -80,6 +108,12 @@ export class NotebookTextModel extends Disposable implements INotebookTextModel
|
||||
|
||||
// TODO@rebornix should this trigger content change event?
|
||||
$spliceNotebookCells(splices: NotebookCellsSplice[]): void {
|
||||
if (!splices.length) {
|
||||
return;
|
||||
}
|
||||
|
||||
this._isUntitled = false;
|
||||
|
||||
splices.reverse().forEach(splice => {
|
||||
let cellDtos = splice[2];
|
||||
let newCells = cellDtos.map(cell => {
|
||||
|
||||
@@ -136,6 +136,7 @@ export interface ICell {
|
||||
metadata?: NotebookCellMetadata;
|
||||
onDidChangeOutputs?: Event<NotebookCellOutputsSplice[]>;
|
||||
onDidChangeMetadata: Event<NotebookCellMetadata | undefined>;
|
||||
onDidChangeLanguage: Event<string>;
|
||||
resolveTextBufferFactory(): PieceTreeTextBufferFactory;
|
||||
// TODO@rebornix it should be later on replaced by moving textmodel resolution into CellTextModel
|
||||
contentChange(): void;
|
||||
|
||||
@@ -27,6 +27,9 @@ export class TestCell implements ICell {
|
||||
onDidChangeOutputs: Event<NotebookCellOutputsSplice[]> = this._onDidChangeOutputs.event;
|
||||
private _onDidChangeMetadata = new Emitter<NotebookCellMetadata>();
|
||||
onDidChangeMetadata: Event<NotebookCellMetadata> = this._onDidChangeMetadata.event;
|
||||
private _onDidChangeLanguage = new Emitter<string>();
|
||||
onDidChangeLanguage: Event<string> = this._onDidChangeLanguage.event;
|
||||
|
||||
private _isDirty: boolean = false;
|
||||
private _outputs: IOutput[];
|
||||
|
||||
|
||||
@@ -61,6 +61,7 @@ const toggleOutputActionKeybindings = {
|
||||
const VIEW_CONTAINER: ViewContainer = Registry.as<IViewContainersRegistry>(ViewContainerExtensions.ViewContainersRegistry).registerViewContainer({
|
||||
id: OUTPUT_VIEW_ID,
|
||||
name: nls.localize('output', "Output"),
|
||||
order: 1,
|
||||
ctorDescriptor: new SyncDescriptor(ViewPaneContainer, [OUTPUT_VIEW_ID, OUTPUT_VIEW_ID, { mergeViewWithContainerWhenSingleView: true, donotShowContainerTitleWhenMergedWithContainer: true }]),
|
||||
focusCommand: { id: toggleOutputAcitonId, keybindings: toggleOutputActionKeybindings }
|
||||
}, ViewContainerLocation.Panel);
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import 'vs/css!./remoteViewlet';
|
||||
import 'vs/css!./media/remoteViewlet';
|
||||
import * as nls from 'vs/nls';
|
||||
import * as dom from 'vs/base/browser/dom';
|
||||
import { URI } from 'vs/base/common/uri';
|
||||
@@ -55,6 +55,7 @@ import { IKeybindingService } from 'vs/platform/keybinding/common/keybinding';
|
||||
import { Event } from 'vs/base/common/event';
|
||||
import { ExtensionsRegistry, IExtensionPointUser } from 'vs/workbench/services/extensions/common/extensionsRegistry';
|
||||
import { SyncDescriptor } from 'vs/platform/instantiation/common/descriptors';
|
||||
import { RemoteWindowActiveIndicator } from 'vs/workbench/contrib/remote/browser/remoteIndicator';
|
||||
|
||||
export interface HelpInformation {
|
||||
extensionDescription: IExtensionDescription;
|
||||
@@ -803,3 +804,5 @@ class RemoteAgentConnectionStatusListener implements IWorkbenchContribution {
|
||||
|
||||
const workbenchContributionsRegistry = Registry.as<IWorkbenchContributionsRegistry>(WorkbenchExtensions.Workbench);
|
||||
workbenchContributionsRegistry.registerWorkbenchContribution(RemoteAgentConnectionStatusListener, LifecyclePhase.Eventually);
|
||||
workbenchContributionsRegistry.registerWorkbenchContribution(RemoteWindowActiveIndicator, LifecyclePhase.Starting);
|
||||
|
||||
|
||||
229
src/vs/workbench/contrib/remote/browser/remoteIndicator.ts
Normal file
229
src/vs/workbench/contrib/remote/browser/remoteIndicator.ts
Normal file
@@ -0,0 +1,229 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import * as nls from 'vs/nls';
|
||||
import { STATUS_BAR_HOST_NAME_BACKGROUND, STATUS_BAR_HOST_NAME_FOREGROUND } from 'vs/workbench/common/theme';
|
||||
import { themeColorFromId } from 'vs/platform/theme/common/themeService';
|
||||
import { IRemoteAgentService } from 'vs/workbench/services/remote/common/remoteAgentService';
|
||||
import { Disposable } from 'vs/base/common/lifecycle';
|
||||
import { MenuId, IMenuService, MenuItemAction, IMenu, MenuRegistry, registerAction2, Action2 } from 'vs/platform/actions/common/actions';
|
||||
import { IWorkbenchContribution } from 'vs/workbench/common/contributions';
|
||||
import { StatusbarAlignment, IStatusbarService, IStatusbarEntryAccessor, IStatusbarEntry } from 'vs/workbench/services/statusbar/common/statusbar';
|
||||
import { ILabelService } from 'vs/platform/label/common/label';
|
||||
import { IContextKeyService } from 'vs/platform/contextkey/common/contextkey';
|
||||
import { ICommandService } from 'vs/platform/commands/common/commands';
|
||||
import { REMOTE_HOST_SCHEME } from 'vs/platform/remote/common/remoteHosts';
|
||||
import { IExtensionService } from 'vs/workbench/services/extensions/common/extensions';
|
||||
import { IQuickInputService, IQuickPickItem, IQuickPickSeparator } from 'vs/platform/quickinput/common/quickInput';
|
||||
import { IWorkbenchEnvironmentService } from 'vs/workbench/services/environment/common/environmentService';
|
||||
import { PersistentConnectionEventType } from 'vs/platform/remote/common/remoteAgentConnection';
|
||||
import { IRemoteAuthorityResolverService } from 'vs/platform/remote/common/remoteAuthorityResolver';
|
||||
import { IHostService } from 'vs/workbench/services/host/browser/host';
|
||||
import { RemoteConnectionState, Deprecated_RemoteAuthorityContext } from 'vs/workbench/browser/contextkeys';
|
||||
import { isWeb } from 'vs/base/common/platform';
|
||||
import { once } from 'vs/base/common/functional';
|
||||
|
||||
const WINDOW_ACTIONS_COMMAND_ID = 'workbench.action.remote.showMenu';
|
||||
const CLOSE_REMOTE_COMMAND_ID = 'workbench.action.remote.close';
|
||||
const SHOW_CLOSE_REMOTE_COMMAND_ID = !isWeb; // web does not have a "Close Remote" command
|
||||
|
||||
export class RemoteWindowActiveIndicator extends Disposable implements IWorkbenchContribution {
|
||||
|
||||
private windowIndicatorEntry: IStatusbarEntryAccessor | undefined;
|
||||
private windowCommandMenu: IMenu;
|
||||
private hasWindowActions: boolean = false;
|
||||
private remoteAuthority: string | undefined;
|
||||
private connectionState: 'initializing' | 'connected' | 'disconnected' | undefined = undefined;
|
||||
|
||||
constructor(
|
||||
@IStatusbarService private readonly statusbarService: IStatusbarService,
|
||||
@IWorkbenchEnvironmentService environmentService: IWorkbenchEnvironmentService,
|
||||
@ILabelService private readonly labelService: ILabelService,
|
||||
@IContextKeyService private contextKeyService: IContextKeyService,
|
||||
@IMenuService private menuService: IMenuService,
|
||||
@IQuickInputService private readonly quickInputService: IQuickInputService,
|
||||
@ICommandService private readonly commandService: ICommandService,
|
||||
@IExtensionService extensionService: IExtensionService,
|
||||
@IRemoteAgentService remoteAgentService: IRemoteAgentService,
|
||||
@IRemoteAuthorityResolverService remoteAuthorityResolverService: IRemoteAuthorityResolverService,
|
||||
@IHostService hostService: IHostService
|
||||
) {
|
||||
super();
|
||||
|
||||
this.windowCommandMenu = this.menuService.createMenu(MenuId.StatusBarWindowIndicatorMenu, this.contextKeyService);
|
||||
this._register(this.windowCommandMenu);
|
||||
|
||||
const category = nls.localize('remote.category', "Remote");
|
||||
const that = this;
|
||||
registerAction2(class extends Action2 {
|
||||
constructor() {
|
||||
super({
|
||||
id: WINDOW_ACTIONS_COMMAND_ID,
|
||||
category,
|
||||
title: { value: nls.localize('remote.showMenu', "Show Remote Menu"), original: 'Show Remote Menu' },
|
||||
f1: true,
|
||||
});
|
||||
}
|
||||
run = () => that.showIndicatorActions(that.windowCommandMenu);
|
||||
});
|
||||
|
||||
this.remoteAuthority = environmentService.configuration.remoteAuthority;
|
||||
Deprecated_RemoteAuthorityContext.bindTo(this.contextKeyService).set(this.remoteAuthority || '');
|
||||
|
||||
if (this.remoteAuthority) {
|
||||
|
||||
if (SHOW_CLOSE_REMOTE_COMMAND_ID) {
|
||||
registerAction2(class extends Action2 {
|
||||
constructor() {
|
||||
super({
|
||||
id: CLOSE_REMOTE_COMMAND_ID,
|
||||
category,
|
||||
title: { value: nls.localize('remote.close', "Close Remote Connection"), original: 'Close Remote Connection' },
|
||||
f1: true
|
||||
});
|
||||
}
|
||||
run = () => that.remoteAuthority && hostService.openWindow({ forceReuseWindow: true });
|
||||
});
|
||||
|
||||
MenuRegistry.appendMenuItem(MenuId.MenubarFileMenu, {
|
||||
group: '6_close',
|
||||
command: {
|
||||
id: CLOSE_REMOTE_COMMAND_ID,
|
||||
title: nls.localize({ key: 'miCloseRemote', comment: ['&& denotes a mnemonic'] }, "Close Re&&mote Connection")
|
||||
},
|
||||
order: 3.5
|
||||
});
|
||||
}
|
||||
|
||||
// Pending entry until extensions are ready
|
||||
this.renderWindowIndicator('$(sync~spin) ' + nls.localize('host.open', "Opening Remote..."), undefined, WINDOW_ACTIONS_COMMAND_ID);
|
||||
this.connectionState = 'initializing';
|
||||
RemoteConnectionState.bindTo(this.contextKeyService).set(this.connectionState);
|
||||
|
||||
const connection = remoteAgentService.getConnection();
|
||||
if (connection) {
|
||||
this._register(connection.onDidStateChange((e) => {
|
||||
switch (e.type) {
|
||||
case PersistentConnectionEventType.ConnectionLost:
|
||||
case PersistentConnectionEventType.ReconnectionPermanentFailure:
|
||||
case PersistentConnectionEventType.ReconnectionRunning:
|
||||
case PersistentConnectionEventType.ReconnectionWait:
|
||||
this.setDisconnected(true);
|
||||
break;
|
||||
case PersistentConnectionEventType.ConnectionGain:
|
||||
this.setDisconnected(false);
|
||||
break;
|
||||
}
|
||||
}));
|
||||
}
|
||||
}
|
||||
|
||||
extensionService.whenInstalledExtensionsRegistered().then(_ => {
|
||||
if (this.remoteAuthority) {
|
||||
this._register(this.labelService.onDidChangeFormatters(e => this.updateWindowIndicator()));
|
||||
remoteAuthorityResolverService.resolveAuthority(this.remoteAuthority).then(() => this.setDisconnected(false), () => this.setDisconnected(true));
|
||||
}
|
||||
this._register(this.windowCommandMenu.onDidChange(e => this.updateWindowActions()));
|
||||
this.updateWindowIndicator();
|
||||
});
|
||||
}
|
||||
|
||||
private setDisconnected(isDisconnected: boolean): void {
|
||||
const newState = isDisconnected ? 'disconnected' : 'connected';
|
||||
if (this.connectionState !== newState) {
|
||||
this.connectionState = newState;
|
||||
RemoteConnectionState.bindTo(this.contextKeyService).set(this.connectionState);
|
||||
Deprecated_RemoteAuthorityContext.bindTo(this.contextKeyService).set(isDisconnected ? `disconnected/${this.remoteAuthority!}` : this.remoteAuthority!);
|
||||
this.updateWindowIndicator();
|
||||
}
|
||||
}
|
||||
|
||||
private updateWindowIndicator(): void {
|
||||
const windowActionCommand = (this.remoteAuthority || this.windowCommandMenu.getActions().length) ? WINDOW_ACTIONS_COMMAND_ID : undefined;
|
||||
if (this.remoteAuthority) {
|
||||
const hostLabel = this.labelService.getHostLabel(REMOTE_HOST_SCHEME, this.remoteAuthority) || this.remoteAuthority;
|
||||
if (this.connectionState !== 'disconnected') {
|
||||
this.renderWindowIndicator(`$(remote) ${hostLabel}`, nls.localize('host.tooltip', "Editing on {0}", hostLabel), windowActionCommand);
|
||||
} else {
|
||||
this.renderWindowIndicator(`$(alert) ${nls.localize('disconnectedFrom', "Disconnected from")} ${hostLabel}`, nls.localize('host.tooltipDisconnected', "Disconnected from {0}", hostLabel), windowActionCommand);
|
||||
}
|
||||
} else {
|
||||
if (windowActionCommand) {
|
||||
this.renderWindowIndicator(`$(remote)`, nls.localize('noHost.tooltip', "Open a remote window"), windowActionCommand);
|
||||
} else if (this.windowIndicatorEntry) {
|
||||
this.windowIndicatorEntry.dispose();
|
||||
this.windowIndicatorEntry = undefined;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private updateWindowActions() {
|
||||
const newHasWindowActions = this.windowCommandMenu.getActions().length > 0;
|
||||
if (newHasWindowActions !== this.hasWindowActions) {
|
||||
this.hasWindowActions = newHasWindowActions;
|
||||
this.updateWindowIndicator();
|
||||
}
|
||||
}
|
||||
|
||||
private renderWindowIndicator(text: string, tooltip?: string, command?: string): void {
|
||||
const properties: IStatusbarEntry = {
|
||||
backgroundColor: themeColorFromId(STATUS_BAR_HOST_NAME_BACKGROUND), color: themeColorFromId(STATUS_BAR_HOST_NAME_FOREGROUND), text, tooltip, command
|
||||
};
|
||||
if (this.windowIndicatorEntry) {
|
||||
this.windowIndicatorEntry.update(properties);
|
||||
} else {
|
||||
this.windowIndicatorEntry = this.statusbarService.addEntry(properties, 'status.host', nls.localize('status.host', "Remote Host"), StatusbarAlignment.LEFT, Number.MAX_VALUE /* first entry */);
|
||||
}
|
||||
}
|
||||
|
||||
private showIndicatorActions(menu: IMenu) {
|
||||
|
||||
const actions = menu.getActions();
|
||||
|
||||
const items: (IQuickPickItem | IQuickPickSeparator)[] = [];
|
||||
for (let actionGroup of actions) {
|
||||
if (items.length) {
|
||||
items.push({ type: 'separator' });
|
||||
}
|
||||
for (let action of actionGroup[1]) {
|
||||
if (action instanceof MenuItemAction) {
|
||||
let label = typeof action.item.title === 'string' ? action.item.title : action.item.title.value;
|
||||
if (action.item.category) {
|
||||
const category = typeof action.item.category === 'string' ? action.item.category : action.item.category.value;
|
||||
label = nls.localize('cat.title', "{0}: {1}", category, label);
|
||||
}
|
||||
items.push({
|
||||
type: 'item',
|
||||
id: action.item.id,
|
||||
label
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (SHOW_CLOSE_REMOTE_COMMAND_ID && this.remoteAuthority) {
|
||||
if (items.length) {
|
||||
items.push({ type: 'separator' });
|
||||
}
|
||||
items.push({
|
||||
type: 'item',
|
||||
id: CLOSE_REMOTE_COMMAND_ID,
|
||||
label: nls.localize('closeRemote.title', 'Close Remote Connection')
|
||||
});
|
||||
}
|
||||
|
||||
const quickPick = this.quickInputService.createQuickPick();
|
||||
quickPick.items = items;
|
||||
quickPick.canSelectMany = false;
|
||||
once(quickPick.onDidAccept)((_ => {
|
||||
const selectedItems = quickPick.selectedItems;
|
||||
if (selectedItems.length === 1) {
|
||||
this.commandService.executeCommand(selectedItems[0].id!);
|
||||
}
|
||||
quickPick.hide();
|
||||
}));
|
||||
quickPick.show();
|
||||
}
|
||||
}
|
||||
@@ -5,23 +5,17 @@
|
||||
|
||||
import * as nls from 'vs/nls';
|
||||
import { Registry } from 'vs/platform/registry/common/platform';
|
||||
import { STATUS_BAR_HOST_NAME_BACKGROUND, STATUS_BAR_HOST_NAME_FOREGROUND } from 'vs/workbench/common/theme';
|
||||
import { themeColorFromId } from 'vs/platform/theme/common/themeService';
|
||||
import { IRemoteAgentService } from 'vs/workbench/services/remote/common/remoteAgentService';
|
||||
import { Disposable } from 'vs/base/common/lifecycle';
|
||||
import { isMacintosh } from 'vs/base/common/platform';
|
||||
import { KeyMod, KeyChord, KeyCode } from 'vs/base/common/keyCodes';
|
||||
import { KeybindingsRegistry, KeybindingWeight } from 'vs/platform/keybinding/common/keybindingsRegistry';
|
||||
import { MenuId, IMenuService, MenuItemAction, IMenu, MenuRegistry, registerAction2, Action2 } from 'vs/platform/actions/common/actions';
|
||||
import { IWorkbenchContribution, IWorkbenchContributionsRegistry, Extensions as WorkbenchContributionsExtensions } from 'vs/workbench/common/contributions';
|
||||
import { LifecyclePhase } from 'vs/platform/lifecycle/common/lifecycle';
|
||||
import { StatusbarAlignment, IStatusbarService, IStatusbarEntryAccessor, IStatusbarEntry } from 'vs/workbench/services/statusbar/common/statusbar';
|
||||
import { ILabelService } from 'vs/platform/label/common/label';
|
||||
import { IContextKeyService } from 'vs/platform/contextkey/common/contextkey';
|
||||
import { ICommandService } from 'vs/platform/commands/common/commands';
|
||||
import { REMOTE_HOST_SCHEME } from 'vs/platform/remote/common/remoteHosts';
|
||||
import { IExtensionService } from 'vs/workbench/services/extensions/common/extensions';
|
||||
import { IQuickInputService, IQuickPickItem, IQuickPickSeparator } from 'vs/platform/quickinput/common/quickInput';
|
||||
import { ILogService } from 'vs/platform/log/common/log';
|
||||
import { IDialogService } from 'vs/platform/dialogs/common/dialogs';
|
||||
import { DialogChannel } from 'vs/platform/dialogs/electron-browser/dialogIpc';
|
||||
@@ -34,211 +28,11 @@ import { PersistentConnectionEventType } from 'vs/platform/remote/common/remoteA
|
||||
import { IConfigurationService } from 'vs/platform/configuration/common/configuration';
|
||||
import { IConfigurationRegistry, Extensions as ConfigurationExtensions } from 'vs/platform/configuration/common/configurationRegistry';
|
||||
import { IRemoteAuthorityResolverService } from 'vs/platform/remote/common/remoteAuthorityResolver';
|
||||
import { IHostService } from 'vs/workbench/services/host/browser/host';
|
||||
import { RemoteConnectionState, Deprecated_RemoteAuthorityContext, RemoteFileDialogContext } from 'vs/workbench/browser/contextkeys';
|
||||
import { RemoteFileDialogContext } from 'vs/workbench/browser/contextkeys';
|
||||
import { IDownloadService } from 'vs/platform/download/common/download';
|
||||
import { OpenLocalFileFolderCommand, OpenLocalFileCommand, OpenLocalFolderCommand, SaveLocalFileCommand } from 'vs/workbench/services/dialogs/browser/simpleFileDialog';
|
||||
import { INativeWorkbenchEnvironmentService } from 'vs/workbench/services/environment/electron-browser/environmentService';
|
||||
|
||||
const WINDOW_ACTIONS_COMMAND_ID = 'workbench.action.remote.showMenu';
|
||||
const CLOSE_REMOTE_COMMAND_ID = 'workbench.action.remote.close';
|
||||
|
||||
export class RemoteWindowActiveIndicator extends Disposable implements IWorkbenchContribution {
|
||||
|
||||
private windowIndicatorEntry: IStatusbarEntryAccessor | undefined;
|
||||
private windowCommandMenu: IMenu;
|
||||
private hasWindowActions: boolean = false;
|
||||
private remoteAuthority: string | undefined;
|
||||
private connectionState: 'initializing' | 'connected' | 'disconnected' | undefined = undefined;
|
||||
|
||||
constructor(
|
||||
@IStatusbarService private readonly statusbarService: IStatusbarService,
|
||||
@IWorkbenchEnvironmentService environmentService: IWorkbenchEnvironmentService,
|
||||
@ILabelService private readonly labelService: ILabelService,
|
||||
@IContextKeyService private contextKeyService: IContextKeyService,
|
||||
@IMenuService private menuService: IMenuService,
|
||||
@IQuickInputService private readonly quickInputService: IQuickInputService,
|
||||
@ICommandService private readonly commandService: ICommandService,
|
||||
@IExtensionService extensionService: IExtensionService,
|
||||
@IRemoteAgentService remoteAgentService: IRemoteAgentService,
|
||||
@IRemoteAuthorityResolverService remoteAuthorityResolverService: IRemoteAuthorityResolverService,
|
||||
@IHostService hostService: IHostService
|
||||
) {
|
||||
super();
|
||||
|
||||
this.windowCommandMenu = this.menuService.createMenu(MenuId.StatusBarWindowIndicatorMenu, this.contextKeyService);
|
||||
this._register(this.windowCommandMenu);
|
||||
|
||||
const category = nls.localize('remote.category', "Remote");
|
||||
const that = this;
|
||||
registerAction2(class extends Action2 {
|
||||
constructor() {
|
||||
super({
|
||||
id: WINDOW_ACTIONS_COMMAND_ID,
|
||||
category,
|
||||
title: { value: nls.localize('remote.showMenu', "Show Remote Menu"), original: 'Show Remote Menu' },
|
||||
f1: true,
|
||||
});
|
||||
}
|
||||
run = () => that.showIndicatorActions(that.windowCommandMenu);
|
||||
});
|
||||
|
||||
this.remoteAuthority = environmentService.configuration.remoteAuthority;
|
||||
Deprecated_RemoteAuthorityContext.bindTo(this.contextKeyService).set(this.remoteAuthority || '');
|
||||
|
||||
if (this.remoteAuthority) {
|
||||
registerAction2(class extends Action2 {
|
||||
constructor() {
|
||||
super({
|
||||
id: CLOSE_REMOTE_COMMAND_ID,
|
||||
category,
|
||||
title: { value: nls.localize('remote.close', "Close Remote Connection"), original: 'Close Remote Connection' },
|
||||
f1: true
|
||||
});
|
||||
}
|
||||
run = () => that.remoteAuthority && hostService.openWindow({ forceReuseWindow: true });
|
||||
});
|
||||
|
||||
// Pending entry until extensions are ready
|
||||
this.renderWindowIndicator('$(sync~spin) ' + nls.localize('host.open', "Opening Remote..."), undefined, WINDOW_ACTIONS_COMMAND_ID);
|
||||
this.connectionState = 'initializing';
|
||||
RemoteConnectionState.bindTo(this.contextKeyService).set(this.connectionState);
|
||||
|
||||
MenuRegistry.appendMenuItem(MenuId.MenubarFileMenu, {
|
||||
group: '6_close',
|
||||
command: {
|
||||
id: CLOSE_REMOTE_COMMAND_ID,
|
||||
title: nls.localize({ key: 'miCloseRemote', comment: ['&& denotes a mnemonic'] }, "Close Re&&mote Connection")
|
||||
},
|
||||
order: 3.5
|
||||
});
|
||||
|
||||
const connection = remoteAgentService.getConnection();
|
||||
if (connection) {
|
||||
this._register(connection.onDidStateChange((e) => {
|
||||
switch (e.type) {
|
||||
case PersistentConnectionEventType.ConnectionLost:
|
||||
case PersistentConnectionEventType.ReconnectionPermanentFailure:
|
||||
case PersistentConnectionEventType.ReconnectionRunning:
|
||||
case PersistentConnectionEventType.ReconnectionWait:
|
||||
this.setDisconnected(true);
|
||||
break;
|
||||
case PersistentConnectionEventType.ConnectionGain:
|
||||
this.setDisconnected(false);
|
||||
break;
|
||||
}
|
||||
}));
|
||||
}
|
||||
}
|
||||
|
||||
extensionService.whenInstalledExtensionsRegistered().then(_ => {
|
||||
if (this.remoteAuthority) {
|
||||
this._register(this.labelService.onDidChangeFormatters(e => this.updateWindowIndicator()));
|
||||
remoteAuthorityResolverService.resolveAuthority(this.remoteAuthority).then(() => this.setDisconnected(false), () => this.setDisconnected(true));
|
||||
}
|
||||
this._register(this.windowCommandMenu.onDidChange(e => this.updateWindowActions()));
|
||||
this.updateWindowIndicator();
|
||||
});
|
||||
}
|
||||
|
||||
private setDisconnected(isDisconnected: boolean): void {
|
||||
const newState = isDisconnected ? 'disconnected' : 'connected';
|
||||
if (this.connectionState !== newState) {
|
||||
this.connectionState = newState;
|
||||
RemoteConnectionState.bindTo(this.contextKeyService).set(this.connectionState);
|
||||
Deprecated_RemoteAuthorityContext.bindTo(this.contextKeyService).set(isDisconnected ? `disconnected/${this.remoteAuthority!}` : this.remoteAuthority!);
|
||||
this.updateWindowIndicator();
|
||||
}
|
||||
}
|
||||
|
||||
private updateWindowIndicator(): void {
|
||||
const windowActionCommand = (this.remoteAuthority || this.windowCommandMenu.getActions().length) ? WINDOW_ACTIONS_COMMAND_ID : undefined;
|
||||
if (this.remoteAuthority) {
|
||||
const hostLabel = this.labelService.getHostLabel(REMOTE_HOST_SCHEME, this.remoteAuthority) || this.remoteAuthority;
|
||||
if (this.connectionState !== 'disconnected') {
|
||||
this.renderWindowIndicator(`$(remote) ${hostLabel}`, nls.localize('host.tooltip', "Editing on {0}", hostLabel), windowActionCommand);
|
||||
} else {
|
||||
this.renderWindowIndicator(`$(alert) ${nls.localize('disconnectedFrom', "Disconnected from")} ${hostLabel}`, nls.localize('host.tooltipDisconnected', "Disconnected from {0}", hostLabel), windowActionCommand);
|
||||
}
|
||||
} else {
|
||||
if (windowActionCommand) {
|
||||
this.renderWindowIndicator(`$(remote)`, nls.localize('noHost.tooltip', "Open a remote window"), windowActionCommand);
|
||||
} else if (this.windowIndicatorEntry) {
|
||||
this.windowIndicatorEntry.dispose();
|
||||
this.windowIndicatorEntry = undefined;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private updateWindowActions() {
|
||||
const newHasWindowActions = this.windowCommandMenu.getActions().length > 0;
|
||||
if (newHasWindowActions !== this.hasWindowActions) {
|
||||
this.hasWindowActions = newHasWindowActions;
|
||||
this.updateWindowIndicator();
|
||||
}
|
||||
}
|
||||
|
||||
private renderWindowIndicator(text: string, tooltip?: string, command?: string): void {
|
||||
const properties: IStatusbarEntry = {
|
||||
backgroundColor: themeColorFromId(STATUS_BAR_HOST_NAME_BACKGROUND), color: themeColorFromId(STATUS_BAR_HOST_NAME_FOREGROUND), text, tooltip, command
|
||||
};
|
||||
if (this.windowIndicatorEntry) {
|
||||
this.windowIndicatorEntry.update(properties);
|
||||
} else {
|
||||
this.windowIndicatorEntry = this.statusbarService.addEntry(properties, 'status.host', nls.localize('status.host', "Remote Host"), StatusbarAlignment.LEFT, Number.MAX_VALUE /* first entry */);
|
||||
}
|
||||
}
|
||||
|
||||
private showIndicatorActions(menu: IMenu) {
|
||||
|
||||
const actions = menu.getActions();
|
||||
|
||||
const items: (IQuickPickItem | IQuickPickSeparator)[] = [];
|
||||
for (let actionGroup of actions) {
|
||||
if (items.length) {
|
||||
items.push({ type: 'separator' });
|
||||
}
|
||||
for (let action of actionGroup[1]) {
|
||||
if (action instanceof MenuItemAction) {
|
||||
let label = typeof action.item.title === 'string' ? action.item.title : action.item.title.value;
|
||||
if (action.item.category) {
|
||||
const category = typeof action.item.category === 'string' ? action.item.category : action.item.category.value;
|
||||
label = nls.localize('cat.title', "{0}: {1}", category, label);
|
||||
}
|
||||
items.push({
|
||||
type: 'item',
|
||||
id: action.item.id,
|
||||
label
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (this.remoteAuthority) {
|
||||
if (items.length) {
|
||||
items.push({ type: 'separator' });
|
||||
}
|
||||
items.push({
|
||||
type: 'item',
|
||||
id: CLOSE_REMOTE_COMMAND_ID,
|
||||
label: nls.localize('closeRemote.title', 'Close Remote Connection')
|
||||
});
|
||||
}
|
||||
|
||||
const quickPick = this.quickInputService.createQuickPick();
|
||||
quickPick.items = items;
|
||||
quickPick.canSelectMany = false;
|
||||
quickPick.onDidAccept(_ => {
|
||||
const selectedItems = quickPick.selectedItems;
|
||||
if (selectedItems.length === 1) {
|
||||
this.commandService.executeCommand(selectedItems[0].id!);
|
||||
}
|
||||
quickPick.hide();
|
||||
});
|
||||
quickPick.show();
|
||||
}
|
||||
}
|
||||
|
||||
class RemoteChannelsContribution implements IWorkbenchContribution {
|
||||
|
||||
constructor(
|
||||
@@ -366,7 +160,6 @@ const workbenchContributionsRegistry = Registry.as<IWorkbenchContributionsRegist
|
||||
workbenchContributionsRegistry.registerWorkbenchContribution(RemoteChannelsContribution, LifecyclePhase.Starting);
|
||||
workbenchContributionsRegistry.registerWorkbenchContribution(RemoteAgentDiagnosticListener, LifecyclePhase.Eventually);
|
||||
workbenchContributionsRegistry.registerWorkbenchContribution(RemoteExtensionHostEnvironmentUpdater, LifecyclePhase.Eventually);
|
||||
workbenchContributionsRegistry.registerWorkbenchContribution(RemoteWindowActiveIndicator, LifecyclePhase.Starting);
|
||||
workbenchContributionsRegistry.registerWorkbenchContribution(RemoteTelemetryEnablementUpdater, LifecyclePhase.Ready);
|
||||
workbenchContributionsRegistry.registerWorkbenchContribution(RemoteEmptyWorkbenchPresentation, LifecyclePhase.Starting);
|
||||
|
||||
|
||||
@@ -496,6 +496,10 @@ export class AnythingQuickAccessProvider extends PickerQuickAccessProvider<IAnyt
|
||||
this.getRelativePathFileResults(query, token)
|
||||
]);
|
||||
|
||||
if (token.isCancellationRequested) {
|
||||
return [];
|
||||
}
|
||||
|
||||
// Return quickly if no relative results are present
|
||||
if (!relativePathFileResults) {
|
||||
return fileSearchResults.results.map(result => result.resource);
|
||||
|
||||
@@ -516,7 +516,7 @@ const viewContainer = Registry.as<IViewContainersRegistry>(ViewExtensions.ViewCo
|
||||
order: 1
|
||||
}, ViewContainerLocation.Sidebar);
|
||||
|
||||
const viewDescriptor = { id: VIEW_ID, name: nls.localize('search', "Search"), ctorDescriptor: new SyncDescriptor(SearchView), canToggleVisibility: false, canMoveView: true };
|
||||
const viewDescriptor = { id: VIEW_ID, containerIcon: 'codicon-search', name: nls.localize('search', "Search"), ctorDescriptor: new SyncDescriptor(SearchView), canToggleVisibility: false, canMoveView: true };
|
||||
|
||||
// Register search default location to sidebar
|
||||
Registry.as<IViewsRegistry>(ViewExtensions.ViewsRegistry).registerViews([viewDescriptor], viewContainer);
|
||||
|
||||
@@ -462,8 +462,8 @@ export class SearchEditor extends BaseTextEditor {
|
||||
_reason: 'searchEditor',
|
||||
extraFileResources: this.instantiationService.invokeFunction(getOutOfWorkspaceEditorResources),
|
||||
maxResults: 10000,
|
||||
disregardIgnoreFiles: !config.useIgnores,
|
||||
disregardExcludeSettings: !config.useIgnores,
|
||||
disregardIgnoreFiles: !config.useIgnores || undefined,
|
||||
disregardExcludeSettings: !config.useIgnores || undefined,
|
||||
excludePattern: config.excludes,
|
||||
includePattern: config.includes,
|
||||
previewOptions: {
|
||||
|
||||
@@ -382,7 +382,8 @@ const VIEW_CONTAINER = Registry.as<IViewContainersRegistry>(ViewContainerExtensi
|
||||
name: nls.localize('terminal', "Terminal"),
|
||||
ctorDescriptor: new SyncDescriptor(ViewPaneContainer, [TERMINAL_VIEW_ID, TERMINAL_VIEW_ID, { mergeViewWithContainerWhenSingleView: true, donotShowContainerTitleWhenMergedWithContainer: true }]),
|
||||
focusCommand: { id: TERMINAL_COMMAND_ID.FOCUS },
|
||||
hideIfEmpty: true
|
||||
hideIfEmpty: true,
|
||||
order: 3
|
||||
}, ViewContainerLocation.Panel);
|
||||
Registry.as<panel.PanelRegistry>(panel.Extensions.Panels).setDefaultPanelId(TERMINAL_VIEW_ID);
|
||||
|
||||
|
||||
@@ -695,7 +695,6 @@ export class UserDataSyncWorkbenchContribution extends Disposable implements IWo
|
||||
}, {
|
||||
id: SyncResource.GlobalState,
|
||||
label: getSyncAreaLabel(SyncResource.GlobalState),
|
||||
description: localize('ui state description', "only 'Display Language' for now")
|
||||
}];
|
||||
}
|
||||
|
||||
@@ -914,7 +913,7 @@ export class UserDataSyncWorkbenchContribution extends Disposable implements IWo
|
||||
constructor() {
|
||||
super({
|
||||
id: signInCommand.id,
|
||||
title: signInCommand.title,
|
||||
title: localize('sign in 2', "Sync: Sign in to sync (1)"),
|
||||
menu: {
|
||||
group: '5_sync',
|
||||
id: MenuId.GlobalActivity,
|
||||
|
||||
@@ -7,10 +7,9 @@ import { Disposable, IDisposable } from 'vs/base/common/lifecycle';
|
||||
import { ContextKeyExpr } from 'vs/platform/contextkey/common/contextkey';
|
||||
import { IWorkbenchContribution } from 'vs/workbench/common/contributions';
|
||||
import { IExtensionPoint } from 'vs/workbench/services/extensions/common/extensionsRegistry';
|
||||
import { ViewsWelcomeExtensionPoint, ViewWelcome, viewsWelcomeExtensionPointDescriptor, ViewIdentifierMap } from './viewsWelcomeExtensionPoint';
|
||||
import { ViewsWelcomeExtensionPoint, ViewWelcome, ViewIdentifierMap } from './viewsWelcomeExtensionPoint';
|
||||
import { Registry } from 'vs/platform/registry/common/platform';
|
||||
import { Extensions as ViewContainerExtensions, IViewsRegistry, ViewContentPriority } from 'vs/workbench/common/views';
|
||||
import { localize } from 'vs/nls';
|
||||
|
||||
const viewsRegistry = Registry.as<IViewsRegistry>(ViewContainerExtensions.ViewsRegistry);
|
||||
|
||||
@@ -23,11 +22,6 @@ export class ViewsWelcomeContribution extends Disposable implements IWorkbenchCo
|
||||
|
||||
extensionPoint.setHandler((_, { added, removed }) => {
|
||||
for (const contribution of removed) {
|
||||
// Proposed API check
|
||||
if (!contribution.description.enableProposedApi) {
|
||||
continue;
|
||||
}
|
||||
|
||||
for (const welcome of contribution.value) {
|
||||
const disposable = this.viewWelcomeContents.get(welcome);
|
||||
|
||||
@@ -38,12 +32,6 @@ export class ViewsWelcomeContribution extends Disposable implements IWorkbenchCo
|
||||
}
|
||||
|
||||
for (const contribution of added) {
|
||||
// Proposed API check
|
||||
if (!contribution.description.enableProposedApi) {
|
||||
contribution.collector.error(localize('proposedAPI.invalid', "The '{0}' contribution is a proposed API and is only available when running out of dev or with the following command line switch: --enable-proposed-api {1}", viewsWelcomeExtensionPointDescriptor.extensionPoint, contribution.description.identifier.value));
|
||||
continue;
|
||||
}
|
||||
|
||||
for (const welcome of contribution.value) {
|
||||
const id = ViewIdentifierMap[welcome.view] ?? welcome.view;
|
||||
const disposable = viewsRegistry.registerViewWelcomeContent(id, {
|
||||
|
||||
Reference in New Issue
Block a user