mirror of
https://github.com/ckaczor/azuredatastudio.git
synced 2026-02-16 10:58:30 -05:00
Merge from vscode 8c426f9f3b6b18935cc6c2ec8aa6d45ccd88021e
This commit is contained in:
@@ -49,7 +49,7 @@
|
||||
"rollup-plugin-commonjs": "^10.1.0",
|
||||
"rollup-plugin-node-resolve": "^5.2.0",
|
||||
"terser": "4.3.8",
|
||||
"typescript": "^4.0.0-dev.20200715",
|
||||
"typescript": "^4.0.0-dev.20200722",
|
||||
"vsce": "1.48.0",
|
||||
"vscode-telemetry-extractor": "^1.6.0",
|
||||
"xml2js": "^0.4.17"
|
||||
|
||||
@@ -3539,10 +3539,10 @@ typescript@^3.0.1:
|
||||
resolved "https://registry.yarnpkg.com/typescript/-/typescript-3.5.3.tgz#c830f657f93f1ea846819e929092f5fe5983e977"
|
||||
integrity sha512-ACzBtm/PhXBDId6a6sDJfroT2pOWt/oOnk4/dElG5G33ZL776N3Y6/6bKZJBFpd+b05F3Ct9qDjMeJmRWtE2/g==
|
||||
|
||||
typescript@^4.0.0-dev.20200715:
|
||||
version "4.0.0-dev.20200715"
|
||||
resolved "https://registry.yarnpkg.com/typescript/-/typescript-4.0.0-dev.20200715.tgz#d65961a5a6f13fde95a6f4db5f5946f15e4c59bc"
|
||||
integrity sha512-gmPXoWktfXeutmWTM6el9U4vIn5kqOHGI1OESSOhPtLWrxodKqLfFuMygQtOUTtGjKLFQRFAJhHEwUhHZNOURA==
|
||||
typescript@^4.0.0-dev.20200722:
|
||||
version "4.0.0-dev.20200722"
|
||||
resolved "https://registry.yarnpkg.com/typescript/-/typescript-4.0.0-dev.20200722.tgz#b59dd5a3cd84a98d5aae0e4f3a3c58f0c81a3b9b"
|
||||
integrity sha512-MmJ1YyPNK3JYeKLiTg5sQXdeZaMgt99Fg4BMRZhJmhoq1/x2V1cpXMYvE1rtIYl9K7NvmTDdU3WDW7ZOD6ybaw==
|
||||
|
||||
typical@^4.0.0:
|
||||
version "4.0.0"
|
||||
|
||||
@@ -1801,7 +1801,7 @@
|
||||
"Ignore",
|
||||
"ignore"
|
||||
],
|
||||
"filenames": [
|
||||
"extensions": [
|
||||
".gitignore_global",
|
||||
".gitignore"
|
||||
],
|
||||
|
||||
@@ -74,7 +74,7 @@ async function createModel(context: ExtensionContext, outputChannel: OutputChann
|
||||
new GitTimelineProvider(model)
|
||||
);
|
||||
|
||||
// await checkGitVersion(info); {{SQL CARBON EDIT}} Don't check git version
|
||||
// checkGitVersion(info); {{SQL CARBON EDIT}} Don't check git version
|
||||
|
||||
return model;
|
||||
}
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
"version": "0.0.1",
|
||||
"description": "Dependencies shared by all extensions",
|
||||
"dependencies": {
|
||||
"typescript": "3.9.6"
|
||||
"typescript": "3.9.7"
|
||||
},
|
||||
"scripts": {
|
||||
"postinstall": "node ./postinstall"
|
||||
|
||||
@@ -76,10 +76,10 @@ rimraf@^3.0.2:
|
||||
dependencies:
|
||||
glob "^7.1.3"
|
||||
|
||||
typescript@3.9.6:
|
||||
version "3.9.6"
|
||||
resolved "https://registry.yarnpkg.com/typescript/-/typescript-3.9.6.tgz#8f3e0198a34c3ae17091b35571d3afd31999365a"
|
||||
integrity sha512-Pspx3oKAPJtjNwE92YS05HQoY7z2SFyOpHo9MqJor3BXAGNaPUs83CuVp9VISFkSjyRfiTpmKuAYGJB7S7hOxw==
|
||||
typescript@3.9.7:
|
||||
version "3.9.7"
|
||||
resolved "https://registry.yarnpkg.com/typescript/-/typescript-3.9.7.tgz#98d600a5ebdc38f40cb277522f12dc800e9e25fa"
|
||||
integrity sha512-BLbiRkiBzAwsjut4x/dsibSTB6yWpwT5qWmC2OfuCg3GgVQCSgMs4vEctYPhsaGtd0AeuuHMkjZ2h2WG8MSzRw==
|
||||
|
||||
wrappy@1:
|
||||
version "1.0.2"
|
||||
|
||||
@@ -37,9 +37,6 @@ if "%INTEGRATION_TEST_ELECTRON_PATH%"=="" (
|
||||
|
||||
:: Tests in the extension host
|
||||
|
||||
REM call "%INTEGRATION_TEST_ELECTRON_PATH%" %~dp0\..\extensions\vscode-notebook-tests\test --enable-proposed-api=vscode.vscode-notebook-tests --extensionDevelopmentPath=%~dp0\..\extensions\vscode-notebook-tests --extensionTestsPath=%~dp0\..\extensions\vscode-notebook-tests\out --disable-telemetry --crash-reporter-directory=%VSCODECRASHDIR% --no-cached-data --disable-updates --disable-extensions --user-data-dir=%VSCODEUSERDATADIR%
|
||||
REM if %errorlevel% neq 0 exit /b %errorlevel%
|
||||
|
||||
REM call "%INTEGRATION_TEST_ELECTRON_PATH%" %~dp0\..\extensions\vscode-api-tests\testWorkspace --enable-proposed-api=vscode.vscode-api-tests --extensionDevelopmentPath=%~dp0\..\extensions\vscode-api-tests --extensionTestsPath=%~dp0\..\extensions\vscode-api-tests\out\singlefolder-tests --disable-telemetry --crash-reporter-directory=%VSCODECRASHDIR% --no-cached-data --disable-updates --disable-extensions --user-data-dir=%VSCODEUSERDATADIR%
|
||||
REM if %errorlevel% neq 0 exit /b %errorlevel%
|
||||
|
||||
@@ -61,6 +58,9 @@ REM if %errorlevel% neq 0 exit /b %errorlevel%
|
||||
call "%INTEGRATION_TEST_ELECTRON_PATH%" %~dp0\..\extensions\azurecore\test-fixtures --extensionDevelopmentPath=%~dp0\..\extensions\azurecore --extensionTestsPath=%~dp0\..\extensions\azurecore\out\test --no-cached-data --disable-telemetry --disable-crash-reporter --disable-updates --disable-extensions --user-data-dir=%VSCODEUSERDATADIR%
|
||||
if %errorlevel% neq 0 exit /b %errorlevel%
|
||||
|
||||
REM call "%INTEGRATION_TEST_ELECTRON_PATH%" %~dp0\..\extensions\vscode-notebook-tests\test --enable-proposed-api=vscode.vscode-notebook-tests --extensionDevelopmentPath=%~dp0\..\extensions\vscode-notebook-tests --extensionTestsPath=%~dp0\..\extensions\vscode-notebook-tests\out --disable-telemetry --crash-reporter-directory=%VSCODECRASHDIR% --no-cached-data --disable-updates --disable-extensions --user-data-dir=%VSCODEUSERDATADIR%
|
||||
REM if %errorlevel% neq 0 exit /b %errorlevel%
|
||||
|
||||
for /f "delims=" %%i in ('node -p "require('fs').realpathSync.native(require('os').tmpdir())"') do set TEMPDIR=%%i
|
||||
set GITWORKSPACE=%TEMPDIR%\git-%RANDOM%
|
||||
mkdir %GITWORKSPACE%
|
||||
|
||||
@@ -48,7 +48,7 @@ fi
|
||||
# "$INTEGRATION_TEST_ELECTRON_PATH" $LINUX_NO_SANDBOX $ROOT/extensions/typescript-language-features/test-workspace --extensionDevelopmentPath=$ROOT/extensions/typescript-language-features --extensionTestsPath=$ROOT/extensions/typescript-language-features/out/test --disable-telemetry --crash-reporter-directory=$VSCODECRASHDIR --no-cached-data --disable-updates --disable-extensions --user-data-dir=$VSCODEUSERDATADIR
|
||||
# "$INTEGRATION_TEST_ELECTRON_PATH" $LINUX_NO_SANDBOX $ROOT/extensions/emmet/out/test/test-fixtures --extensionDevelopmentPath=$ROOT/extensions/emmet --extensionTestsPath=$ROOT/extensions/emmet/out/test --disable-telemetry --crash-reporter-directory=$VSCODECRASHDIR --no-cached-data --disable-updates --disable-extensions --user-data-dir=$VSCODEUSERDATADIR
|
||||
"$INTEGRATION_TEST_ELECTRON_PATH" $LINUX_NO_SANDBOX $(mktemp -d 2>/dev/null) --enable-proposed-api=vscode.git --extensionDevelopmentPath=$ROOT/extensions/git --extensionTestsPath=$ROOT/extensions/git/out/test --disable-telemetry --crash-reporter-directory=$VSCODECRASHDIR --no-cached-data --disable-updates --disable-extensions --user-data-dir=$VSCODEUSERDATADIR
|
||||
# "$INTEGRATION_TEST_ELECTRON_PATH" $LINUX_NO_SANDBOX $ROOT/extensions/vscode-notebook-tests/test --enable-proposed-api=vscode.vscode-notebook-tests --extensionDevelopmentPath=$ROOT/extensions/vscode-notebook-tests --extensionTestsPath=$ROOT/extensions/vscode-notebook-tests/out/ --disable-telemetry --crash-reporter-directory=$VSCODECRASHDIR --no-cached-data --disable-updates --disable-extensions --user-data-dir=$VSCODEUSERDATADIR
|
||||
"$INTEGRATION_TEST_ELECTRON_PATH" $LINUX_NO_SANDBOX $ROOT/extensions/vscode-notebook-tests/test --enable-proposed-api=vscode.vscode-notebook-tests --extensionDevelopmentPath=$ROOT/extensions/vscode-notebook-tests --extensionTestsPath=$ROOT/extensions/vscode-notebook-tests/out/ --disable-telemetry --crash-reporter-directory=$VSCODECRASHDIR --no-cached-data --disable-updates --disable-extensions --user-data-dir=$VSCODEUSERDATADIR
|
||||
|
||||
"$INTEGRATION_TEST_ELECTRON_PATH" $LINUX_NO_SANDBOX $ROOT/extensions/azurecore/test-fixtures --extensionDevelopmentPath=$ROOT/extensions/azurecore --extensionTestsPath=$ROOT/extensions/azurecore/out/test --no-cached-data --disable-telemetry --disable-crash-reporter --disable-updates --disable-extensions --user-data-dir=$VSCODEUSERDATADIR
|
||||
|
||||
|
||||
@@ -34,5 +34,5 @@ export interface IContextMenuDelegate {
|
||||
actionRunner?: IActionRunner;
|
||||
autoSelectFirstItem?: boolean;
|
||||
anchorAlignment?: AnchorAlignment;
|
||||
anchorAsContainer?: boolean;
|
||||
domForShadowRoot?: HTMLElement;
|
||||
}
|
||||
|
||||
@@ -5,7 +5,6 @@
|
||||
|
||||
.monaco-action-bar {
|
||||
text-align: right;
|
||||
overflow: hidden;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
|
||||
@@ -28,7 +28,7 @@ function initialize() {
|
||||
delayer.schedule();
|
||||
}
|
||||
|
||||
function formatRule(c: Codicon) {
|
||||
export function formatRule(c: Codicon) {
|
||||
let def = c.definition;
|
||||
while (def instanceof Codicon) {
|
||||
def = def.definition;
|
||||
|
||||
@@ -10,6 +10,12 @@ import { IDisposable, toDisposable, Disposable, DisposableStore } from 'vs/base/
|
||||
import { Range } from 'vs/base/common/range';
|
||||
import { BrowserFeatures } from 'vs/base/browser/canIUse';
|
||||
|
||||
export const enum ContextViewDOMPosition {
|
||||
ABSOLUTE = 1,
|
||||
FIXED,
|
||||
FIXED_SHADOW
|
||||
}
|
||||
|
||||
export interface IAnchor {
|
||||
x: number;
|
||||
y: number;
|
||||
@@ -105,32 +111,62 @@ export class ContextView extends Disposable {
|
||||
private container: HTMLElement | null = null;
|
||||
private view: HTMLElement;
|
||||
private useFixedPosition: boolean;
|
||||
private useShadowDOM: boolean;
|
||||
private delegate: IDelegate | null = null;
|
||||
private toDisposeOnClean: IDisposable = Disposable.None;
|
||||
private toDisposeOnSetContainer: IDisposable = Disposable.None;
|
||||
private shadowRoot: ShadowRoot | null = null;
|
||||
private shadowRootHostElement: HTMLElement | null = null;
|
||||
|
||||
constructor(container: HTMLElement, useFixedPosition: boolean) {
|
||||
constructor(container: HTMLElement, domPosition: ContextViewDOMPosition) {
|
||||
super();
|
||||
|
||||
this.view = DOM.$('.context-view');
|
||||
this.useFixedPosition = false;
|
||||
this.useShadowDOM = false;
|
||||
|
||||
DOM.hide(this.view);
|
||||
|
||||
this.setContainer(container, useFixedPosition);
|
||||
this.setContainer(container, domPosition);
|
||||
|
||||
this._register(toDisposable(() => this.setContainer(null, false)));
|
||||
this._register(toDisposable(() => this.setContainer(null, ContextViewDOMPosition.ABSOLUTE)));
|
||||
}
|
||||
|
||||
setContainer(container: HTMLElement | null, useFixedPosition: boolean): void {
|
||||
setContainer(container: HTMLElement | null, domPosition: ContextViewDOMPosition): void {
|
||||
if (this.container) {
|
||||
this.toDisposeOnSetContainer.dispose();
|
||||
this.container.removeChild(this.view);
|
||||
|
||||
if (this.shadowRoot) {
|
||||
this.shadowRoot.removeChild(this.view);
|
||||
this.shadowRoot = null;
|
||||
DOM.removeNode(this.shadowRootHostElement!);
|
||||
this.shadowRootHostElement = null;
|
||||
} else {
|
||||
this.container.removeChild(this.view);
|
||||
}
|
||||
|
||||
this.container = null;
|
||||
}
|
||||
if (container) {
|
||||
this.container = container;
|
||||
this.container.appendChild(this.view);
|
||||
|
||||
this.useFixedPosition = domPosition !== ContextViewDOMPosition.ABSOLUTE;
|
||||
this.useShadowDOM = domPosition === ContextViewDOMPosition.FIXED_SHADOW;
|
||||
|
||||
if (this.useShadowDOM) {
|
||||
this.shadowRootHostElement = DOM.$('.shadow-root-host');
|
||||
this.container.appendChild(this.shadowRootHostElement);
|
||||
this.shadowRoot = this.shadowRootHostElement.attachShadow({ mode: 'closed' });
|
||||
this.shadowRoot.innerHTML = `
|
||||
<style>
|
||||
${SHADOW_ROOT_CSS}
|
||||
</style>
|
||||
`;
|
||||
this.shadowRoot.appendChild(this.view);
|
||||
this.shadowRoot.appendChild(DOM.$('slot'));
|
||||
} else {
|
||||
this.container.appendChild(this.view);
|
||||
}
|
||||
|
||||
const toDisposeOnSetContainer = new DisposableStore();
|
||||
|
||||
@@ -148,8 +184,6 @@ export class ContextView extends Disposable {
|
||||
|
||||
this.toDisposeOnSetContainer = toDisposeOnSetContainer;
|
||||
}
|
||||
|
||||
this.useFixedPosition = useFixedPosition;
|
||||
}
|
||||
|
||||
show(delegate: IDelegate): void {
|
||||
@@ -162,6 +196,7 @@ export class ContextView extends Disposable {
|
||||
this.view.className = 'context-view';
|
||||
this.view.style.top = '0px';
|
||||
this.view.style.left = '0px';
|
||||
this.view.style.zIndex = '2500';
|
||||
this.view.style.position = this.useFixedPosition ? 'fixed' : 'absolute';
|
||||
DOM.show(this.view);
|
||||
|
||||
@@ -301,3 +336,45 @@ export class ContextView extends Disposable {
|
||||
super.dispose();
|
||||
}
|
||||
}
|
||||
|
||||
let SHADOW_ROOT_CSS = /* css */ `
|
||||
:host {
|
||||
all: initial; /* 1st rule so subsequent properties are reset. */
|
||||
}
|
||||
|
||||
@font-face {
|
||||
font-family: "codicon";
|
||||
src: url("./codicon.ttf?5d4d76ab2ce5108968ad644d591a16a6") format("truetype");
|
||||
}
|
||||
|
||||
.codicon[class*='codicon-'] {
|
||||
font: normal normal normal 16px/1 codicon;
|
||||
display: inline-block;
|
||||
text-decoration: none;
|
||||
text-rendering: auto;
|
||||
text-align: center;
|
||||
-webkit-font-smoothing: antialiased;
|
||||
-moz-osx-font-smoothing: grayscale;
|
||||
user-select: none;
|
||||
-webkit-user-select: none;
|
||||
-ms-user-select: none;
|
||||
}
|
||||
|
||||
:host-context(.mac) { font-family: -apple-system, BlinkMacSystemFont, sans-serif; }
|
||||
:host-context(.mac:lang(zh-Hans)) { font-family: -apple-system, BlinkMacSystemFont, "PingFang SC", "Hiragino Sans GB", sans-serif; }
|
||||
:host-context(.mac:lang(zh-Hant)) { font-family: -apple-system, BlinkMacSystemFont, "PingFang TC", sans-serif; }
|
||||
:host-context(.mac:lang(ja)) { font-family: -apple-system, BlinkMacSystemFont, "Hiragino Kaku Gothic Pro", sans-serif; }
|
||||
:host-context(.mac:lang(ko)) { font-family: -apple-system, BlinkMacSystemFont, "Nanum Gothic", "Apple SD Gothic Neo", "AppleGothic", sans-serif; }
|
||||
|
||||
:host-context(.windows) { font-family: "Segoe WPC", "Segoe UI", sans-serif; }
|
||||
:host-context(.windows:lang(zh-Hans)) { font-family: "Segoe WPC", "Segoe UI", "Microsoft YaHei", sans-serif; }
|
||||
:host-context(.windows:lang(zh-Hant)) { font-family: "Segoe WPC", "Segoe UI", "Microsoft Jhenghei", sans-serif; }
|
||||
:host-context(.windows:lang(ja)) { font-family: "Segoe WPC", "Segoe UI", "Yu Gothic UI", "Meiryo UI", sans-serif; }
|
||||
:host-context(.windows:lang(ko)) { font-family: "Segoe WPC", "Segoe UI", "Malgun Gothic", "Dotom", sans-serif; }
|
||||
|
||||
:host-context(.mac).linux) { font-family: system-ui, "Ubuntu", "Droid Sans", sans-serif; }
|
||||
:host-context(.mac).linux:lang(zh-Hans)) { font-family: system-ui, "Ubuntu", "Droid Sans", "Source Han Sans SC", "Source Han Sans CN", "Source Han Sans", sans-serif; }
|
||||
:host-context(.mac).linux:lang(zh-Hant)) { font-family: system-ui, "Ubuntu", "Droid Sans", "Source Han Sans TC", "Source Han Sans TW", "Source Han Sans", sans-serif; }
|
||||
:host-context(.mac).linux:lang(ja)) { font-family: system-ui, "Ubuntu", "Droid Sans", "Source Han Sans J", "Source Han Sans JP", "Source Han Sans", sans-serif; }
|
||||
:host-context(.mac).linux:lang(ko)) { font-family: system-ui, "Ubuntu", "Droid Sans", "Source Han Sans K", "Source Han Sans JR", "Source Han Sans", "UnDotum", "FBaekmuk Gulim", sans-serif; }
|
||||
`;
|
||||
|
||||
@@ -270,7 +270,7 @@ export class DropdownMenu extends BaseDropdown {
|
||||
onHide: () => this.onHide(),
|
||||
actionRunner: this.menuOptions ? this.menuOptions.actionRunner : undefined,
|
||||
anchorAlignment: this.menuOptions ? this.menuOptions.anchorAlignment : AnchorAlignment.LEFT,
|
||||
anchorAsContainer: this.menuAsChild
|
||||
domForShadowRoot: this.menuAsChild ? this.element : undefined
|
||||
});
|
||||
}
|
||||
|
||||
@@ -297,15 +297,17 @@ export class DropdownMenuActionViewItem extends BaseActionViewItem {
|
||||
private _onDidChangeVisibility = this._register(new Emitter<boolean>());
|
||||
readonly onDidChangeVisibility = this._onDidChangeVisibility.event;
|
||||
|
||||
constructor(action: IAction, menuActions: ReadonlyArray<IAction>, contextMenuProvider: IContextMenuProvider, actionViewItemProvider: IActionViewItemProvider | undefined, actionRunner: IActionRunner, keybindings: ((action: IAction) => ResolvedKeybinding | undefined) | undefined, clazz: string | undefined, anchorAlignmentProvider?: () => AnchorAlignment, menuAsChild?: boolean);
|
||||
constructor(action: IAction, actionProvider: IActionProvider, contextMenuProvider: IContextMenuProvider, actionViewItemProvider: IActionViewItemProvider | undefined, actionRunner: IActionRunner, keybindings: ((action: IAction) => ResolvedKeybinding) | undefined, clazz: string | undefined, anchorAlignmentProvider?: () => AnchorAlignment, menuAsChild?: boolean);
|
||||
constructor(action: IAction, menuActionsOrProvider: ReadonlyArray<IAction> | IActionProvider, contextMenuProvider: IContextMenuProvider, actionViewItemProvider: IActionViewItemProvider | undefined, actionRunner: IActionRunner, keybindings: ((action: IAction) => ResolvedKeybinding | undefined) | undefined, clazz: string | undefined, anchorAlignmentProvider?: () => AnchorAlignment, menuAsChild?: boolean) {
|
||||
constructor(action: IAction, menuActions: ReadonlyArray<IAction>, contextMenuProvider: IContextMenuProvider, actionViewItemProvider: IActionViewItemProvider | undefined, actionRunner: IActionRunner | undefined, keybindings: ((action: IAction) => ResolvedKeybinding | undefined) | undefined, clazz: string | undefined, anchorAlignmentProvider?: () => AnchorAlignment, menuAsChild?: boolean);
|
||||
constructor(action: IAction, actionProvider: IActionProvider, contextMenuProvider: IContextMenuProvider, actionViewItemProvider: IActionViewItemProvider | undefined, actionRunner: IActionRunner | undefined, keybindings: ((action: IAction) => ResolvedKeybinding) | undefined, clazz: string | undefined, anchorAlignmentProvider?: () => AnchorAlignment, menuAsChild?: boolean);
|
||||
constructor(action: IAction, menuActionsOrProvider: ReadonlyArray<IAction> | IActionProvider, contextMenuProvider: IContextMenuProvider, actionViewItemProvider: IActionViewItemProvider | undefined, actionRunner: IActionRunner | undefined, keybindings: ((action: IAction) => ResolvedKeybinding | undefined) | undefined, clazz: string | undefined, anchorAlignmentProvider?: () => AnchorAlignment, menuAsChild?: boolean) {
|
||||
super(null, action);
|
||||
|
||||
this.menuActionsOrProvider = menuActionsOrProvider;
|
||||
this.contextMenuProvider = contextMenuProvider;
|
||||
this.actionViewItemProvider = actionViewItemProvider;
|
||||
this.actionRunner = actionRunner;
|
||||
if (actionRunner) {
|
||||
this.actionRunner = actionRunner;
|
||||
}
|
||||
this.keybindings = keybindings;
|
||||
this.clazz = clazz;
|
||||
this.anchorAlignmentProvider = anchorAlignmentProvider;
|
||||
|
||||
@@ -1,225 +0,0 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
.monaco-menu .monaco-action-bar.vertical {
|
||||
margin-left: 0;
|
||||
overflow: visible;
|
||||
}
|
||||
|
||||
.monaco-menu .monaco-action-bar.vertical .actions-container {
|
||||
display: block;
|
||||
}
|
||||
|
||||
.monaco-menu .monaco-action-bar.vertical .action-item {
|
||||
padding: 0;
|
||||
transform: none;
|
||||
display: flex;
|
||||
}
|
||||
|
||||
.monaco-menu .monaco-action-bar.vertical .action-item.active {
|
||||
transform: none;
|
||||
}
|
||||
|
||||
.monaco-menu .monaco-action-bar.vertical .action-menu-item {
|
||||
flex: 1 1 auto;
|
||||
display: flex;
|
||||
height: 2em;
|
||||
align-items: center;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.monaco-menu .monaco-action-bar.vertical .action-label {
|
||||
flex: 1 1 auto;
|
||||
text-decoration: none;
|
||||
padding: 0 1em;
|
||||
background: none;
|
||||
font-size: 12px;
|
||||
line-height: 1;
|
||||
}
|
||||
|
||||
.monaco-menu .monaco-action-bar.vertical .keybinding,
|
||||
.monaco-menu .monaco-action-bar.vertical .submenu-indicator {
|
||||
display: inline-block;
|
||||
flex: 2 1 auto;
|
||||
padding: 0 1em;
|
||||
text-align: right;
|
||||
font-size: 12px;
|
||||
line-height: 1;
|
||||
}
|
||||
|
||||
.monaco-menu .monaco-action-bar.vertical .submenu-indicator {
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
.monaco-menu .monaco-action-bar.vertical .submenu-indicator.codicon {
|
||||
font-size: 16px !important;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.monaco-menu .monaco-action-bar.vertical .submenu-indicator.codicon::before {
|
||||
margin-left: auto;
|
||||
margin-right: -20px;
|
||||
}
|
||||
|
||||
.monaco-menu .monaco-action-bar.vertical .action-item.disabled .keybinding,
|
||||
.monaco-menu .monaco-action-bar.vertical .action-item.disabled .submenu-indicator {
|
||||
opacity: 0.4;
|
||||
}
|
||||
|
||||
.monaco-menu .monaco-action-bar.vertical .action-label:not(.separator) {
|
||||
display: inline-block;
|
||||
box-sizing: border-box;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.monaco-menu .monaco-action-bar.vertical .action-item {
|
||||
position: static;
|
||||
overflow: visible;
|
||||
}
|
||||
|
||||
.monaco-menu .monaco-action-bar.vertical .action-item .monaco-submenu {
|
||||
position: absolute;
|
||||
}
|
||||
|
||||
.monaco-menu .monaco-action-bar.vertical .action-label.separator {
|
||||
padding: 0.5em 0 0 0;
|
||||
margin-bottom: 0.5em;
|
||||
width: 100%;
|
||||
height: 0px !important;
|
||||
margin-left: .8em !important;
|
||||
margin-right: .8em !important;
|
||||
}
|
||||
|
||||
.monaco-menu .monaco-action-bar.vertical .action-label.separator.text {
|
||||
padding: 0.7em 1em 0.1em 1em;
|
||||
font-weight: bold;
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
.monaco-menu .monaco-action-bar.vertical .action-label:hover {
|
||||
color: inherit;
|
||||
}
|
||||
|
||||
.monaco-menu .monaco-action-bar.vertical .menu-item-check {
|
||||
position: absolute;
|
||||
visibility: hidden;
|
||||
width: 1em;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
.monaco-menu .monaco-action-bar.vertical .action-menu-item.checked .menu-item-check {
|
||||
visibility: visible;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
/* Context Menu */
|
||||
|
||||
.context-view.monaco-menu-container {
|
||||
outline: 0;
|
||||
border: none;
|
||||
animation: fadeIn 0.083s linear;
|
||||
}
|
||||
|
||||
.context-view.monaco-menu-container :focus,
|
||||
.context-view.monaco-menu-container .monaco-action-bar.vertical:focus,
|
||||
.context-view.monaco-menu-container .monaco-action-bar.vertical :focus {
|
||||
outline: 0;
|
||||
}
|
||||
|
||||
.monaco-menu .monaco-action-bar.vertical .action-item {
|
||||
border: thin solid transparent; /* prevents jumping behaviour on hover or focus */
|
||||
}
|
||||
|
||||
|
||||
/* High Contrast Theming */
|
||||
.hc-black .context-view.monaco-menu-container {
|
||||
box-shadow: none;
|
||||
}
|
||||
|
||||
.hc-black .monaco-menu .monaco-action-bar.vertical .action-item.focused {
|
||||
background: none;
|
||||
}
|
||||
|
||||
/* Menubar styles */
|
||||
|
||||
.menubar {
|
||||
display: flex;
|
||||
flex-shrink: 1;
|
||||
box-sizing: border-box;
|
||||
height: 30px;
|
||||
overflow: hidden;
|
||||
flex-wrap: wrap;
|
||||
}
|
||||
|
||||
.fullscreen .menubar:not(.compact) {
|
||||
margin: 0px;
|
||||
padding: 0px 5px;
|
||||
}
|
||||
|
||||
.menubar > .menubar-menu-button {
|
||||
align-items: center;
|
||||
box-sizing: border-box;
|
||||
padding: 0px 8px;
|
||||
cursor: default;
|
||||
-webkit-app-region: no-drag;
|
||||
zoom: 1;
|
||||
white-space: nowrap;
|
||||
outline: 0;
|
||||
}
|
||||
|
||||
.menubar.compact {
|
||||
flex-shrink: 0;
|
||||
overflow: visible; /* to avoid the compact menu to be repositioned when clicking */
|
||||
}
|
||||
|
||||
.menubar.compact > .menubar-menu-button {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
padding: 0px;
|
||||
}
|
||||
|
||||
.menubar .menubar-menu-items-holder {
|
||||
position: absolute;
|
||||
left: 0px;
|
||||
opacity: 1;
|
||||
z-index: 2000;
|
||||
}
|
||||
|
||||
.menubar .menubar-menu-items-holder.monaco-menu-container {
|
||||
outline: 0;
|
||||
border: none;
|
||||
}
|
||||
|
||||
.menubar .menubar-menu-items-holder.monaco-menu-container :focus {
|
||||
outline: 0;
|
||||
}
|
||||
|
||||
.menubar .toolbar-toggle-more {
|
||||
width: 20px;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
.menubar.compact .toolbar-toggle-more {
|
||||
position: relative;
|
||||
left: 0px;
|
||||
top: 0px;
|
||||
cursor: pointer;
|
||||
width: 100%;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.menubar .toolbar-toggle-more {
|
||||
padding: 0;
|
||||
vertical-align: sub;
|
||||
}
|
||||
|
||||
.menubar.compact .toolbar-toggle-more::before {
|
||||
content: "\eb94" !important;
|
||||
}
|
||||
@@ -3,13 +3,12 @@
|
||||
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import 'vs/css!./menu';
|
||||
import * as nls from 'vs/nls';
|
||||
import * as strings from 'vs/base/common/strings';
|
||||
import { IActionRunner, IAction, Action } from 'vs/base/common/actions';
|
||||
import { ActionBar, IActionViewItemProvider, ActionsOrientation, Separator, ActionViewItem, IActionViewItemOptions, BaseActionViewItem } from 'vs/base/browser/ui/actionbar/actionbar';
|
||||
import { ResolvedKeybinding, KeyCode } from 'vs/base/common/keyCodes';
|
||||
import { addClass, EventType, EventHelper, EventLike, removeTabIndexAndUpdateFocus, isAncestor, hasClass, addDisposableListener, removeClass, append, $, addClasses, removeClasses, clearNode } from 'vs/base/browser/dom';
|
||||
import { addClass, EventType, EventHelper, EventLike, removeTabIndexAndUpdateFocus, isAncestor, hasClass, addDisposableListener, removeClass, append, $, addClasses, removeClasses, clearNode, createStyleSheet, isInShadowDOM } from 'vs/base/browser/dom';
|
||||
import { StandardKeyboardEvent } from 'vs/base/browser/keyboardEvent';
|
||||
import { RunOnceScheduler } from 'vs/base/common/async';
|
||||
import { DisposableStore } from 'vs/base/common/lifecycle';
|
||||
@@ -20,6 +19,7 @@ import { Event } from 'vs/base/common/event';
|
||||
import { AnchorAlignment } from 'vs/base/browser/ui/contextview/contextview';
|
||||
import { isLinux, isMacintosh } from 'vs/base/common/platform';
|
||||
import { Codicon, registerIcon, stripCodicons } from 'vs/base/common/codicons';
|
||||
import { formatRule } from 'vs/base/browser/ui/codicons/codiconStyles';
|
||||
|
||||
export const MENU_MNEMONIC_REGEX = /\(&([^\s&])\)|(^|[^&])&([^\s&])/;
|
||||
export const MENU_ESCAPED_MNEMONIC_REGEX = /(&)?(&)([^\s&])/g;
|
||||
@@ -71,6 +71,8 @@ export class Menu extends ActionBar {
|
||||
private readonly menuDisposables: DisposableStore;
|
||||
private scrollableElement: DomScrollableElement;
|
||||
private menuElement: HTMLElement;
|
||||
static globalStyleSheet: HTMLStyleElement;
|
||||
protected styleSheet: HTMLStyleElement | undefined;
|
||||
|
||||
constructor(container: HTMLElement, actions: ReadonlyArray<IAction>, options: IMenuOptions = {}) {
|
||||
addClass(container, 'monaco-menu-container');
|
||||
@@ -96,6 +98,8 @@ export class Menu extends ActionBar {
|
||||
|
||||
this.menuDisposables = this._register(new DisposableStore());
|
||||
|
||||
this.initializeStyleSheet(container);
|
||||
|
||||
addDisposableListener(menuElement, EventType.KEY_DOWN, (e) => {
|
||||
const event = new StandardKeyboardEvent(e);
|
||||
|
||||
@@ -215,6 +219,20 @@ export class Menu extends ActionBar {
|
||||
});
|
||||
}
|
||||
|
||||
private initializeStyleSheet(container: HTMLElement): void {
|
||||
if (isInShadowDOM(container)) {
|
||||
this.styleSheet = createStyleSheet(container);
|
||||
this.styleSheet.innerHTML = MENU_WIDGET_CSS;
|
||||
} else {
|
||||
if (!Menu.globalStyleSheet) {
|
||||
Menu.globalStyleSheet = createStyleSheet();
|
||||
Menu.globalStyleSheet.innerHTML = MENU_WIDGET_CSS;
|
||||
}
|
||||
|
||||
this.styleSheet = Menu.globalStyleSheet;
|
||||
}
|
||||
}
|
||||
|
||||
style(style: IMenuStyles): void {
|
||||
const container = this.getContainer();
|
||||
|
||||
@@ -877,3 +895,298 @@ export function cleanMnemonic(label: string): string {
|
||||
|
||||
return label.replace(regex, mnemonicInText ? '$2$3' : '').trim();
|
||||
}
|
||||
|
||||
let MENU_WIDGET_CSS: string = /* css */`
|
||||
.monaco-menu {
|
||||
font-size: 13px;
|
||||
|
||||
}
|
||||
|
||||
${formatRule(menuSelectionIcon)}
|
||||
${formatRule(menuSubmenuIcon)}
|
||||
|
||||
.monaco-action-bar {
|
||||
text-align: right;
|
||||
overflow: hidden;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.monaco-action-bar .actions-container {
|
||||
display: flex;
|
||||
margin: 0 auto;
|
||||
padding: 0;
|
||||
width: 100%;
|
||||
justify-content: flex-end;
|
||||
}
|
||||
|
||||
.monaco-action-bar.vertical .actions-container {
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
.monaco-action-bar.reverse .actions-container {
|
||||
flex-direction: row-reverse;
|
||||
}
|
||||
|
||||
.monaco-action-bar .action-item {
|
||||
cursor: pointer;
|
||||
display: inline-block;
|
||||
transition: transform 50ms ease;
|
||||
position: relative; /* DO NOT REMOVE - this is the key to preventing the ghosting icon bug in Chrome 42 */
|
||||
}
|
||||
|
||||
.monaco-action-bar .action-item.disabled {
|
||||
cursor: default;
|
||||
}
|
||||
|
||||
.monaco-action-bar.animated .action-item.active {
|
||||
transform: scale(1.272019649, 1.272019649); /* 1.272019649 = √φ */
|
||||
}
|
||||
|
||||
.monaco-action-bar .action-item .icon,
|
||||
.monaco-action-bar .action-item .codicon {
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
.monaco-action-bar .action-item .codicon {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.monaco-action-bar .action-label {
|
||||
font-size: 11px;
|
||||
margin-right: 4px;
|
||||
}
|
||||
|
||||
.monaco-action-bar .action-item.disabled .action-label,
|
||||
.monaco-action-bar .action-item.disabled .action-label:hover {
|
||||
opacity: 0.4;
|
||||
}
|
||||
|
||||
/* Vertical actions */
|
||||
|
||||
.monaco-action-bar.vertical {
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
.monaco-action-bar.vertical .action-item {
|
||||
display: block;
|
||||
}
|
||||
|
||||
.monaco-action-bar.vertical .action-label.separator {
|
||||
display: block;
|
||||
border-bottom: 1px solid #bbb;
|
||||
padding-top: 1px;
|
||||
margin-left: .8em;
|
||||
margin-right: .8em;
|
||||
}
|
||||
|
||||
.monaco-action-bar.animated.vertical .action-item.active {
|
||||
transform: translate(5px, 0);
|
||||
}
|
||||
|
||||
.secondary-actions .monaco-action-bar .action-label {
|
||||
margin-left: 6px;
|
||||
}
|
||||
|
||||
/* Action Items */
|
||||
.monaco-action-bar .action-item.select-container {
|
||||
overflow: hidden; /* somehow the dropdown overflows its container, we prevent it here to not push */
|
||||
flex: 1;
|
||||
max-width: 170px;
|
||||
min-width: 60px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
margin-right: 10px;
|
||||
}
|
||||
|
||||
.monaco-menu .monaco-action-bar.vertical {
|
||||
margin-left: 0;
|
||||
overflow: visible;
|
||||
}
|
||||
|
||||
.monaco-menu .monaco-action-bar.vertical .actions-container {
|
||||
display: block;
|
||||
}
|
||||
|
||||
.monaco-menu .monaco-action-bar.vertical .action-item {
|
||||
padding: 0;
|
||||
transform: none;
|
||||
display: flex;
|
||||
}
|
||||
|
||||
.monaco-menu .monaco-action-bar.vertical .action-item.active {
|
||||
transform: none;
|
||||
}
|
||||
|
||||
.monaco-menu .monaco-action-bar.vertical .action-menu-item {
|
||||
flex: 1 1 auto;
|
||||
display: flex;
|
||||
height: 2em;
|
||||
align-items: center;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.monaco-menu .monaco-action-bar.vertical .action-label {
|
||||
flex: 1 1 auto;
|
||||
text-decoration: none;
|
||||
padding: 0 1em;
|
||||
background: none;
|
||||
font-size: 12px;
|
||||
line-height: 1;
|
||||
}
|
||||
|
||||
.monaco-menu .monaco-action-bar.vertical .keybinding,
|
||||
.monaco-menu .monaco-action-bar.vertical .submenu-indicator {
|
||||
display: inline-block;
|
||||
flex: 2 1 auto;
|
||||
padding: 0 1em;
|
||||
text-align: right;
|
||||
font-size: 12px;
|
||||
line-height: 1;
|
||||
}
|
||||
|
||||
.monaco-menu .monaco-action-bar.vertical .submenu-indicator {
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
.monaco-menu .monaco-action-bar.vertical .submenu-indicator.codicon {
|
||||
font-size: 16px !important;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.monaco-menu .monaco-action-bar.vertical .submenu-indicator.codicon::before {
|
||||
margin-left: auto;
|
||||
margin-right: -20px;
|
||||
}
|
||||
|
||||
.monaco-menu .monaco-action-bar.vertical .action-item.disabled .keybinding,
|
||||
.monaco-menu .monaco-action-bar.vertical .action-item.disabled .submenu-indicator {
|
||||
opacity: 0.4;
|
||||
}
|
||||
|
||||
.monaco-menu .monaco-action-bar.vertical .action-label:not(.separator) {
|
||||
display: inline-block;
|
||||
box-sizing: border-box;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.monaco-menu .monaco-action-bar.vertical .action-item {
|
||||
position: static;
|
||||
overflow: visible;
|
||||
}
|
||||
|
||||
.monaco-menu .monaco-action-bar.vertical .action-item .monaco-submenu {
|
||||
position: absolute;
|
||||
}
|
||||
|
||||
.monaco-menu .monaco-action-bar.vertical .action-label.separator {
|
||||
padding: 0.5em 0 0 0;
|
||||
margin-bottom: 0.5em;
|
||||
width: 100%;
|
||||
height: 0px !important;
|
||||
margin-left: .8em !important;
|
||||
margin-right: .8em !important;
|
||||
}
|
||||
|
||||
.monaco-menu .monaco-action-bar.vertical .action-label.separator.text {
|
||||
padding: 0.7em 1em 0.1em 1em;
|
||||
font-weight: bold;
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
.monaco-menu .monaco-action-bar.vertical .action-label:hover {
|
||||
color: inherit;
|
||||
}
|
||||
|
||||
.monaco-menu .monaco-action-bar.vertical .menu-item-check {
|
||||
position: absolute;
|
||||
visibility: hidden;
|
||||
width: 1em;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
.monaco-menu .monaco-action-bar.vertical .action-menu-item.checked .menu-item-check {
|
||||
visibility: visible;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
/* Context Menu */
|
||||
|
||||
.context-view.monaco-menu-container {
|
||||
outline: 0;
|
||||
border: none;
|
||||
animation: fadeIn 0.083s linear;
|
||||
}
|
||||
|
||||
.context-view.monaco-menu-container :focus,
|
||||
.context-view.monaco-menu-container .monaco-action-bar.vertical:focus,
|
||||
.context-view.monaco-menu-container .monaco-action-bar.vertical :focus {
|
||||
outline: 0;
|
||||
}
|
||||
|
||||
.monaco-menu .monaco-action-bar.vertical .action-item {
|
||||
border: thin solid transparent; /* prevents jumping behaviour on hover or focus */
|
||||
}
|
||||
|
||||
|
||||
/* High Contrast Theming */
|
||||
.hc-black .context-view.monaco-menu-container {
|
||||
box-shadow: none;
|
||||
}
|
||||
|
||||
.hc-black .monaco-menu .monaco-action-bar.vertical .action-item.focused {
|
||||
background: none;
|
||||
}
|
||||
|
||||
/* Vertical Action Bar Styles */
|
||||
|
||||
.monaco-menu .monaco-action-bar.vertical {
|
||||
padding: .5em 0;
|
||||
}
|
||||
|
||||
.monaco-menu .monaco-action-bar.vertical .action-menu-item {
|
||||
height: 1.8em;
|
||||
}
|
||||
|
||||
.monaco-menu .monaco-action-bar.vertical .action-label:not(.separator),
|
||||
.monaco-menu .monaco-action-bar.vertical .keybinding {
|
||||
font-size: inherit;
|
||||
padding: 0 2em;
|
||||
}
|
||||
|
||||
.monaco-menu .monaco-action-bar.vertical .menu-item-check {
|
||||
font-size: inherit;
|
||||
width: 2em;
|
||||
}
|
||||
|
||||
.monaco-menu .monaco-action-bar.vertical .action-label.separator {
|
||||
font-size: inherit;
|
||||
padding: 0.2em 0 0 0;
|
||||
margin-bottom: 0.2em;
|
||||
}
|
||||
|
||||
linux .monaco-menu .monaco-action-bar.vertical .action-label.separator {
|
||||
margin-left: 0;
|
||||
margin-right: 0;
|
||||
}
|
||||
|
||||
.monaco-menu .monaco-action-bar.vertical .submenu-indicator {
|
||||
font-size: 60%;
|
||||
padding: 0 1.8em;
|
||||
}
|
||||
|
||||
:host-context(.linux) .monaco-menu .monaco-action-bar.vertical .submenu-indicator {
|
||||
height: 100%;
|
||||
mask-size: 10px 10px;
|
||||
-webkit-mask-size: 10px 10px;
|
||||
}
|
||||
|
||||
.monaco-menu .action-item {
|
||||
cursor: default;
|
||||
}
|
||||
|
||||
`;
|
||||
|
||||
83
src/vs/base/browser/ui/menu/menubar.css
Normal file
83
src/vs/base/browser/ui/menu/menubar.css
Normal file
@@ -0,0 +1,83 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
/* Menubar styles */
|
||||
|
||||
.menubar {
|
||||
display: flex;
|
||||
flex-shrink: 1;
|
||||
box-sizing: border-box;
|
||||
height: 30px;
|
||||
overflow: hidden;
|
||||
flex-wrap: wrap;
|
||||
}
|
||||
|
||||
.fullscreen .menubar:not(.compact) {
|
||||
margin: 0px;
|
||||
padding: 0px 5px;
|
||||
}
|
||||
|
||||
.menubar > .menubar-menu-button {
|
||||
align-items: center;
|
||||
box-sizing: border-box;
|
||||
padding: 0px 8px;
|
||||
cursor: default;
|
||||
-webkit-app-region: no-drag;
|
||||
zoom: 1;
|
||||
white-space: nowrap;
|
||||
outline: 0;
|
||||
}
|
||||
|
||||
.menubar.compact {
|
||||
flex-shrink: 0;
|
||||
overflow: visible; /* to avoid the compact menu to be repositioned when clicking */
|
||||
}
|
||||
|
||||
.menubar.compact > .menubar-menu-button {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
padding: 0px;
|
||||
}
|
||||
|
||||
.menubar .menubar-menu-items-holder {
|
||||
position: absolute;
|
||||
left: 0px;
|
||||
opacity: 1;
|
||||
z-index: 2000;
|
||||
}
|
||||
|
||||
.menubar .menubar-menu-items-holder.monaco-menu-container {
|
||||
outline: 0;
|
||||
border: none;
|
||||
}
|
||||
|
||||
.menubar .menubar-menu-items-holder.monaco-menu-container :focus {
|
||||
outline: 0;
|
||||
}
|
||||
|
||||
.menubar .toolbar-toggle-more {
|
||||
width: 20px;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
.menubar.compact .toolbar-toggle-more {
|
||||
position: relative;
|
||||
left: 0px;
|
||||
top: 0px;
|
||||
cursor: pointer;
|
||||
width: 100%;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.menubar .toolbar-toggle-more {
|
||||
padding: 0;
|
||||
vertical-align: sub;
|
||||
}
|
||||
|
||||
.menubar.compact .toolbar-toggle-more::before {
|
||||
content: "\eb94" !important;
|
||||
}
|
||||
@@ -3,6 +3,7 @@
|
||||
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import 'vs/css!./menubar';
|
||||
import * as browser from 'vs/base/browser/browser';
|
||||
import * as DOM from 'vs/base/browser/dom';
|
||||
import * as strings from 'vs/base/common/strings';
|
||||
|
||||
@@ -3,8 +3,9 @@
|
||||
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import { URI } from 'vs/base/common/uri';
|
||||
import { VSBuffer } from 'vs/base/common/buffer';
|
||||
import { regExpFlags } from 'vs/base/common/strings';
|
||||
import { URI } from 'vs/base/common/uri';
|
||||
|
||||
export function stringify(obj: any): string {
|
||||
return JSON.stringify(obj, replacer);
|
||||
@@ -44,10 +45,23 @@ export function revive(obj: any, depth = 0): any {
|
||||
case 2: return new RegExp(obj.source, obj.flags);
|
||||
}
|
||||
|
||||
// walk object (or array)
|
||||
for (let key in obj) {
|
||||
if (Object.hasOwnProperty.call(obj, key)) {
|
||||
obj[key] = revive(obj[key], depth + 1);
|
||||
if (
|
||||
obj instanceof VSBuffer
|
||||
|| obj instanceof Uint8Array
|
||||
) {
|
||||
return obj;
|
||||
}
|
||||
|
||||
if (Array.isArray(obj)) {
|
||||
for (let i = 0; i < obj.length; ++i) {
|
||||
obj[i] = revive(obj[i], depth + 1);
|
||||
}
|
||||
} else {
|
||||
// walk object
|
||||
for (const key in obj) {
|
||||
if (Object.hasOwnProperty.call(obj, key)) {
|
||||
obj[key] = revive(obj[key], depth + 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -16,6 +16,7 @@ export interface ISocket extends IDisposable {
|
||||
onEnd(listener: () => void): IDisposable;
|
||||
write(buffer: VSBuffer): void;
|
||||
end(): void;
|
||||
drain(): Promise<void>;
|
||||
}
|
||||
|
||||
let emptyBuffer: VSBuffer | null = null;
|
||||
@@ -277,6 +278,11 @@ class ProtocolWriter {
|
||||
this._isDisposed = true;
|
||||
}
|
||||
|
||||
public drain(): Promise<void> {
|
||||
this.flush();
|
||||
return this._socket.drain();
|
||||
}
|
||||
|
||||
public flush(): void {
|
||||
// flush
|
||||
this._writeNow();
|
||||
@@ -372,6 +378,10 @@ export class Protocol extends Disposable implements IMessagePassingProtocol {
|
||||
this._register(this._socket.onClose(() => this._onClose.fire()));
|
||||
}
|
||||
|
||||
drain(): Promise<void> {
|
||||
return this._socketWriter.drain();
|
||||
}
|
||||
|
||||
getSocket(): ISocket {
|
||||
return this._socket;
|
||||
}
|
||||
@@ -619,6 +629,10 @@ export class PersistentProtocol implements IMessagePassingProtocol {
|
||||
this._socketDisposables = dispose(this._socketDisposables);
|
||||
}
|
||||
|
||||
drain(): Promise<void> {
|
||||
return this._socketWriter.drain();
|
||||
}
|
||||
|
||||
sendDisconnect(): void {
|
||||
const msg = new ProtocolMessage(ProtocolMessageType.Disconnect, 0, 0, getEmptyBuffer());
|
||||
this._socketWriter.write(msg);
|
||||
|
||||
@@ -70,6 +70,10 @@ interface IHandler {
|
||||
export interface IMessagePassingProtocol {
|
||||
send(buffer: VSBuffer): void;
|
||||
onMessage: Event<VSBuffer>;
|
||||
/**
|
||||
* Wait for the write buffer (if applicable) to become empty.
|
||||
*/
|
||||
drain?(): Promise<void>;
|
||||
}
|
||||
|
||||
enum State {
|
||||
@@ -482,10 +486,7 @@ export class ChannelClient implements IChannelClient, IDisposable {
|
||||
return e(errors.canceled());
|
||||
}
|
||||
|
||||
let uninitializedPromise: CancelablePromise<void> | null = createCancelablePromise(_ => this.whenInitialized());
|
||||
uninitializedPromise.then(() => {
|
||||
uninitializedPromise = null;
|
||||
|
||||
const doRequest = () => {
|
||||
const handler: IHandler = response => {
|
||||
switch (response.type) {
|
||||
case ResponseType.PromiseSuccess:
|
||||
@@ -510,7 +511,18 @@ export class ChannelClient implements IChannelClient, IDisposable {
|
||||
|
||||
this.handlers.set(id, handler);
|
||||
this.sendRequest(request);
|
||||
});
|
||||
};
|
||||
|
||||
let uninitializedPromise: CancelablePromise<void> | null = null;
|
||||
if (this.state === State.Idle) {
|
||||
doRequest();
|
||||
} else {
|
||||
uninitializedPromise = createCancelablePromise(_ => this.whenInitialized());
|
||||
uninitializedPromise.then(() => {
|
||||
uninitializedPromise = null;
|
||||
doRequest();
|
||||
});
|
||||
}
|
||||
|
||||
const cancel = () => {
|
||||
if (uninitializedPromise) {
|
||||
|
||||
@@ -12,6 +12,7 @@ import { generateUuid } from 'vs/base/common/uuid';
|
||||
import { IDisposable, Disposable } from 'vs/base/common/lifecycle';
|
||||
import { VSBuffer } from 'vs/base/common/buffer';
|
||||
import { ISocket, Protocol, Client, ChunkStream } from 'vs/base/parts/ipc/common/ipc.net';
|
||||
import { onUnexpectedError } from 'vs/base/common/errors';
|
||||
|
||||
export class NodeSocket implements ISocket {
|
||||
public readonly socket: Socket;
|
||||
@@ -57,12 +58,47 @@ export class NodeSocket implements ISocket {
|
||||
// > https://nodejs.org/api/stream.html#stream_writable_write_chunk_encoding_callback
|
||||
// > However, the false return value is only advisory and the writable stream will unconditionally
|
||||
// > accept and buffer chunk even if it has not been allowed to drain.
|
||||
this.socket.write(<Buffer>buffer.buffer);
|
||||
try {
|
||||
this.socket.write(<Buffer>buffer.buffer);
|
||||
} catch (err) {
|
||||
if (err.code === 'EPIPE') {
|
||||
// An EPIPE exception at the wrong time can lead to a renderer process crash
|
||||
// so ignore the error since the socket will fire the close event soon anyways:
|
||||
// > https://nodejs.org/api/errors.html#errors_common_system_errors
|
||||
// > EPIPE (Broken pipe): A write on a pipe, socket, or FIFO for which there is no
|
||||
// > process to read the data. Commonly encountered at the net and http layers,
|
||||
// > indicative that the remote side of the stream being written to has been closed.
|
||||
return;
|
||||
}
|
||||
onUnexpectedError(err);
|
||||
}
|
||||
}
|
||||
|
||||
public end(): void {
|
||||
this.socket.end();
|
||||
}
|
||||
|
||||
public drain(): Promise<void> {
|
||||
return new Promise<void>((resolve, reject) => {
|
||||
if (this.socket.bufferSize === 0) {
|
||||
resolve();
|
||||
return;
|
||||
}
|
||||
const finished = () => {
|
||||
this.socket.off('close', finished);
|
||||
this.socket.off('end', finished);
|
||||
this.socket.off('error', finished);
|
||||
this.socket.off('timeout', finished);
|
||||
this.socket.off('drain', finished);
|
||||
resolve();
|
||||
};
|
||||
this.socket.on('close', finished);
|
||||
this.socket.on('end', finished);
|
||||
this.socket.on('error', finished);
|
||||
this.socket.on('timeout', finished);
|
||||
this.socket.on('drain', finished);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
const enum Constants {
|
||||
@@ -229,6 +265,10 @@ export class WebSocketNodeSocket extends Disposable implements ISocket {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public drain(): Promise<void> {
|
||||
return this.socket.drain();
|
||||
}
|
||||
}
|
||||
|
||||
function unmask(buffer: VSBuffer, mask: number): void {
|
||||
|
||||
@@ -90,6 +90,7 @@ export class CodeActionMenu extends Disposable {
|
||||
const resolver = this._keybindingResolver.getResolver();
|
||||
|
||||
this._contextMenuService.showContextMenu({
|
||||
domForShadowRoot: this._editor.getDomNode()!,
|
||||
getAnchor: () => anchor,
|
||||
getActions: () => menuActions,
|
||||
onHide: () => {
|
||||
|
||||
@@ -205,6 +205,8 @@ export class ContextMenuController implements IEditorContribution {
|
||||
// Show menu
|
||||
this._contextMenuIsBeingShownCount++;
|
||||
this._contextMenuService.showContextMenu({
|
||||
domForShadowRoot: this._editor.getDomNode(),
|
||||
|
||||
getAnchor: () => anchor!,
|
||||
|
||||
getActions: () => actions,
|
||||
|
||||
@@ -54,6 +54,7 @@ export class DragAndDropController extends Disposable implements IEditorContribu
|
||||
this._register(this._editor.onKeyDown((e: IKeyboardEvent) => this.onEditorKeyDown(e)));
|
||||
this._register(this._editor.onKeyUp((e: IKeyboardEvent) => this.onEditorKeyUp(e)));
|
||||
this._register(this._editor.onDidBlurEditorWidget(() => this.onEditorBlur()));
|
||||
this._register(this._editor.onDidBlurEditorText(() => this.onEditorBlur()));
|
||||
this._dndDecorationIds = [];
|
||||
this._mouseDown = false;
|
||||
this._modifierPressed = false;
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
/* Find widget */
|
||||
.monaco-editor .find-widget {
|
||||
position: absolute;
|
||||
z-index: 10;
|
||||
z-index: 20;
|
||||
height: 33px;
|
||||
overflow: hidden;
|
||||
line-height: 19px;
|
||||
|
||||
@@ -50,7 +50,7 @@ export class ContextMenuHandler {
|
||||
|
||||
let menu: Menu | undefined;
|
||||
|
||||
const anchor = delegate.getAnchor();
|
||||
let shadowRootElement = isHTMLElement(delegate.domForShadowRoot) ? delegate.domForShadowRoot : undefined;
|
||||
this.contextViewService.showContextView({
|
||||
getAnchor: () => delegate.getAnchor(),
|
||||
canRelayout: false,
|
||||
@@ -133,7 +133,7 @@ export class ContextMenuHandler {
|
||||
this.focusToReturn.focus();
|
||||
}
|
||||
}
|
||||
}, !!delegate.anchorAsContainer && isHTMLElement(anchor) ? anchor : undefined);
|
||||
}, shadowRootElement, !!shadowRootElement);
|
||||
}
|
||||
|
||||
private onActionRun(e: IRunEvent): void {
|
||||
|
||||
@@ -15,7 +15,7 @@ export interface IContextViewService extends IContextViewProvider {
|
||||
|
||||
readonly _serviceBrand: undefined;
|
||||
|
||||
showContextView(delegate: IContextViewDelegate, container?: HTMLElement): IDisposable;
|
||||
showContextView(delegate: IContextViewDelegate, container?: HTMLElement, shadowRoot?: boolean): IDisposable;
|
||||
hideContextView(data?: any): void;
|
||||
layout(): void;
|
||||
anchorAlignment?: AnchorAlignment;
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import { IContextViewService, IContextViewDelegate } from './contextView';
|
||||
import { ContextView } from 'vs/base/browser/ui/contextview/contextview';
|
||||
import { ContextView, ContextViewDOMPosition } from 'vs/base/browser/ui/contextview/contextview';
|
||||
import { Disposable, IDisposable, toDisposable } from 'vs/base/common/lifecycle';
|
||||
import { ILayoutService } from 'vs/platform/layout/browser/layoutService';
|
||||
|
||||
@@ -21,7 +21,7 @@ export class ContextViewService extends Disposable implements IContextViewServic
|
||||
super();
|
||||
|
||||
this.container = layoutService.container;
|
||||
this.contextView = this._register(new ContextView(this.container, false));
|
||||
this.contextView = this._register(new ContextView(this.container, ContextViewDOMPosition.ABSOLUTE));
|
||||
this.layout();
|
||||
|
||||
this._register(layoutService.onLayout(() => this.layout()));
|
||||
@@ -29,20 +29,20 @@ export class ContextViewService extends Disposable implements IContextViewServic
|
||||
|
||||
// ContextView
|
||||
|
||||
setContainer(container: HTMLElement, useFixedPosition?: boolean): void {
|
||||
this.contextView.setContainer(container, !!useFixedPosition);
|
||||
setContainer(container: HTMLElement, domPosition?: ContextViewDOMPosition): void {
|
||||
this.contextView.setContainer(container, domPosition || ContextViewDOMPosition.ABSOLUTE);
|
||||
}
|
||||
|
||||
showContextView(delegate: IContextViewDelegate, container?: HTMLElement): IDisposable {
|
||||
showContextView(delegate: IContextViewDelegate, container?: HTMLElement, shadowRoot?: boolean): IDisposable {
|
||||
if (container) {
|
||||
if (container !== this.container) {
|
||||
this.container = container;
|
||||
this.setContainer(container, true);
|
||||
this.setContainer(container, shadowRoot ? ContextViewDOMPosition.FIXED_SHADOW : ContextViewDOMPosition.FIXED);
|
||||
}
|
||||
} else {
|
||||
if (this.container !== this.layoutService.container) {
|
||||
this.container = this.layoutService.container;
|
||||
this.setContainer(this.container, false);
|
||||
this.setContainer(this.container, ContextViewDOMPosition.ABSOLUTE);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -149,8 +149,25 @@ export interface IExtensionIdentifier {
|
||||
uuid?: string;
|
||||
}
|
||||
|
||||
export const EXTENSION_CATEGORIES = ['Programming Languages', 'Snippets', 'Linters', 'Themes', 'Debuggers', 'Other', 'Keymaps', 'Formatters', 'Extension Packs',
|
||||
'SCM Providers', 'Azure', 'Language Packs', 'Data Science', 'Machine Learning', 'Visualization', 'Testing', 'Notebooks'];
|
||||
export const EXTENSION_CATEGORIES = [
|
||||
'Azure',
|
||||
'Data Science',
|
||||
'Debuggers',
|
||||
'Extension Packs',
|
||||
'Formatters',
|
||||
'Keymaps',
|
||||
'Language Packs',
|
||||
'Linters',
|
||||
'Machine Learning',
|
||||
'Notebooks',
|
||||
'Programming Languages',
|
||||
'SCM Providers',
|
||||
'Snippets',
|
||||
'Themes',
|
||||
'Testing',
|
||||
'Visualization',
|
||||
'Other',
|
||||
];
|
||||
|
||||
export interface IExtensionManifest {
|
||||
readonly name: string;
|
||||
|
||||
@@ -194,6 +194,9 @@ class BrowserSocket implements ISocket {
|
||||
this.socket.close();
|
||||
}
|
||||
|
||||
public drain(): Promise<void> {
|
||||
return Promise.resolve();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -82,10 +82,19 @@ class RemovedResources {
|
||||
|
||||
let messages: string[] = [];
|
||||
if (externalRemoval.length > 0) {
|
||||
messages.push(nls.localize('externalRemoval', "The following files have been closed and modified on disk: {0}.", externalRemoval.join(', ')));
|
||||
messages.push(
|
||||
nls.localize(
|
||||
{ key: 'externalRemoval', comment: ['{0} is a list of filenames'] },
|
||||
"The following files have been closed and modified on disk: {0}.", externalRemoval.join(', ')
|
||||
)
|
||||
);
|
||||
}
|
||||
if (noParallelUniverses.length > 0) {
|
||||
messages.push(nls.localize('noParallelUniverses', "The following files have been modified in an incompatible way: {0}.", noParallelUniverses.join(', ')));
|
||||
messages.push(
|
||||
nls.localize(
|
||||
{ key: 'noParallelUniverses', comment: ['{0} is a list of filenames'] },
|
||||
"The following files have been modified in an incompatible way: {0}.", noParallelUniverses.join(', ')
|
||||
));
|
||||
}
|
||||
return messages.join('\n');
|
||||
}
|
||||
@@ -771,10 +780,26 @@ export class UndoRedoService implements IUndoRedoService {
|
||||
|
||||
private _checkWorkspaceUndo(strResource: string, element: WorkspaceStackElement, editStackSnapshot: EditStackSnapshot, checkInvalidatedResources: boolean): WorkspaceVerificationError | null {
|
||||
if (element.removedResources) {
|
||||
return this._tryToSplitAndUndo(strResource, element, element.removedResources, nls.localize('cannotWorkspaceUndo', "Could not undo '{0}' across all files. {1}", element.label, element.removedResources.createMessage()));
|
||||
return this._tryToSplitAndUndo(
|
||||
strResource,
|
||||
element,
|
||||
element.removedResources,
|
||||
nls.localize(
|
||||
{ key: 'cannotWorkspaceUndo', comment: ['{0} is a label for an operation. {1} is another message.'] },
|
||||
"Could not undo '{0}' across all files. {1}", element.label, element.removedResources.createMessage()
|
||||
)
|
||||
);
|
||||
}
|
||||
if (checkInvalidatedResources && element.invalidatedResources) {
|
||||
return this._tryToSplitAndUndo(strResource, element, element.invalidatedResources, nls.localize('cannotWorkspaceUndo', "Could not undo '{0}' across all files. {1}", element.label, element.invalidatedResources.createMessage()));
|
||||
return this._tryToSplitAndUndo(
|
||||
strResource,
|
||||
element,
|
||||
element.invalidatedResources,
|
||||
nls.localize(
|
||||
{ key: 'cannotWorkspaceUndo', comment: ['{0} is a label for an operation. {1} is another message.'] },
|
||||
"Could not undo '{0}' across all files. {1}", element.label, element.invalidatedResources.createMessage()
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
// this must be the last past element in all the impacted resources!
|
||||
@@ -785,7 +810,15 @@ export class UndoRedoService implements IUndoRedoService {
|
||||
}
|
||||
}
|
||||
if (cannotUndoDueToResources.length > 0) {
|
||||
return this._tryToSplitAndUndo(strResource, element, null, nls.localize('cannotWorkspaceUndoDueToChanges', "Could not undo '{0}' across all files because changes were made to {1}", element.label, cannotUndoDueToResources.join(', ')));
|
||||
return this._tryToSplitAndUndo(
|
||||
strResource,
|
||||
element,
|
||||
null,
|
||||
nls.localize(
|
||||
{ key: 'cannotWorkspaceUndoDueToChanges', comment: ['{0} is a label for an operation. {1} is a list of filenames.'] },
|
||||
"Could not undo '{0}' across all files because changes were made to {1}", element.label, cannotUndoDueToResources.join(', ')
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
const cannotLockDueToResources: string[] = [];
|
||||
@@ -795,12 +828,28 @@ export class UndoRedoService implements IUndoRedoService {
|
||||
}
|
||||
}
|
||||
if (cannotLockDueToResources.length > 0) {
|
||||
return this._tryToSplitAndUndo(strResource, element, null, nls.localize('cannotWorkspaceUndoDueToInProgressUndoRedo', "Could not undo '{0}' across all files because there is already an undo or redo operation running on {1}", element.label, cannotLockDueToResources.join(', ')));
|
||||
return this._tryToSplitAndUndo(
|
||||
strResource,
|
||||
element,
|
||||
null,
|
||||
nls.localize(
|
||||
{ key: 'cannotWorkspaceUndoDueToInProgressUndoRedo', comment: ['{0} is a label for an operation. {1} is a list of filenames.'] },
|
||||
"Could not undo '{0}' across all files because there is already an undo or redo operation running on {1}", element.label, cannotLockDueToResources.join(', ')
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
// check if new stack elements were added in the meantime...
|
||||
if (!editStackSnapshot.isValid()) {
|
||||
return this._tryToSplitAndUndo(strResource, element, null, nls.localize('cannotWorkspaceUndoDueToInMeantimeUndoRedo', "Could not undo '{0}' across all files because an undo or redo operation occurred in the meantime", element.label));
|
||||
return this._tryToSplitAndUndo(
|
||||
strResource,
|
||||
element,
|
||||
null,
|
||||
nls.localize(
|
||||
{ key: 'cannotWorkspaceUndoDueToInMeantimeUndoRedo', comment: ['{0} is a label for an operation. {1} is a list of filenames.'] },
|
||||
"Could not undo '{0}' across all files because an undo or redo operation occurred in the meantime", element.label
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
return null;
|
||||
@@ -881,7 +930,10 @@ export class UndoRedoService implements IUndoRedoService {
|
||||
return;
|
||||
}
|
||||
if (editStack.locked) {
|
||||
const message = nls.localize('cannotResourceUndoDueToInProgressUndoRedo', "Could not undo '{0}' because there is already an undo or redo operation running.", element.label);
|
||||
const message = nls.localize(
|
||||
{ key: 'cannotResourceUndoDueToInProgressUndoRedo', comment: ['{0} is a label for an operation.'] },
|
||||
"Could not undo '{0}' because there is already an undo or redo operation running.", element.label
|
||||
);
|
||||
this._notificationService.info(message);
|
||||
return;
|
||||
}
|
||||
@@ -942,10 +994,26 @@ export class UndoRedoService implements IUndoRedoService {
|
||||
|
||||
private _checkWorkspaceRedo(strResource: string, element: WorkspaceStackElement, editStackSnapshot: EditStackSnapshot, checkInvalidatedResources: boolean): WorkspaceVerificationError | null {
|
||||
if (element.removedResources) {
|
||||
return this._tryToSplitAndRedo(strResource, element, element.removedResources, nls.localize('cannotWorkspaceRedo', "Could not redo '{0}' across all files. {1}", element.label, element.removedResources.createMessage()));
|
||||
return this._tryToSplitAndRedo(
|
||||
strResource,
|
||||
element,
|
||||
element.removedResources,
|
||||
nls.localize(
|
||||
{ key: 'cannotWorkspaceRedo', comment: ['{0} is a label for an operation. {1} is another message.'] },
|
||||
"Could not redo '{0}' across all files. {1}", element.label, element.removedResources.createMessage()
|
||||
)
|
||||
);
|
||||
}
|
||||
if (checkInvalidatedResources && element.invalidatedResources) {
|
||||
return this._tryToSplitAndRedo(strResource, element, element.invalidatedResources, nls.localize('cannotWorkspaceRedo', "Could not redo '{0}' across all files. {1}", element.label, element.invalidatedResources.createMessage()));
|
||||
return this._tryToSplitAndRedo(
|
||||
strResource,
|
||||
element,
|
||||
element.invalidatedResources,
|
||||
nls.localize(
|
||||
{ key: 'cannotWorkspaceRedo', comment: ['{0} is a label for an operation. {1} is another message.'] },
|
||||
"Could not redo '{0}' across all files. {1}", element.label, element.invalidatedResources.createMessage()
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
// this must be the last future element in all the impacted resources!
|
||||
@@ -956,7 +1024,15 @@ export class UndoRedoService implements IUndoRedoService {
|
||||
}
|
||||
}
|
||||
if (cannotRedoDueToResources.length > 0) {
|
||||
return this._tryToSplitAndRedo(strResource, element, null, nls.localize('cannotWorkspaceRedoDueToChanges', "Could not redo '{0}' across all files because changes were made to {1}", element.label, cannotRedoDueToResources.join(', ')));
|
||||
return this._tryToSplitAndRedo(
|
||||
strResource,
|
||||
element,
|
||||
null,
|
||||
nls.localize(
|
||||
{ key: 'cannotWorkspaceRedoDueToChanges', comment: ['{0} is a label for an operation. {1} is a list of filenames.'] },
|
||||
"Could not redo '{0}' across all files because changes were made to {1}", element.label, cannotRedoDueToResources.join(', ')
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
const cannotLockDueToResources: string[] = [];
|
||||
@@ -966,12 +1042,28 @@ export class UndoRedoService implements IUndoRedoService {
|
||||
}
|
||||
}
|
||||
if (cannotLockDueToResources.length > 0) {
|
||||
return this._tryToSplitAndRedo(strResource, element, null, nls.localize('cannotWorkspaceRedoDueToInProgressUndoRedo', "Could not redo '{0}' across all files because there is already an undo or redo operation running on {1}", element.label, cannotLockDueToResources.join(', ')));
|
||||
return this._tryToSplitAndRedo(
|
||||
strResource,
|
||||
element,
|
||||
null,
|
||||
nls.localize(
|
||||
{ key: 'cannotWorkspaceRedoDueToInProgressUndoRedo', comment: ['{0} is a label for an operation. {1} is a list of filenames.'] },
|
||||
"Could not redo '{0}' across all files because there is already an undo or redo operation running on {1}", element.label, cannotLockDueToResources.join(', ')
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
// check if new stack elements were added in the meantime...
|
||||
if (!editStackSnapshot.isValid()) {
|
||||
return this._tryToSplitAndRedo(strResource, element, null, nls.localize('cannotWorkspaceRedoDueToInMeantimeUndoRedo', "Could not redo '{0}' across all files because an undo or redo operation occurred in the meantime", element.label));
|
||||
return this._tryToSplitAndRedo(
|
||||
strResource,
|
||||
element,
|
||||
null,
|
||||
nls.localize(
|
||||
{ key: 'cannotWorkspaceRedoDueToInMeantimeUndoRedo', comment: ['{0} is a label for an operation. {1} is a list of filenames.'] },
|
||||
"Could not redo '{0}' across all files because an undo or redo operation occurred in the meantime", element.label
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
return null;
|
||||
@@ -1015,7 +1107,10 @@ export class UndoRedoService implements IUndoRedoService {
|
||||
return;
|
||||
}
|
||||
if (editStack.locked) {
|
||||
const message = nls.localize('cannotResourceRedoDueToInProgressUndoRedo', "Could not redo '{0}' because there is already an undo or redo operation running.", element.label);
|
||||
const message = nls.localize(
|
||||
{ key: 'cannotResourceRedoDueToInProgressUndoRedo', comment: ['{0} is a label for an operation.'] },
|
||||
"Could not redo '{0}' because there is already an undo or redo operation running.", element.label
|
||||
);
|
||||
this._notificationService.info(message);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -32,6 +32,7 @@ type AutoSyncErrorClassification = {
|
||||
const enablementKey = 'sync.enable';
|
||||
const disableMachineEventuallyKey = 'sync.disableMachineEventually';
|
||||
const sessionIdKey = 'sync.sessionId';
|
||||
const storeUrlKey = 'sync.storeUrl';
|
||||
|
||||
export class UserDataAutoSyncEnablementService extends Disposable {
|
||||
|
||||
@@ -97,15 +98,20 @@ export class UserDataAutoSyncService extends UserDataAutoSyncEnablementService i
|
||||
this.syncTriggerDelayer = this._register(new Delayer<void>(0));
|
||||
|
||||
if (userDataSyncStoreService.userDataSyncStore) {
|
||||
|
||||
storageService.store(storeUrlKey, userDataSyncStoreService.userDataSyncStore.url.toString(), StorageScope.GLOBAL);
|
||||
|
||||
if (this.isEnabled()) {
|
||||
this.logService.info('Auto Sync is enabled.');
|
||||
} else {
|
||||
this.logService.info('Auto Sync is disabled.');
|
||||
}
|
||||
this.updateAutoSync();
|
||||
|
||||
if (this.hasToDisableMachineEventually()) {
|
||||
this.disableMachineEventually();
|
||||
}
|
||||
|
||||
this._register(userDataSyncAccountService.onDidChangeAccount(() => this.updateAutoSync()));
|
||||
this._register(userDataSyncStoreService.onDidChangeDonotMakeRequestsUntil(() => this.updateAutoSync()));
|
||||
this._register(Event.debounce<string, string[]>(userDataSyncService.onDidChangeLocal, (last, source) => last ? [...last, source] : [source], 1000)(sources => this.triggerSync(sources, false)));
|
||||
|
||||
16
src/vs/vscode.proposed.d.ts
vendored
16
src/vs/vscode.proposed.d.ts
vendored
@@ -868,22 +868,6 @@ declare module 'vscode' {
|
||||
debugAdapterExecutable?(folder: WorkspaceFolder | undefined, token?: CancellationToken): ProviderResult<DebugAdapterExecutable>;
|
||||
}
|
||||
|
||||
export interface DebugSession {
|
||||
|
||||
/**
|
||||
* Terminates the session.
|
||||
*/
|
||||
terminate(): Thenable<void>;
|
||||
}
|
||||
|
||||
export interface DebugSession {
|
||||
|
||||
/**
|
||||
* Terminates the session.
|
||||
*/
|
||||
terminate(): Thenable<void>;
|
||||
}
|
||||
|
||||
export namespace debug {
|
||||
|
||||
/**
|
||||
|
||||
@@ -262,14 +262,6 @@ export class MainThreadDebugService implements MainThreadDebugServiceShape, IDeb
|
||||
return Promise.reject(new Error('debug session not found'));
|
||||
}
|
||||
|
||||
public $terminateDebugSession(sessionId: DebugSessionUUID): Promise<void> {
|
||||
const session = this.debugService.getModel().getSession(sessionId, true);
|
||||
if (session) {
|
||||
return session.terminate();
|
||||
}
|
||||
return Promise.reject(new Error('debug session not found'));
|
||||
}
|
||||
|
||||
public $stopDebugging(sessionId: DebugSessionUUID | undefined): Promise<void> {
|
||||
if (sessionId) {
|
||||
const session = this.debugService.getModel().getSession(sessionId, true);
|
||||
|
||||
@@ -269,6 +269,14 @@ export class MainThreadTextEditor {
|
||||
}
|
||||
}));
|
||||
|
||||
const isValidCodeEditor = () => {
|
||||
// Due to event timings, it is possible that there is a model change event not yet delivered to us.
|
||||
// > e.g. a model change event is emitted to a listener which then decides to update editor options
|
||||
// > In this case the editor configuration change event reaches us first.
|
||||
// So simply check that the model is still attached to this code editor
|
||||
return (this._codeEditor && this._codeEditor.getModel() === this._model);
|
||||
};
|
||||
|
||||
const updateProperties = (selectionChangeSource: string | null) => {
|
||||
// Some editor events get delivered faster than model content changes. This is
|
||||
// problematic, as this leads to editor properties reaching the extension host
|
||||
@@ -287,18 +295,30 @@ export class MainThreadTextEditor {
|
||||
|
||||
this._codeEditorListeners.add(this._codeEditor.onDidChangeCursorSelection((e) => {
|
||||
// selection
|
||||
if (!isValidCodeEditor()) {
|
||||
return;
|
||||
}
|
||||
updateProperties(e.source);
|
||||
}));
|
||||
this._codeEditorListeners.add(this._codeEditor.onDidChangeConfiguration(() => {
|
||||
this._codeEditorListeners.add(this._codeEditor.onDidChangeConfiguration((e) => {
|
||||
// options
|
||||
if (!isValidCodeEditor()) {
|
||||
return;
|
||||
}
|
||||
updateProperties(null);
|
||||
}));
|
||||
this._codeEditorListeners.add(this._codeEditor.onDidLayoutChange(() => {
|
||||
// visibleRanges
|
||||
if (!isValidCodeEditor()) {
|
||||
return;
|
||||
}
|
||||
updateProperties(null);
|
||||
}));
|
||||
this._codeEditorListeners.add(this._codeEditor.onDidScrollChange(() => {
|
||||
// visibleRanges
|
||||
if (!isValidCodeEditor()) {
|
||||
return;
|
||||
}
|
||||
updateProperties(null);
|
||||
}));
|
||||
this._updatePropertiesNow(null);
|
||||
|
||||
@@ -128,7 +128,7 @@ export class MainThreadExtensionService implements MainThreadExtensionServiceSha
|
||||
}
|
||||
}
|
||||
|
||||
$onExtensionHostExit(code: number): void {
|
||||
async $onExtensionHostExit(code: number): Promise<void> {
|
||||
this._extensionService._onExtensionHostExit(code);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -799,7 +799,7 @@ export interface MainThreadExtensionServiceShape extends IDisposable {
|
||||
$onDidActivateExtension(extensionId: ExtensionIdentifier, codeLoadingTime: number, activateCallTime: number, activateResolvedTime: number, activationReason: ExtensionActivationReason): void;
|
||||
$onExtensionActivationError(extensionId: ExtensionIdentifier, error: ExtensionActivationError): Promise<void>;
|
||||
$onExtensionRuntimeError(extensionId: ExtensionIdentifier, error: SerializedError): void;
|
||||
$onExtensionHostExit(code: number): void;
|
||||
$onExtensionHostExit(code: number): Promise<void>;
|
||||
}
|
||||
|
||||
export interface SCMProviderFeatures {
|
||||
@@ -882,7 +882,6 @@ export interface MainThreadDebugServiceShape extends IDisposable {
|
||||
$stopDebugging(sessionId: DebugSessionUUID | undefined): Promise<void>;
|
||||
$setDebugSessionName(id: DebugSessionUUID, name: string): void;
|
||||
$customDebugAdapterRequest(id: DebugSessionUUID, command: string, args: any): Promise<any>;
|
||||
$terminateDebugSession(id: DebugSessionUUID): Promise<void>;
|
||||
$appendDebugConsole(value: string): void;
|
||||
$startBreakpointEvents(): void;
|
||||
$registerBreakpoints(breakpoints: Array<ISourceMultiBreakpointDto | IFunctionBreakpointDto | IDataBreakpointDto>): Promise<void>;
|
||||
|
||||
@@ -957,10 +957,6 @@ export class ExtHostDebugSession implements vscode.DebugSession {
|
||||
public customRequest(command: string, args: any): Promise<any> {
|
||||
return this._debugServiceProxy.$customDebugAdapterRequest(this._id, command, args);
|
||||
}
|
||||
|
||||
public terminate(): Promise<void> {
|
||||
return this._debugServiceProxy.$terminateDebugSession(this._id);
|
||||
}
|
||||
}
|
||||
|
||||
export class ExtHostDebugConsole implements vscode.DebugConsole {
|
||||
|
||||
@@ -557,7 +557,7 @@ export abstract class AbstractExtHostExtensionService extends Disposable impleme
|
||||
}
|
||||
|
||||
// after tests have run, we shutdown the host
|
||||
this._gracefulExit(error || (typeof failures === 'number' && failures > 0) ? 1 /* ERROR */ : 0 /* OK */);
|
||||
this._testRunnerExit(error || (typeof failures === 'number' && failures > 0) ? 1 /* ERROR */ : 0 /* OK */);
|
||||
};
|
||||
|
||||
const runResult = testRunner!.run(extensionTestsPath, oldTestRunnerCallback);
|
||||
@@ -567,11 +567,11 @@ export abstract class AbstractExtHostExtensionService extends Disposable impleme
|
||||
runResult
|
||||
.then(() => {
|
||||
c();
|
||||
this._gracefulExit(0);
|
||||
this._testRunnerExit(0);
|
||||
})
|
||||
.catch((err: Error) => {
|
||||
e(err.toString());
|
||||
this._gracefulExit(1);
|
||||
this._testRunnerExit(1);
|
||||
});
|
||||
}
|
||||
});
|
||||
@@ -579,24 +579,20 @@ export abstract class AbstractExtHostExtensionService extends Disposable impleme
|
||||
|
||||
// Otherwise make sure to shutdown anyway even in case of an error
|
||||
else {
|
||||
this._gracefulExit(1 /* ERROR */);
|
||||
this._testRunnerExit(1 /* ERROR */);
|
||||
}
|
||||
|
||||
return Promise.reject(new Error(requireError ? requireError.toString() : nls.localize('extensionTestError', "Path {0} does not point to a valid extension test runner.", extensionTestsPath)));
|
||||
}
|
||||
|
||||
private _gracefulExit(code: number): void {
|
||||
// to give the PH process a chance to flush any outstanding console
|
||||
// messages to the main process, we delay the exit() by some time
|
||||
setTimeout(() => {
|
||||
// If extension tests are running, give the exit code to the renderer
|
||||
if (this._initData.remote.isRemote && !!this._initData.environment.extensionTestsLocationURI) {
|
||||
this._mainThreadExtensionsProxy.$onExtensionHostExit(code);
|
||||
return;
|
||||
}
|
||||
|
||||
private _testRunnerExit(code: number): void {
|
||||
// wait at most 5000ms for the renderer to confirm our exit request and for the renderer socket to drain
|
||||
// (this is to ensure all outstanding messages reach the renderer)
|
||||
const exitPromise = this._mainThreadExtensionsProxy.$onExtensionHostExit(code);
|
||||
const drainPromise = this._extHostContext.drain();
|
||||
Promise.race([Promise.all([exitPromise, drainPromise]), timeout(5000)]).then(() => {
|
||||
this._hostUtils.exit(code);
|
||||
}, 500);
|
||||
});
|
||||
}
|
||||
|
||||
private _startExtensionHost(): Promise<void> {
|
||||
|
||||
@@ -18,12 +18,12 @@ export class ExtHostRpcService implements IExtHostRpcService {
|
||||
readonly getProxy: <T>(identifier: ProxyIdentifier<T>) => T;
|
||||
readonly set: <T, R extends T> (identifier: ProxyIdentifier<T>, instance: R) => R;
|
||||
readonly assertRegistered: (identifiers: ProxyIdentifier<any>[]) => void;
|
||||
readonly drain: () => Promise<void>;
|
||||
|
||||
constructor(rpcProtocol: IRPCProtocol) {
|
||||
this.getProxy = rpcProtocol.getProxy.bind(rpcProtocol);
|
||||
this.set = rpcProtocol.set.bind(rpcProtocol);
|
||||
this.assertRegistered = rpcProtocol.assertRegistered.bind(rpcProtocol);
|
||||
|
||||
this.drain = rpcProtocol.drain.bind(rpcProtocol);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -51,7 +51,10 @@ export class ExtHostExtensionService extends AbstractExtHostExtensionService {
|
||||
|
||||
// fetch JS sources as text and create a new function around it
|
||||
const source = await response.text();
|
||||
const initFn = new Function('module', 'exports', 'require', `${source}\n//# sourceURL=${module.toString(true)}`);
|
||||
// Here we append #vscode-extension to serve as a marker, such that source maps
|
||||
// can be adjusted for the extra wrapping function.
|
||||
const sourceURL = `${module.toString(true)}#vscode-extension`;
|
||||
const initFn = new Function('module', 'exports', 'require', `${source}\n//# sourceURL=${sourceURL}`);
|
||||
|
||||
// define commonjs globals: `module`, `exports`, and `require`
|
||||
const _exports = {};
|
||||
|
||||
@@ -33,6 +33,7 @@ import { ContextSubMenu } from 'vs/base/browser/contextmenu';
|
||||
import { IAuthenticationService } from 'vs/workbench/services/authentication/browser/authenticationService';
|
||||
import { AuthenticationSession } from 'vs/editor/common/modes';
|
||||
import { IWorkbenchEnvironmentService } from 'vs/workbench/services/environment/common/environmentService';
|
||||
import { IStorageService, StorageScope } from 'vs/platform/storage/common/storage';
|
||||
|
||||
export class ViewContainerActivityAction extends ActivityAction {
|
||||
|
||||
@@ -98,6 +99,8 @@ export class ViewContainerActivityAction extends ActivityAction {
|
||||
}
|
||||
}
|
||||
|
||||
export const ACCOUNTS_VISIBILITY_PREFERENCE_KEY = 'workbench.activity.showAccounts';
|
||||
|
||||
export class AccountsActionViewItem extends ActivityActionViewItem {
|
||||
constructor(
|
||||
action: ActivityAction,
|
||||
@@ -107,7 +110,8 @@ export class AccountsActionViewItem extends ActivityActionViewItem {
|
||||
@IMenuService protected menuService: IMenuService,
|
||||
@IContextKeyService private readonly contextKeyService: IContextKeyService,
|
||||
@IAuthenticationService private readonly authenticationService: IAuthenticationService,
|
||||
@IWorkbenchEnvironmentService private readonly environmentService: IWorkbenchEnvironmentService
|
||||
@IWorkbenchEnvironmentService private readonly environmentService: IWorkbenchEnvironmentService,
|
||||
@IStorageService private readonly storageService: IStorageService
|
||||
) {
|
||||
super(action, { draggable: false, colors, icon: true }, themeService);
|
||||
}
|
||||
@@ -190,6 +194,15 @@ export class AccountsActionViewItem extends ActivityActionViewItem {
|
||||
}
|
||||
});
|
||||
|
||||
if (menus.length) {
|
||||
menus.push(new Separator());
|
||||
}
|
||||
|
||||
menus.push(new Action('hide', nls.localize('hide', "Hide"), undefined, true, _ => {
|
||||
this.storageService.store(ACCOUNTS_VISIBILITY_PREFERENCE_KEY, false, StorageScope.GLOBAL);
|
||||
return Promise.resolve();
|
||||
}));
|
||||
|
||||
return menus;
|
||||
}
|
||||
|
||||
|
||||
@@ -5,11 +5,10 @@
|
||||
|
||||
import 'vs/css!./media/activitybarpart';
|
||||
import * as nls from 'vs/nls';
|
||||
import { ActionsOrientation, ActionBar } from 'vs/base/browser/ui/actionbar/actionbar';
|
||||
import { ActionsOrientation, ActionBar, Separator } from 'vs/base/browser/ui/actionbar/actionbar';
|
||||
import { GLOBAL_ACTIVITY_ID, IActivity, ACCOUNTS_ACTIIVTY_ID } from 'vs/workbench/common/activity';
|
||||
import { Part } from 'vs/workbench/browser/part';
|
||||
import { GlobalActivityActionViewItem, ViewContainerActivityAction, PlaceHolderToggleCompositePinnedAction, PlaceHolderViewContainerActivityAction, HomeAction, HomeActionViewItem } from 'vs/workbench/browser/parts/activitybar/activitybarActions';
|
||||
import { AccountsActionViewItem } from 'sql/workbench/browser/parts/activitybar/activitybarActions'; // {{ SQL CARBON EDIT }} - use the ADS account management action
|
||||
import { GlobalActivityActionViewItem, ViewContainerActivityAction, PlaceHolderToggleCompositePinnedAction, PlaceHolderViewContainerActivityAction, HomeAction, HomeActionViewItem, ACCOUNTS_VISIBILITY_PREFERENCE_KEY } from 'vs/workbench/browser/parts/activitybar/activitybarActions';
|
||||
import { IBadge, NumberBadge } from 'vs/workbench/services/activity/common/activity';
|
||||
import { IWorkbenchLayoutService, Parts } from 'vs/workbench/services/layout/browser/layoutService';
|
||||
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
|
||||
@@ -43,6 +42,8 @@ import { Event } from 'vs/base/common/event';
|
||||
import { StandardKeyboardEvent } from 'vs/base/browser/keyboardEvent';
|
||||
import { KeyCode } from 'vs/base/common/keyCodes';
|
||||
|
||||
import { AccountsActionViewItem } from 'sql/workbench/browser/parts/activitybar/activitybarActions'; // {{ SQL CARBON EDIT }} - use the ADS account management action
|
||||
|
||||
interface IPlaceholderViewContainer {
|
||||
id: string;
|
||||
name?: string;
|
||||
@@ -76,7 +77,7 @@ export class ActivitybarPart extends Part implements IActivityBarService {
|
||||
static readonly PINNED_VIEW_CONTAINERS = 'workbench.activity.pinnedViewlets2';
|
||||
private static readonly PLACEHOLDER_VIEW_CONTAINERS = 'workbench.activity.placeholderViewlets';
|
||||
private static readonly HOME_BAR_VISIBILITY_PREFERENCE = 'workbench.activity.showHomeIndicator';
|
||||
|
||||
private static readonly ACCOUNTS_ACTION_INDEX = 0;
|
||||
//#region IView
|
||||
|
||||
readonly minimumWidth: number = 48;
|
||||
@@ -165,6 +166,18 @@ export class ActivitybarPart extends Part implements IActivityBarService {
|
||||
actions.push(this.instantiationService.createInstance(ToggleMenuBarAction, ToggleMenuBarAction.ID, menuBarVisibility === 'compact' ? nls.localize('hideMenu', "Hide Menu") : nls.localize('showMenu', "Show Menu")));
|
||||
}
|
||||
|
||||
const toggleAccountsVisibilityAction = new Action(
|
||||
'toggleAccountsVisibility',
|
||||
nls.localize('accounts', "Accounts"),
|
||||
undefined,
|
||||
true,
|
||||
async () => { this.accountsVisibilityPreference = !this.accountsVisibilityPreference; }
|
||||
);
|
||||
|
||||
toggleAccountsVisibilityAction.checked = !!this.accountsActivityAction;
|
||||
actions.push(toggleAccountsVisibilityAction);
|
||||
actions.push(new Separator());
|
||||
|
||||
actions.push(new Action(
|
||||
ToggleActivityBarVisibilityAction.ID,
|
||||
nls.localize('hideActivitBar', "Hide Activity Bar"),
|
||||
@@ -588,17 +601,35 @@ export class ActivitybarPart extends Part implements IActivityBarService {
|
||||
cssClass: Codicon.settingsGear.classNames
|
||||
});
|
||||
|
||||
this.accountsActivityAction = new ActivityAction({
|
||||
id: 'workbench.actions.accounts',
|
||||
name: nls.localize('accounts', "Accounts"),
|
||||
cssClass: Codicon.account.classNames
|
||||
});
|
||||
if (this.accountsVisibilityPreference) {
|
||||
this.accountsActivityAction = new ActivityAction({
|
||||
id: 'workbench.actions.accounts',
|
||||
name: nls.localize('accounts', "Accounts"),
|
||||
cssClass: Codicon.account.classNames
|
||||
});
|
||||
|
||||
this.globalActivityActionBar.push(this.accountsActivityAction);
|
||||
this.globalActivityActionBar.push(this.accountsActivityAction, { index: ActivitybarPart.ACCOUNTS_ACTION_INDEX });
|
||||
}
|
||||
|
||||
this.globalActivityActionBar.push(this.globalActivityAction);
|
||||
}
|
||||
|
||||
private toggleAccountsActivity() {
|
||||
if (this.globalActivityActionBar) {
|
||||
if (this.accountsActivityAction) {
|
||||
this.globalActivityActionBar.pull(ActivitybarPart.ACCOUNTS_ACTION_INDEX);
|
||||
this.accountsActivityAction = undefined;
|
||||
} else {
|
||||
this.accountsActivityAction = new ActivityAction({
|
||||
id: 'workbench.actions.accounts',
|
||||
name: nls.localize('accounts', "Accounts"),
|
||||
cssClass: Codicon.account.classNames
|
||||
});
|
||||
this.globalActivityActionBar.push(this.accountsActivityAction, { index: ActivitybarPart.ACCOUNTS_ACTION_INDEX });
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private getCompositeActions(compositeId: string): { activityAction: ViewContainerActivityAction, pinnedAction: ToggleCompositePinnedAction } {
|
||||
let compositeActions = this.compositeActions.get(compositeId);
|
||||
if (!compositeActions) {
|
||||
@@ -828,6 +859,10 @@ export class ActivitybarPart extends Part implements IActivityBarService {
|
||||
if (e.key === ActivitybarPart.HOME_BAR_VISIBILITY_PREFERENCE && e.scope === StorageScope.GLOBAL) {
|
||||
this.onDidChangeHomeBarVisibility();
|
||||
}
|
||||
|
||||
if (e.key === ACCOUNTS_VISIBILITY_PREFERENCE_KEY && e.scope === StorageScope.GLOBAL) {
|
||||
this.toggleAccountsActivity();
|
||||
}
|
||||
}
|
||||
|
||||
private saveCachedViewContainers(): void {
|
||||
@@ -965,6 +1000,14 @@ export class ActivitybarPart extends Part implements IActivityBarService {
|
||||
this.storageService.store(ActivitybarPart.HOME_BAR_VISIBILITY_PREFERENCE, value, StorageScope.GLOBAL);
|
||||
}
|
||||
|
||||
private get accountsVisibilityPreference(): boolean {
|
||||
return this.storageService.getBoolean(ACCOUNTS_VISIBILITY_PREFERENCE_KEY, StorageScope.GLOBAL, true);
|
||||
}
|
||||
|
||||
private set accountsVisibilityPreference(value: boolean) {
|
||||
this.storageService.store(ACCOUNTS_VISIBILITY_PREFERENCE_KEY, value, StorageScope.GLOBAL);
|
||||
}
|
||||
|
||||
private migrateFromOldCachedViewContainersValue(): void {
|
||||
const value = this.storageService.get('workbench.activity.pinnedViewlets', StorageScope.GLOBAL);
|
||||
if (value !== undefined) {
|
||||
|
||||
@@ -68,18 +68,18 @@ export abstract class Viewlet extends PaneComposite implements IViewlet {
|
||||
}
|
||||
|
||||
getSecondaryActions(): IAction[] {
|
||||
const viewSecondaryActions = this.viewPaneContainer.getViewsVisibilityActions();
|
||||
const viewVisibilityActions = this.viewPaneContainer.getViewsVisibilityActions();
|
||||
const secondaryActions = this.viewPaneContainer.getSecondaryActions();
|
||||
if (viewSecondaryActions.length <= 1) {
|
||||
if (viewVisibilityActions.length <= 1 || viewVisibilityActions.every(({ enabled }) => !enabled)) {
|
||||
return secondaryActions;
|
||||
}
|
||||
|
||||
if (secondaryActions.length === 0) {
|
||||
return viewSecondaryActions;
|
||||
return viewVisibilityActions;
|
||||
}
|
||||
|
||||
return [
|
||||
new ContextSubMenu(nls.localize('views', "Views"), viewSecondaryActions),
|
||||
new ContextSubMenu(nls.localize('views', "Views"), viewVisibilityActions),
|
||||
new Separator(),
|
||||
...secondaryActions
|
||||
];
|
||||
|
||||
@@ -689,7 +689,7 @@ export class Breakpoint extends BaseBreakpoint implements IBreakpoint {
|
||||
|
||||
toJSON(): any {
|
||||
const result = super.toJSON();
|
||||
result.uri = this.uri;
|
||||
result.uri = this._uri;
|
||||
result.lineNumber = this._lineNumber;
|
||||
result.column = this._column;
|
||||
result.adapterData = this.adapterData;
|
||||
|
||||
@@ -1775,6 +1775,29 @@ export class ShowPopularExtensionsAction extends Action {
|
||||
}
|
||||
}
|
||||
|
||||
export class RecentlyPublishedExtensionsAction extends Action {
|
||||
|
||||
static readonly ID = 'workbench.extensions.action.recentlyPublishedExtensions';
|
||||
static readonly LABEL = localize('recentlyPublishedExtensions', "Recently Published Extensions");
|
||||
|
||||
constructor(
|
||||
id: string,
|
||||
label: string,
|
||||
@IViewletService private readonly viewletService: IViewletService
|
||||
) {
|
||||
super(id, label, undefined, true);
|
||||
}
|
||||
|
||||
run(): Promise<void> {
|
||||
return this.viewletService.openViewlet(VIEWLET_ID, true)
|
||||
.then(viewlet => viewlet?.getViewPaneContainer() as IExtensionsViewPaneContainer)
|
||||
.then(viewlet => {
|
||||
viewlet.search('@sort:publishedDate ');
|
||||
viewlet.focus();
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
export class ShowRecommendedExtensionsAction extends Action {
|
||||
|
||||
static readonly ID = 'workbench.extensions.action.showRecommendedExtensions';
|
||||
@@ -2050,6 +2073,27 @@ export class ShowAzureExtensionsAction extends Action {
|
||||
}
|
||||
}
|
||||
|
||||
export class SearchCategoryAction extends Action {
|
||||
|
||||
constructor(
|
||||
id: string,
|
||||
label: string,
|
||||
private readonly category: string,
|
||||
@IViewletService private readonly viewletService: IViewletService
|
||||
) {
|
||||
super(id, label, undefined, true);
|
||||
}
|
||||
|
||||
run(): Promise<void> {
|
||||
return this.viewletService.openViewlet(VIEWLET_ID, true)
|
||||
.then(viewlet => viewlet?.getViewPaneContainer() as IExtensionsViewPaneContainer)
|
||||
.then(viewlet => {
|
||||
viewlet.search(`@category:"${this.category.toLowerCase()}"`);
|
||||
viewlet.focus();
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
export class ChangeSortAction extends Action {
|
||||
|
||||
private query: Query;
|
||||
|
||||
@@ -11,23 +11,23 @@ import { IWorkbenchContribution } from 'vs/workbench/common/contributions';
|
||||
import { Disposable, MutableDisposable } from 'vs/base/common/lifecycle';
|
||||
import { Event as EventOf, Emitter } from 'vs/base/common/event';
|
||||
import { IAction, Action } from 'vs/base/common/actions';
|
||||
import { Separator } from 'vs/base/browser/ui/actionbar/actionbar';
|
||||
import { Separator, IActionViewItem } from 'vs/base/browser/ui/actionbar/actionbar';
|
||||
import { IViewlet } from 'vs/workbench/common/viewlet';
|
||||
import { IViewletService } from 'vs/workbench/services/viewlet/browser/viewlet';
|
||||
import { append, $, addClass, toggleClass, Dimension, hide, show } from 'vs/base/browser/dom';
|
||||
import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry';
|
||||
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
|
||||
import { IExtensionService } from 'vs/workbench/services/extensions/common/extensions';
|
||||
import { IExtensionsWorkbenchService, IExtensionsViewPaneContainer, VIEWLET_ID, AutoUpdateConfigurationKey, ShowRecommendationsOnlyOnDemandKey, CloseExtensionDetailsOnViewChangeKey } from '../common/extensions';
|
||||
import { IExtensionsWorkbenchService, IExtensionsViewPaneContainer, VIEWLET_ID, AutoUpdateConfigurationKey, CloseExtensionDetailsOnViewChangeKey } from '../common/extensions';
|
||||
import {
|
||||
ShowEnabledExtensionsAction, ShowInstalledExtensionsAction, ShowRecommendedExtensionsAction, /*ShowPopularExtensionsAction,*/ ShowDisabledExtensionsAction,
|
||||
ShowOutdatedExtensionsAction, ClearExtensionsInputAction, ChangeSortAction, UpdateAllAction, CheckForUpdatesAction, DisableAllAction, EnableAllAction,
|
||||
EnableAutoUpdateAction, DisableAutoUpdateAction, ShowBuiltInExtensionsAction, InstallVSIXAction
|
||||
ShowRecommendedExtensionsAction, /*ShowPopularExtensionsAction,*/
|
||||
ClearExtensionsInputAction, ChangeSortAction, UpdateAllAction, CheckForUpdatesAction, DisableAllAction, EnableAllAction,
|
||||
EnableAutoUpdateAction, DisableAutoUpdateAction, ShowBuiltInExtensionsAction, InstallVSIXAction, SearchCategoryAction, /*RecentlyPublishedExtensionsAction, */ShowInstalledExtensionsAction, ShowOutdatedExtensionsAction, ShowDisabledExtensionsAction, ShowEnabledExtensionsAction
|
||||
} from 'vs/workbench/contrib/extensions/browser/extensionsActions';
|
||||
import { IExtensionManagementService } from 'vs/platform/extensionManagement/common/extensionManagement';
|
||||
import { IWorkbenchExtensionEnablementService, IExtensionManagementServerService, IExtensionManagementServer } from 'vs/workbench/services/extensionManagement/common/extensionManagement';
|
||||
import { ExtensionsInput } from 'vs/workbench/contrib/extensions/common/extensionsInput';
|
||||
import { ExtensionsListView, EnabledExtensionsView, DisabledExtensionsView, RecommendedExtensionsView, WorkspaceRecommendedExtensionsView, BuiltInExtensionsView, BuiltInThemesExtensionsView, BuiltInBasicsExtensionsView, ServerExtensionsView, DefaultRecommendedExtensionsView } from 'vs/workbench/contrib/extensions/browser/extensionsViews';
|
||||
import { ExtensionsListView, EnabledExtensionsView, DisabledExtensionsView, RecommendedExtensionsView, WorkspaceRecommendedExtensionsView, BuiltInFeatureExtensionsView, BuiltInThemesExtensionsView, BuiltInProgrammingLanguageExtensionsView, ServerExtensionsView, DefaultRecommendedExtensionsView, OutdatedExtensionsView, InstalledExtensionsView, SearchBuiltInExtensionsView } from 'vs/workbench/contrib/extensions/browser/extensionsViews';
|
||||
import { IProgressService, ProgressLocation } from 'vs/platform/progress/common/progress';
|
||||
import { IEditorGroupsService } from 'vs/workbench/services/editor/common/editorGroupsService';
|
||||
import Severity from 'vs/base/common/severity';
|
||||
@@ -50,9 +50,8 @@ import { SuggestEnabledInput, attachSuggestEnabledInputBoxStyler } from 'vs/work
|
||||
import { alert } from 'vs/base/browser/ui/aria/aria';
|
||||
import { createErrorWithActions } from 'vs/base/common/errorsWithActions';
|
||||
import { IEnvironmentService } from 'vs/platform/environment/common/environment';
|
||||
import { ExtensionType } from 'vs/platform/extensions/common/extensions';
|
||||
import { ExtensionType, EXTENSION_CATEGORIES } from 'vs/platform/extensions/common/extensions';
|
||||
import { Registry } from 'vs/platform/registry/common/platform';
|
||||
import { RemoteNameContext } from 'vs/workbench/browser/contextkeys';
|
||||
import { ILabelService } from 'vs/platform/label/common/label';
|
||||
import { MementoObject } from 'vs/workbench/common/memento';
|
||||
import { SyncDescriptor } from 'vs/platform/instantiation/common/descriptors';
|
||||
@@ -60,6 +59,8 @@ import { IPreferencesService } from 'vs/workbench/services/preferences/common/pr
|
||||
import { DragAndDropObserver } from 'vs/workbench/browser/dnd';
|
||||
import { URI } from 'vs/base/common/uri';
|
||||
import { SIDE_BAR_DRAG_AND_DROP_BACKGROUND } from 'vs/workbench/common/theme';
|
||||
import { ContextSubMenu } from 'vs/base/browser/contextmenu';
|
||||
import { DropdownMenuActionViewItem } from 'vs/base/browser/ui/dropdown/dropdown';
|
||||
|
||||
const NonEmptyWorkspaceContext = new RawContextKey<boolean>('nonEmptyWorkspace', false);
|
||||
const DefaultViewsContext = new RawContextKey<boolean>('defaultExtensionViews', true);
|
||||
@@ -69,25 +70,9 @@ const SearchOutdatedExtensionsContext = new RawContextKey<boolean>('searchOutdat
|
||||
const SearchEnabledExtensionsContext = new RawContextKey<boolean>('searchEnabledExtensions', false);
|
||||
const SearchDisabledExtensionsContext = new RawContextKey<boolean>('searchDisabledExtensions', false);
|
||||
const HasInstalledExtensionsContext = new RawContextKey<boolean>('hasInstalledExtensions', true);
|
||||
const BuiltInExtensionsContext = new RawContextKey<boolean>('builtInExtensions', false);
|
||||
const SearchBuiltInExtensionsContext = new RawContextKey<boolean>('searchBuiltInExtensions', false);
|
||||
const RecommendedExtensionsContext = new RawContextKey<boolean>('recommendedExtensions', false);
|
||||
const DefaultRecommendedExtensionsContext = new RawContextKey<boolean>('defaultRecommendedExtensions', false);
|
||||
const viewIdNameMappings: { [id: string]: string } = {
|
||||
'extensions.listView': localize('marketPlace', "Marketplace"),
|
||||
'extensions.enabledExtensionList': localize('enabledExtensions', "Enabled"),
|
||||
'extensions.enabledExtensionList2': localize('enabledExtensions', "Enabled"),
|
||||
'extensions.disabledExtensionList': localize('disabledExtensions', "Disabled"),
|
||||
'extensions.disabledExtensionList2': localize('disabledExtensions', "Disabled"),
|
||||
// {{SQL CARBON EDIT}}
|
||||
// 'extensions.popularExtensionsList': localize('popularExtensions', "Popular"),
|
||||
'extensions.recommendedList': localize('recommendedExtensions', "Recommended"),
|
||||
'extensions.otherrecommendedList': localize('otherRecommendedExtensions', "Other Recommendations"),
|
||||
'extensions.workspaceRecommendedList': localize('workspaceRecommendedExtensions', "Workspace Recommendations"),
|
||||
'extensions.builtInExtensionsList': localize('builtInExtensions', "Features"),
|
||||
'extensions.builtInThemesExtensionsList': localize('builtInThemesExtensions', "Themes"),
|
||||
'extensions.builtInBasicsExtensionsList': localize('builtInBasicsExtensions', "Programming Languages"),
|
||||
'extensions.syncedExtensionsList': localize('syncedExtensions', "My Account"),
|
||||
};
|
||||
|
||||
export class ExtensionsViewletViewsContribution implements IWorkbenchContribution {
|
||||
|
||||
@@ -103,223 +88,233 @@ export class ExtensionsViewletViewsContribution implements IWorkbenchContributio
|
||||
}
|
||||
|
||||
private registerViews(): void {
|
||||
let viewDescriptors: IViewDescriptor[] = [];
|
||||
viewDescriptors.push(this.createMarketPlaceExtensionsListViewDescriptor());
|
||||
viewDescriptors.push(this.createDefaultEnabledExtensionsListViewDescriptor());
|
||||
viewDescriptors.push(this.createDefaultDisabledExtensionsListViewDescriptor());
|
||||
// {{SQL CARBON EDIT}}
|
||||
// viewDescriptors.push(this.createDefaultPopularExtensionsListViewDescriptor());
|
||||
viewDescriptors.push(this.createEnabledExtensionsListViewDescriptor());
|
||||
viewDescriptors.push(this.createDisabledExtensionsListViewDescriptor());
|
||||
viewDescriptors.push(this.createBuiltInExtensionsListViewDescriptor());
|
||||
viewDescriptors.push(this.createBuiltInBasicsExtensionsListViewDescriptor());
|
||||
viewDescriptors.push(this.createBuiltInThemesExtensionsListViewDescriptor());
|
||||
viewDescriptors.push(this.createDefaultRecommendedExtensionsListViewDescriptor());
|
||||
viewDescriptors.push(this.createOtherRecommendedExtensionsListViewDescriptor());
|
||||
viewDescriptors.push(this.createWorkspaceRecommendedExtensionsListViewDescriptor());
|
||||
const viewDescriptors: IViewDescriptor[] = [];
|
||||
|
||||
if (this.extensionManagementServerService.localExtensionManagementServer) {
|
||||
viewDescriptors.push(...this.createExtensionsViewDescriptorsForServer(this.extensionManagementServerService.localExtensionManagementServer));
|
||||
}
|
||||
if (this.extensionManagementServerService.remoteExtensionManagementServer) {
|
||||
viewDescriptors.push(...this.createExtensionsViewDescriptorsForServer(this.extensionManagementServerService.remoteExtensionManagementServer));
|
||||
}
|
||||
/* Default views */
|
||||
viewDescriptors.push(...this.createDefaultExtensionsViewDescriptors());
|
||||
|
||||
/* Search views */
|
||||
viewDescriptors.push(...this.createSearchExtensionsViewDescriptors());
|
||||
|
||||
/* Recommendations views */
|
||||
viewDescriptors.push(...this.createRecommendedExtensionsViewDescriptors());
|
||||
|
||||
/* Built-in extensions views */
|
||||
viewDescriptors.push(...this.createBuiltinExtensionsViewDescriptors());
|
||||
|
||||
Registry.as<IViewsRegistry>(Extensions.ViewsRegistry).registerViews(viewDescriptors, this.container);
|
||||
}
|
||||
|
||||
// View used for any kind of searching
|
||||
private createMarketPlaceExtensionsListViewDescriptor(): IViewDescriptor {
|
||||
const id = 'extensions.listView';
|
||||
return {
|
||||
id,
|
||||
name: viewIdNameMappings[id],
|
||||
private createDefaultExtensionsViewDescriptors(): IViewDescriptor[] {
|
||||
const viewDescriptors: IViewDescriptor[] = [];
|
||||
|
||||
/*
|
||||
* Default popular extensions view
|
||||
* Separate view for popular extensions required as we need to show popular and recommended sections
|
||||
* in the default view when there is no search text, and user has no installed extensions.
|
||||
*/
|
||||
// viewDescriptors.push({ {{SQL CARBON EDIT}} remove popular
|
||||
// id: 'workbench.views.extensions.popular',
|
||||
// name: localize('popularExtensions', "Popular"),
|
||||
// ctorDescriptor: new SyncDescriptor(ExtensionsListView),
|
||||
// when: ContextKeyExpr.and(ContextKeyExpr.has('defaultExtensionViews'), ContextKeyExpr.not('hasInstalledExtensions')),
|
||||
// weight: 60,
|
||||
// order: 1,
|
||||
// });
|
||||
|
||||
/*
|
||||
* Default installed extensions views - Shows all user installed extensions.
|
||||
*/
|
||||
const servers: IExtensionManagementServer[] = [];
|
||||
if (this.extensionManagementServerService.localExtensionManagementServer) {
|
||||
servers.push(this.extensionManagementServerService.localExtensionManagementServer);
|
||||
}
|
||||
if (this.extensionManagementServerService.remoteExtensionManagementServer) {
|
||||
servers.push(this.extensionManagementServerService.remoteExtensionManagementServer);
|
||||
}
|
||||
const getViewName = (viewTitle: string, server: IExtensionManagementServer): string => {
|
||||
return servers.length > 1 ? `${server.label} - ${viewTitle}` : viewTitle;
|
||||
};
|
||||
for (const server of servers) {
|
||||
const getInstalledViewName = (): string => getViewName(localize('installed', "Installed"), server);
|
||||
const onDidChangeServerLabel: EventOf<void> = EventOf.map(this.labelService.onDidChangeFormatters, () => undefined);
|
||||
viewDescriptors.push({
|
||||
id: servers.length > 1 ? `workbench.views.extensions.${server.id}.installed` : `workbench.views.extensions.installed`,
|
||||
get name() { return getInstalledViewName(); },
|
||||
ctorDescriptor: new SyncDescriptor(ServerExtensionsView, [server, EventOf.map<void, string>(onDidChangeServerLabel, () => getInstalledViewName())]),
|
||||
when: ContextKeyExpr.and(ContextKeyExpr.has('defaultExtensionViews'), ContextKeyExpr.has('hasInstalledExtensions')),
|
||||
weight: 100,
|
||||
order: 2,
|
||||
/* Installed extensions views shall not be hidden when there are more than one server */
|
||||
canToggleVisibility: servers.length === 1
|
||||
});
|
||||
}
|
||||
|
||||
/*
|
||||
* Default recommended extensions view
|
||||
* When user has installed extensions, this is shown along with the views for enabled & disabled extensions
|
||||
* When user has no installed extensions, this is shown along with the view for popular extensions
|
||||
*/
|
||||
viewDescriptors.push({
|
||||
id: 'extensions.recommendedList',
|
||||
name: localize('recommendedExtensions', "Recommended"),
|
||||
ctorDescriptor: new SyncDescriptor(DefaultRecommendedExtensionsView),
|
||||
when: ContextKeyExpr.and(ContextKeyExpr.has('defaultExtensionViews'), ContextKeyExpr.not('config.extensions.showRecommendationsOnlyOnDemand')),
|
||||
weight: 40,
|
||||
order: 3,
|
||||
canToggleVisibility: true
|
||||
});
|
||||
|
||||
/* Installed views shall be default in multi server window */
|
||||
if (servers.length === 1) {
|
||||
/*
|
||||
* Default enabled extensions view - Shows all user installed enabled extensions.
|
||||
* Hidden by default
|
||||
*/
|
||||
viewDescriptors.push({
|
||||
id: 'workbench.views.extensions.enabled',
|
||||
name: localize('enabledExtensions', "Enabled"),
|
||||
ctorDescriptor: new SyncDescriptor(EnabledExtensionsView),
|
||||
when: ContextKeyExpr.and(ContextKeyExpr.has('defaultExtensionViews'), ContextKeyExpr.has('hasInstalledExtensions')),
|
||||
hideByDefault: true,
|
||||
weight: 40,
|
||||
order: 4,
|
||||
canToggleVisibility: true
|
||||
});
|
||||
|
||||
/*
|
||||
* Default disabled extensions view - Shows all disabled extensions.
|
||||
* Hidden by default
|
||||
*/
|
||||
viewDescriptors.push({
|
||||
id: 'workbench.views.extensions.disabled',
|
||||
name: localize('disabledExtensions', "Disabled"),
|
||||
ctorDescriptor: new SyncDescriptor(DisabledExtensionsView),
|
||||
when: ContextKeyExpr.and(ContextKeyExpr.has('defaultExtensionViews'), ContextKeyExpr.has('hasInstalledExtensions')),
|
||||
hideByDefault: true,
|
||||
weight: 10,
|
||||
order: 5,
|
||||
canToggleVisibility: true
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
return viewDescriptors;
|
||||
}
|
||||
|
||||
private createSearchExtensionsViewDescriptors(): IViewDescriptor[] {
|
||||
const viewDescriptors: IViewDescriptor[] = [];
|
||||
|
||||
/*
|
||||
* View used for searching Marketplace
|
||||
*/
|
||||
viewDescriptors.push({
|
||||
id: 'workbench.views.extensions.marketplace',
|
||||
name: localize('marketPlace', "Marketplace"),
|
||||
ctorDescriptor: new SyncDescriptor(ExtensionsListView),
|
||||
when: ContextKeyExpr.and(ContextKeyExpr.has('searchMarketplaceExtensions')),
|
||||
weight: 100
|
||||
};
|
||||
}
|
||||
});
|
||||
|
||||
// Separate view for enabled extensions required as we need to show enabled, disabled and recommended sections
|
||||
// in the default view when there is no search text, but user has installed extensions.
|
||||
private createDefaultEnabledExtensionsListViewDescriptor(): IViewDescriptor {
|
||||
const id = 'extensions.enabledExtensionList';
|
||||
return {
|
||||
id,
|
||||
name: viewIdNameMappings[id],
|
||||
ctorDescriptor: new SyncDescriptor(EnabledExtensionsView),
|
||||
when: ContextKeyExpr.and(ContextKeyExpr.has('defaultExtensionViews'), ContextKeyExpr.has('hasInstalledExtensions'), RemoteNameContext.isEqualTo('')),
|
||||
weight: 40,
|
||||
canToggleVisibility: true,
|
||||
order: 1
|
||||
};
|
||||
}
|
||||
|
||||
// Separate view for disabled extensions required as we need to show enabled, disabled and recommended sections
|
||||
// in the default view when there is no search text, but user has installed extensions.
|
||||
private createDefaultDisabledExtensionsListViewDescriptor(): IViewDescriptor {
|
||||
const id = 'extensions.disabledExtensionList';
|
||||
return {
|
||||
id,
|
||||
name: viewIdNameMappings[id],
|
||||
ctorDescriptor: new SyncDescriptor(DisabledExtensionsView),
|
||||
when: ContextKeyExpr.and(ContextKeyExpr.has('defaultExtensionViews'), ContextKeyExpr.has('hasInstalledExtensions'), RemoteNameContext.isEqualTo('')),
|
||||
weight: 10,
|
||||
canToggleVisibility: true,
|
||||
order: 3,
|
||||
collapsed: true
|
||||
};
|
||||
}
|
||||
|
||||
/* // {{SQL CARBON EDIT}}
|
||||
// Separate view for popular extensions required as we need to show popular and recommended sections
|
||||
// in the default view when there is no search text, and user has no installed extensions.
|
||||
private createDefaultPopularExtensionsListViewDescriptor(): IViewDescriptor {
|
||||
const id = 'extensions.popularExtensionsList';
|
||||
return {
|
||||
id,
|
||||
name: viewIdNameMappings[id],
|
||||
ctorDescriptor: new SyncDescriptor(ExtensionsListView),
|
||||
when: ContextKeyExpr.and(ContextKeyExpr.has('defaultExtensionViews'), ContextKeyExpr.not('hasInstalledExtensions')),
|
||||
weight: 60,
|
||||
order: 1
|
||||
};
|
||||
}
|
||||
*/
|
||||
|
||||
private createExtensionsViewDescriptorsForServer(server: IExtensionManagementServer): IViewDescriptor[] {
|
||||
const getViewName = (viewTitle: string, server: IExtensionManagementServer): string => {
|
||||
const serverLabel = server.label;
|
||||
if (viewTitle && this.extensionManagementServerService.localExtensionManagementServer && this.extensionManagementServerService.remoteExtensionManagementServer) {
|
||||
return `${serverLabel} - ${viewTitle}`;
|
||||
}
|
||||
return viewTitle ? viewTitle : serverLabel;
|
||||
};
|
||||
const getInstalledViewName = (): string => getViewName(localize('installed', "Installed"), server);
|
||||
const getOutdatedViewName = (): string => getViewName(localize('outdated', "Outdated"), server);
|
||||
const onDidChangeServerLabel: EventOf<void> = EventOf.map(this.labelService.onDidChangeFormatters, () => undefined);
|
||||
return [{
|
||||
id: `extensions.${server.id}.installed`,
|
||||
get name() { return getInstalledViewName(); },
|
||||
ctorDescriptor: new SyncDescriptor(ServerExtensionsView, [server, EventOf.map<void, string>(onDidChangeServerLabel, () => getInstalledViewName())]),
|
||||
/*
|
||||
* View used for searching all installed extensions
|
||||
*/
|
||||
viewDescriptors.push({
|
||||
id: 'workbench.views.extensions.searchInstalled',
|
||||
name: localize('installed', "Installed"),
|
||||
ctorDescriptor: new SyncDescriptor(InstalledExtensionsView),
|
||||
when: ContextKeyExpr.and(ContextKeyExpr.has('searchInstalledExtensions')),
|
||||
weight: 100
|
||||
}, {
|
||||
id: `extensions.${server.id}.outdated`,
|
||||
get name() { return getOutdatedViewName(); },
|
||||
ctorDescriptor: new SyncDescriptor(ServerExtensionsView, [server, EventOf.map<void, string>(onDidChangeServerLabel, () => getOutdatedViewName())]),
|
||||
when: ContextKeyExpr.and(ContextKeyExpr.has('searchOutdatedExtensions')),
|
||||
weight: 100
|
||||
}, {
|
||||
id: `extensions.${server.id}.default`,
|
||||
get name() { return getInstalledViewName(); },
|
||||
ctorDescriptor: new SyncDescriptor(ServerExtensionsView, [server, EventOf.map<void, string>(onDidChangeServerLabel, () => getInstalledViewName())]),
|
||||
when: ContextKeyExpr.and(ContextKeyExpr.has('defaultExtensionViews'), ContextKeyExpr.has('hasInstalledExtensions'), RemoteNameContext.notEqualsTo('')),
|
||||
weight: 40,
|
||||
order: 1
|
||||
}];
|
||||
}
|
||||
});
|
||||
|
||||
// Separate view for recommended extensions required as we need to show it along with other views when there is no search text.
|
||||
// When user has installed extensions, this is shown along with the views for enabled & disabled extensions
|
||||
// When user has no installed extensions, this is shown along with the view for popular extensions
|
||||
private createDefaultRecommendedExtensionsListViewDescriptor(): IViewDescriptor {
|
||||
const id = 'extensions.recommendedList';
|
||||
return {
|
||||
id,
|
||||
name: viewIdNameMappings[id],
|
||||
ctorDescriptor: new SyncDescriptor(DefaultRecommendedExtensionsView),
|
||||
when: ContextKeyExpr.and(ContextKeyExpr.has('defaultExtensionViews'), ContextKeyExpr.has('defaultRecommendedExtensions')),
|
||||
weight: 40,
|
||||
order: 2,
|
||||
canToggleVisibility: true
|
||||
};
|
||||
}
|
||||
|
||||
// Separate view for recommedations that are not workspace recommendations.
|
||||
// Shown along with view for workspace recommendations, when using the command that shows recommendations
|
||||
private createOtherRecommendedExtensionsListViewDescriptor(): IViewDescriptor {
|
||||
const id = 'extensions.otherrecommendedList';
|
||||
return {
|
||||
id,
|
||||
name: viewIdNameMappings[id],
|
||||
ctorDescriptor: new SyncDescriptor(RecommendedExtensionsView),
|
||||
when: ContextKeyExpr.has('recommendedExtensions'),
|
||||
weight: 50,
|
||||
order: 2
|
||||
};
|
||||
}
|
||||
|
||||
// Separate view for workspace recommendations.
|
||||
// Shown along with view for other recommendations, when using the command that shows recommendations
|
||||
private createWorkspaceRecommendedExtensionsListViewDescriptor(): IViewDescriptor {
|
||||
const id = 'extensions.workspaceRecommendedList';
|
||||
return {
|
||||
id,
|
||||
name: viewIdNameMappings[id],
|
||||
ctorDescriptor: new SyncDescriptor(WorkspaceRecommendedExtensionsView),
|
||||
when: ContextKeyExpr.and(ContextKeyExpr.has('recommendedExtensions'), ContextKeyExpr.has('nonEmptyWorkspace')),
|
||||
weight: 50,
|
||||
order: 1
|
||||
};
|
||||
}
|
||||
|
||||
private createEnabledExtensionsListViewDescriptor(): IViewDescriptor {
|
||||
const id = 'extensions.enabledExtensionList2';
|
||||
return {
|
||||
id,
|
||||
name: viewIdNameMappings[id],
|
||||
/*
|
||||
* View used for searching enabled extensions
|
||||
*/
|
||||
viewDescriptors.push({
|
||||
id: 'workbench.views.extensions.searchEnabled',
|
||||
name: localize('enabled', "Enabled"),
|
||||
ctorDescriptor: new SyncDescriptor(EnabledExtensionsView),
|
||||
when: ContextKeyExpr.and(ContextKeyExpr.has('searchEnabledExtensions')),
|
||||
weight: 40,
|
||||
order: 1
|
||||
};
|
||||
}
|
||||
});
|
||||
|
||||
private createDisabledExtensionsListViewDescriptor(): IViewDescriptor {
|
||||
const id = 'extensions.disabledExtensionList2';
|
||||
return {
|
||||
id,
|
||||
name: viewIdNameMappings[id],
|
||||
/*
|
||||
* View used for searching disabled extensions
|
||||
*/
|
||||
viewDescriptors.push({
|
||||
id: 'workbench.views.extensions.searchDisabled',
|
||||
name: localize('disabled', "Disabled"),
|
||||
ctorDescriptor: new SyncDescriptor(DisabledExtensionsView),
|
||||
when: ContextKeyExpr.and(ContextKeyExpr.has('searchDisabledExtensions')),
|
||||
weight: 10,
|
||||
order: 3,
|
||||
collapsed: true
|
||||
};
|
||||
});
|
||||
|
||||
/*
|
||||
* View used for searching outdated extensions
|
||||
*/
|
||||
viewDescriptors.push({
|
||||
id: 'workbench.views.extensions.searchOutdated',
|
||||
name: localize('outdated', "Outdated"),
|
||||
ctorDescriptor: new SyncDescriptor(OutdatedExtensionsView),
|
||||
when: ContextKeyExpr.and(ContextKeyExpr.has('searchOutdatedExtensions')),
|
||||
});
|
||||
|
||||
/*
|
||||
* View used for searching builtin extensions
|
||||
*/
|
||||
viewDescriptors.push({
|
||||
id: 'workbench.views.extensions.searchBuiltin',
|
||||
name: localize('builtin', "Builtin"),
|
||||
ctorDescriptor: new SyncDescriptor(SearchBuiltInExtensionsView),
|
||||
when: ContextKeyExpr.and(ContextKeyExpr.has('searchBuiltInExtensions')),
|
||||
});
|
||||
|
||||
return viewDescriptors;
|
||||
}
|
||||
|
||||
private createBuiltInExtensionsListViewDescriptor(): IViewDescriptor {
|
||||
const id = 'extensions.builtInExtensionsList';
|
||||
return {
|
||||
id,
|
||||
name: viewIdNameMappings[id],
|
||||
ctorDescriptor: new SyncDescriptor(BuiltInExtensionsView),
|
||||
when: ContextKeyExpr.has('searchBuiltInExtensions'),
|
||||
weight: 100
|
||||
};
|
||||
private createRecommendedExtensionsViewDescriptors(): IViewDescriptor[] {
|
||||
const viewDescriptors: IViewDescriptor[] = [];
|
||||
|
||||
viewDescriptors.push({
|
||||
id: 'workbench.views.extensions.workspaceRecommendations',
|
||||
name: localize('workspaceRecommendedExtensions', "Workspace Recommendations"),
|
||||
ctorDescriptor: new SyncDescriptor(WorkspaceRecommendedExtensionsView),
|
||||
when: ContextKeyExpr.and(ContextKeyExpr.has('recommendedExtensions'), ContextKeyExpr.has('nonEmptyWorkspace')),
|
||||
order: 1
|
||||
});
|
||||
|
||||
viewDescriptors.push({
|
||||
id: 'workbench.views.extensions.otherRecommendations',
|
||||
name: localize('otherRecommendedExtensions', "Other Recommendations"),
|
||||
ctorDescriptor: new SyncDescriptor(RecommendedExtensionsView),
|
||||
when: ContextKeyExpr.has('recommendedExtensions'),
|
||||
order: 2
|
||||
});
|
||||
|
||||
return viewDescriptors;
|
||||
}
|
||||
|
||||
private createBuiltInThemesExtensionsListViewDescriptor(): IViewDescriptor {
|
||||
const id = 'extensions.builtInThemesExtensionsList';
|
||||
return {
|
||||
id,
|
||||
name: viewIdNameMappings[id],
|
||||
private createBuiltinExtensionsViewDescriptors(): IViewDescriptor[] {
|
||||
const viewDescriptors: IViewDescriptor[] = [];
|
||||
|
||||
viewDescriptors.push({
|
||||
id: 'workbench.views.extensions.builtinFeatureExtensions',
|
||||
name: localize('builtinFeatureExtensions', "Features"),
|
||||
ctorDescriptor: new SyncDescriptor(BuiltInFeatureExtensionsView),
|
||||
when: ContextKeyExpr.has('builtInExtensions'),
|
||||
});
|
||||
|
||||
viewDescriptors.push({
|
||||
id: 'workbench.views.extensions.builtinThemeExtensions',
|
||||
name: localize('builtInThemesExtensions', "Themes"),
|
||||
ctorDescriptor: new SyncDescriptor(BuiltInThemesExtensionsView),
|
||||
when: ContextKeyExpr.has('searchBuiltInExtensions'),
|
||||
weight: 100
|
||||
};
|
||||
}
|
||||
when: ContextKeyExpr.has('builtInExtensions'),
|
||||
});
|
||||
|
||||
private createBuiltInBasicsExtensionsListViewDescriptor(): IViewDescriptor {
|
||||
const id = 'extensions.builtInBasicsExtensionsList';
|
||||
return {
|
||||
id,
|
||||
name: viewIdNameMappings[id],
|
||||
ctorDescriptor: new SyncDescriptor(BuiltInBasicsExtensionsView),
|
||||
when: ContextKeyExpr.has('searchBuiltInExtensions'),
|
||||
weight: 100
|
||||
};
|
||||
viewDescriptors.push({
|
||||
id: 'workbench.views.extensions.builtinProgrammingLanguageExtensions',
|
||||
name: localize('builtinProgrammingLanguageExtensions', "Programming Languages"),
|
||||
ctorDescriptor: new SyncDescriptor(BuiltInProgrammingLanguageExtensionsView),
|
||||
when: ContextKeyExpr.has('builtInExtensions'),
|
||||
});
|
||||
|
||||
return viewDescriptors;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -336,15 +331,13 @@ export class ExtensionsViewPaneContainer extends ViewPaneContainer implements IE
|
||||
private searchEnabledExtensionsContextKey: IContextKey<boolean>;
|
||||
private searchDisabledExtensionsContextKey: IContextKey<boolean>;
|
||||
private hasInstalledExtensionsContextKey: IContextKey<boolean>;
|
||||
private builtInExtensionsContextKey: IContextKey<boolean>;
|
||||
private searchBuiltInExtensionsContextKey: IContextKey<boolean>;
|
||||
private recommendedExtensionsContextKey: IContextKey<boolean>;
|
||||
private defaultRecommendedExtensionsContextKey: IContextKey<boolean>;
|
||||
|
||||
private searchDelayer: Delayer<void>;
|
||||
private root: HTMLElement | undefined;
|
||||
private searchBox: SuggestEnabledInput | undefined;
|
||||
private primaryActions: IAction[] | undefined;
|
||||
private secondaryActions: IAction[] | null = null;
|
||||
private readonly searchViewletState: MementoObject;
|
||||
|
||||
constructor(
|
||||
@@ -364,7 +357,7 @@ export class ExtensionsViewPaneContainer extends ViewPaneContainer implements IE
|
||||
@IContextMenuService contextMenuService: IContextMenuService,
|
||||
@IExtensionService extensionService: IExtensionService,
|
||||
@IViewDescriptorService viewDescriptorService: IViewDescriptorService,
|
||||
@IPreferencesService private readonly preferencesService: IPreferencesService
|
||||
@IPreferencesService private readonly preferencesService: IPreferencesService,
|
||||
) {
|
||||
super(VIEWLET_ID, { mergeViewWithContainerWhenSingleView: true }, instantiationService, configurationService, layoutService, contextMenuService, telemetryService, extensionService, themeService, storageService, contextService, viewDescriptorService);
|
||||
|
||||
@@ -377,10 +370,9 @@ export class ExtensionsViewPaneContainer extends ViewPaneContainer implements IE
|
||||
this.searchEnabledExtensionsContextKey = SearchEnabledExtensionsContext.bindTo(contextKeyService);
|
||||
this.searchDisabledExtensionsContextKey = SearchDisabledExtensionsContext.bindTo(contextKeyService);
|
||||
this.hasInstalledExtensionsContextKey = HasInstalledExtensionsContext.bindTo(contextKeyService);
|
||||
this.builtInExtensionsContextKey = BuiltInExtensionsContext.bindTo(contextKeyService);
|
||||
this.searchBuiltInExtensionsContextKey = SearchBuiltInExtensionsContext.bindTo(contextKeyService);
|
||||
this.recommendedExtensionsContextKey = RecommendedExtensionsContext.bindTo(contextKeyService);
|
||||
this.defaultRecommendedExtensionsContextKey = DefaultRecommendedExtensionsContext.bindTo(contextKeyService);
|
||||
this.defaultRecommendedExtensionsContextKey.set(!this.configurationService.getValue<boolean>(ShowRecommendationsOnlyOnDemandKey));
|
||||
this._register(this.viewletService.onDidViewletOpen(this.onViewletOpen, this));
|
||||
this.searchViewletState = this.getMemento(StorageScope.WORKSPACE);
|
||||
|
||||
@@ -390,12 +382,8 @@ export class ExtensionsViewPaneContainer extends ViewPaneContainer implements IE
|
||||
|
||||
this._register(this.configurationService.onDidChangeConfiguration(e => {
|
||||
if (e.affectsConfiguration(AutoUpdateConfigurationKey)) {
|
||||
this.secondaryActions = null;
|
||||
this.updateTitleArea();
|
||||
}
|
||||
if (e.affectedKeys.indexOf(ShowRecommendationsOnlyOnDemandKey) > -1) {
|
||||
this.defaultRecommendedExtensionsContextKey.set(!this.configurationService.getValue<boolean>(ShowRecommendationsOnlyOnDemandKey));
|
||||
}
|
||||
}, this));
|
||||
}
|
||||
|
||||
@@ -509,40 +497,57 @@ export class ExtensionsViewPaneContainer extends ViewPaneContainer implements IE
|
||||
}
|
||||
|
||||
getActions(): IAction[] {
|
||||
if (!this.primaryActions) {
|
||||
this.primaryActions = [
|
||||
this.instantiationService.createInstance(ClearExtensionsInputAction, ClearExtensionsInputAction.ID, ClearExtensionsInputAction.LABEL, this.onSearchChange, this.searchBox ? this.searchBox.getValue() : '')
|
||||
];
|
||||
return [
|
||||
new Action('workbench.extensions.action.filterExtensions', localize('filterExtensions', "Filter Extensions..."), 'codicon-filter', true),
|
||||
this.instantiationService.createInstance(ClearExtensionsInputAction, ClearExtensionsInputAction.ID, ClearExtensionsInputAction.LABEL, this.onSearchChange, this.searchBox ? this.searchBox.getValue() : ''),
|
||||
];
|
||||
}
|
||||
|
||||
getActionViewItem(action: IAction): IActionViewItem | undefined {
|
||||
if (action.id === 'workbench.extensions.action.filterExtensions') {
|
||||
return new DropdownMenuActionViewItem(action,
|
||||
[
|
||||
// this.instantiationService.createInstance(ShowPopularExtensionsAction, ShowPopularExtensionsAction.ID, localize('most popular filter', "Most Popular")), // {{SQL CARBON EDIT}}
|
||||
// this.instantiationService.createInstance(RecentlyPublishedExtensionsAction, RecentlyPublishedExtensionsAction.ID, localize('recently published filter', "Recently Published")), // {{SQL CARBON EDIT}}
|
||||
this.instantiationService.createInstance(ShowRecommendedExtensionsAction, ShowRecommendedExtensionsAction.ID, localize('recomended filter', "Recommended")),
|
||||
new ContextSubMenu(localize('filter by category', "Category"), EXTENSION_CATEGORIES.map(category => this.instantiationService.createInstance(SearchCategoryAction, `extensions.actions.searchByCategory.${category}`, category, category))),
|
||||
|
||||
new Separator(),
|
||||
this.instantiationService.createInstance(ShowBuiltInExtensionsAction, ShowBuiltInExtensionsAction.ID, localize('builtin filter', "Built-in")),
|
||||
this.instantiationService.createInstance(ShowInstalledExtensionsAction, ShowInstalledExtensionsAction.ID, localize('installed filter', "Installed")),
|
||||
this.instantiationService.createInstance(ShowEnabledExtensionsAction, ShowEnabledExtensionsAction.ID, localize('enabled filter', "Enabled")),
|
||||
this.instantiationService.createInstance(ShowDisabledExtensionsAction, ShowDisabledExtensionsAction.ID, localize('disabled filter', "Disabled")),
|
||||
this.instantiationService.createInstance(ShowOutdatedExtensionsAction, ShowOutdatedExtensionsAction.ID, localize('outdated filter', "Outdated")),
|
||||
|
||||
new Separator(),
|
||||
new ContextSubMenu(localize('sorty by', "Sort By"), [
|
||||
// this.instantiationService.createInstance(ChangeSortAction, 'extensions.sort.install', localize('sort by installs', "Install Count"), this.onSearchChange, 'installs'), // {{SQL CARBON EDIT}}
|
||||
// this.instantiationService.createInstance(ChangeSortAction, 'extensions.sort.rating', localize('sort by rating', "Rating"), this.onSearchChange, 'rating'), // {{SQL CARBON EDIT}}
|
||||
this.instantiationService.createInstance(ChangeSortAction, 'extensions.sort.name', localize('sort by name', "Name"), this.onSearchChange, 'name'),
|
||||
this.instantiationService.createInstance(ChangeSortAction, 'extensions.sort.publishedDate', localize('sort by date', "Published Date"), this.onSearchChange, 'publishedDate'),
|
||||
]),
|
||||
],
|
||||
this.contextMenuService, undefined, undefined, undefined, 'codicon-filter', undefined, true);
|
||||
}
|
||||
return this.primaryActions;
|
||||
return super.getActionViewItem(action);
|
||||
}
|
||||
|
||||
getSecondaryActions(): IAction[] {
|
||||
if (!this.secondaryActions) {
|
||||
this.secondaryActions = [
|
||||
this.instantiationService.createInstance(ShowInstalledExtensionsAction, ShowInstalledExtensionsAction.ID, ShowInstalledExtensionsAction.LABEL),
|
||||
this.instantiationService.createInstance(ShowOutdatedExtensionsAction, ShowOutdatedExtensionsAction.ID, ShowOutdatedExtensionsAction.LABEL),
|
||||
this.instantiationService.createInstance(ShowEnabledExtensionsAction, ShowEnabledExtensionsAction.ID, ShowEnabledExtensionsAction.LABEL),
|
||||
this.instantiationService.createInstance(ShowDisabledExtensionsAction, ShowDisabledExtensionsAction.ID, ShowDisabledExtensionsAction.LABEL),
|
||||
this.instantiationService.createInstance(ShowBuiltInExtensionsAction, ShowBuiltInExtensionsAction.ID, ShowBuiltInExtensionsAction.LABEL),
|
||||
this.instantiationService.createInstance(ShowRecommendedExtensionsAction, ShowRecommendedExtensionsAction.ID, ShowRecommendedExtensionsAction.LABEL),
|
||||
// this.instantiationService.createInstance(ShowPopularExtensionsAction, ShowPopularExtensionsAction.ID, ShowPopularExtensionsAction.LABEL), // {{SQL CARBON EDIT}}
|
||||
new Separator(),
|
||||
// {{SQL CARBON EDIT}}
|
||||
//this.instantiationService.createInstance(ChangeSortAction, 'extensions.sort.install', localize('sort by installs', "Sort By: Install Count"), this.onSearchChange, 'installs'),
|
||||
//this.instantiationService.createInstance(ChangeSortAction, 'extensions.sort.rating', localize('sort by rating', "Sort By: Rating"), this.onSearchChange, 'rating'),
|
||||
this.instantiationService.createInstance(ChangeSortAction, 'extensions.sort.name', localize('sort by name', "Sort By: Name"), this.onSearchChange, 'name'),
|
||||
new Separator(),
|
||||
this.instantiationService.createInstance(CheckForUpdatesAction, CheckForUpdatesAction.ID, CheckForUpdatesAction.LABEL),
|
||||
...(this.configurationService.getValue(AutoUpdateConfigurationKey) ? [this.instantiationService.createInstance(DisableAutoUpdateAction, DisableAutoUpdateAction.ID, DisableAutoUpdateAction.LABEL)] : [this.instantiationService.createInstance(UpdateAllAction, UpdateAllAction.ID, UpdateAllAction.LABEL), this.instantiationService.createInstance(EnableAutoUpdateAction, EnableAutoUpdateAction.ID, EnableAutoUpdateAction.LABEL)]),
|
||||
this.instantiationService.createInstance(InstallVSIXAction, InstallVSIXAction.ID, InstallVSIXAction.LABEL),
|
||||
new Separator(),
|
||||
this.instantiationService.createInstance(DisableAllAction, DisableAllAction.ID, DisableAllAction.LABEL),
|
||||
this.instantiationService.createInstance(EnableAllAction, EnableAllAction.ID, EnableAllAction.LABEL)
|
||||
];
|
||||
}
|
||||
const actions: IAction[] = [];
|
||||
|
||||
return this.secondaryActions;
|
||||
actions.push(this.instantiationService.createInstance(CheckForUpdatesAction, CheckForUpdatesAction.ID, CheckForUpdatesAction.LABEL));
|
||||
if (this.configurationService.getValue(AutoUpdateConfigurationKey)) {
|
||||
actions.push(this.instantiationService.createInstance(DisableAutoUpdateAction, DisableAutoUpdateAction.ID, DisableAutoUpdateAction.LABEL));
|
||||
} else {
|
||||
actions.push(this.instantiationService.createInstance(UpdateAllAction, UpdateAllAction.ID, UpdateAllAction.LABEL), this.instantiationService.createInstance(EnableAutoUpdateAction, EnableAutoUpdateAction.ID, EnableAutoUpdateAction.LABEL));
|
||||
}
|
||||
actions.push(this.instantiationService.createInstance(InstallVSIXAction, InstallVSIXAction.ID, InstallVSIXAction.LABEL));
|
||||
|
||||
actions.push(new Separator());
|
||||
actions.push(this.instantiationService.createInstance(DisableAllAction, DisableAllAction.ID, DisableAllAction.LABEL));
|
||||
actions.push(this.instantiationService.createInstance(EnableAllAction, EnableAllAction.ID, EnableAllAction.LABEL));
|
||||
|
||||
return actions;
|
||||
}
|
||||
|
||||
search(value: string, refresh: boolean = false): void {
|
||||
@@ -580,7 +585,8 @@ export class ExtensionsViewPaneContainer extends ViewPaneContainer implements IE
|
||||
this.searchOutdatedExtensionsContextKey.set(ExtensionsListView.isOutdatedExtensionsQuery(value));
|
||||
this.searchEnabledExtensionsContextKey.set(ExtensionsListView.isEnabledExtensionsQuery(value));
|
||||
this.searchDisabledExtensionsContextKey.set(ExtensionsListView.isDisabledExtensionsQuery(value));
|
||||
this.searchBuiltInExtensionsContextKey.set(ExtensionsListView.isBuiltInExtensionsQuery(value));
|
||||
this.searchBuiltInExtensionsContextKey.set(ExtensionsListView.isSearchBuiltInExtensionsQuery(value));
|
||||
this.builtInExtensionsContextKey.set(ExtensionsListView.isBuiltInExtensionsQuery(value));
|
||||
this.recommendedExtensionsContextKey.set(isRecommendedExtensionsQuery);
|
||||
this.searchMarketplaceExtensionsContextKey.set(!!value && !ExtensionsListView.isLocalExtensionsQuery(value) && !isRecommendedExtensionsQuery);
|
||||
this.nonEmptyWorkspaceContextKey.set(this.contextService.getWorkbenchState() !== WorkbenchState.EMPTY);
|
||||
@@ -602,19 +608,20 @@ export class ExtensionsViewPaneContainer extends ViewPaneContainer implements IE
|
||||
}
|
||||
|
||||
private alertSearchResult(count: number, viewId: string): void {
|
||||
const view = this.viewContainerModel.visibleViewDescriptors.find(view => view.id === viewId);
|
||||
switch (count) {
|
||||
case 0:
|
||||
break;
|
||||
case 1:
|
||||
if (viewIdNameMappings[viewId]) {
|
||||
alert(localize('extensionFoundInSection', "1 extension found in the {0} section.", viewIdNameMappings[viewId]));
|
||||
if (view) {
|
||||
alert(localize('extensionFoundInSection', "1 extension found in the {0} section.", view.name));
|
||||
} else {
|
||||
alert(localize('extensionFound', "1 extension found."));
|
||||
}
|
||||
break;
|
||||
default:
|
||||
if (viewIdNameMappings[viewId]) {
|
||||
alert(localize('extensionsFoundInSection', "{0} extensions found in the {1} section.", count, viewIdNameMappings[viewId]));
|
||||
if (view) {
|
||||
alert(localize('extensionsFoundInSection', "{0} extensions found in the {1} section.", count, view.name));
|
||||
} else {
|
||||
alert(localize('extensionsFound', "{0} extensions found.", count));
|
||||
}
|
||||
|
||||
@@ -197,6 +197,7 @@ export class ExtensionsListView extends ViewPane {
|
||||
case 'installs': options = assign(options, { sortBy: SortBy.InstallCount }); break;
|
||||
case 'rating': options = assign(options, { sortBy: SortBy.WeightedRating }); break;
|
||||
case 'name': options = assign(options, { sortBy: SortBy.Title }); break;
|
||||
case 'publishedDate': options = assign(options, { sortBy: SortBy.PublishedDate }); break;
|
||||
}
|
||||
|
||||
const successCallback = (model: IPagedModel<IExtension>) => {
|
||||
@@ -882,16 +883,21 @@ export class ExtensionsListView extends ViewPane {
|
||||
this.list = null;
|
||||
}
|
||||
|
||||
static isBuiltInExtensionsQuery(query: string): boolean {
|
||||
return /^\s*@builtin\s*$/i.test(query);
|
||||
}
|
||||
|
||||
static isLocalExtensionsQuery(query: string): boolean {
|
||||
return this.isInstalledExtensionsQuery(query)
|
||||
|| this.isOutdatedExtensionsQuery(query)
|
||||
|| this.isEnabledExtensionsQuery(query)
|
||||
|| this.isDisabledExtensionsQuery(query)
|
||||
|| this.isBuiltInExtensionsQuery(query);
|
||||
|| this.isBuiltInExtensionsQuery(query)
|
||||
|| this.isSearchBuiltInExtensionsQuery(query);
|
||||
}
|
||||
|
||||
static isSearchBuiltInExtensionsQuery(query: string): boolean {
|
||||
return /@builtin\s.+/i.test(query);
|
||||
}
|
||||
|
||||
static isBuiltInExtensionsQuery(query: string): boolean {
|
||||
return /@builtin$/i.test(query.trim());
|
||||
}
|
||||
|
||||
static isInstalledExtensionsQuery(query: string): boolean {
|
||||
@@ -977,7 +983,7 @@ export class ServerExtensionsView extends ExtensionsListView {
|
||||
|
||||
async show(query: string): Promise<IPagedModel<IExtension>> {
|
||||
query = query ? query : '@installed';
|
||||
if (!ExtensionsListView.isLocalExtensionsQuery(query) && !ExtensionsListView.isBuiltInExtensionsQuery(query)) {
|
||||
if (!ExtensionsListView.isLocalExtensionsQuery(query)) {
|
||||
query = query += ' @installed';
|
||||
}
|
||||
return super.show(query.trim());
|
||||
@@ -1009,7 +1015,29 @@ export class DisabledExtensionsView extends ExtensionsListView {
|
||||
}
|
||||
}
|
||||
|
||||
export class BuiltInExtensionsView extends ExtensionsListView {
|
||||
export class OutdatedExtensionsView extends ExtensionsListView {
|
||||
|
||||
async show(query: string): Promise<IPagedModel<IExtension>> {
|
||||
query = query || '@outdated';
|
||||
return ExtensionsListView.isOutdatedExtensionsQuery(query) ? super.show(query) : this.showEmptyModel();
|
||||
}
|
||||
}
|
||||
|
||||
export class InstalledExtensionsView extends ExtensionsListView {
|
||||
|
||||
async show(query: string): Promise<IPagedModel<IExtension>> {
|
||||
query = query || '@installed';
|
||||
return ExtensionsListView.isInstalledExtensionsQuery(query) ? super.show(query) : this.showEmptyModel();
|
||||
}
|
||||
}
|
||||
|
||||
export class SearchBuiltInExtensionsView extends ExtensionsListView {
|
||||
async show(query: string): Promise<IPagedModel<IExtension>> {
|
||||
return ExtensionsListView.isSearchBuiltInExtensionsQuery(query) ? super.show(query) : this.showEmptyModel();
|
||||
}
|
||||
}
|
||||
|
||||
export class BuiltInFeatureExtensionsView extends ExtensionsListView {
|
||||
async show(query: string): Promise<IPagedModel<IExtension>> {
|
||||
return (query && query.trim() !== '@builtin') ? this.showEmptyModel() : super.show('@builtin:features');
|
||||
}
|
||||
@@ -1021,7 +1049,7 @@ export class BuiltInThemesExtensionsView extends ExtensionsListView {
|
||||
}
|
||||
}
|
||||
|
||||
export class BuiltInBasicsExtensionsView extends ExtensionsListView {
|
||||
export class BuiltInProgrammingLanguageExtensionsView extends ExtensionsListView {
|
||||
async show(query: string): Promise<IPagedModel<IExtension>> {
|
||||
return (query && query.trim() !== '@builtin') ? this.showEmptyModel() : super.show('@builtin:basics');
|
||||
}
|
||||
|
||||
@@ -13,7 +13,8 @@ export const CELL_RUN_GUTTER = 28;
|
||||
export const CODE_CELL_LEFT_MARGIN = 32;
|
||||
|
||||
export const EDITOR_TOOLBAR_HEIGHT = 0;
|
||||
export const BOTTOM_CELL_TOOLBAR_HEIGHT = 28;
|
||||
export const BOTTOM_CELL_TOOLBAR_HEIGHT = 18;
|
||||
export const BOTTOM_CELL_TOOLBAR_OFFSET = 12;
|
||||
export const CELL_STATUSBAR_HEIGHT = 22;
|
||||
|
||||
// Margin above editor
|
||||
|
||||
@@ -74,7 +74,8 @@ const FOCUS_OUT_OUTPUT_COMMAND_ID = 'notebook.cell.focusOutOutput';
|
||||
|
||||
export const NOTEBOOK_ACTIONS_CATEGORY = { value: localize('notebookActions.category', "Notebook"), original: 'Notebook' };
|
||||
|
||||
export const CELL_TITLE_GROUP_ID = 'inline';
|
||||
export const CELL_TITLE_CELL_GROUP_ID = 'inline/cell';
|
||||
export const CELL_TITLE_OUTPUT_GROUP_ID = 'inline/output';
|
||||
|
||||
const EDITOR_WIDGET_ACTION_WEIGHT = KeybindingWeight.EditorContrib; // smaller than Suggest Widget, etc
|
||||
|
||||
@@ -407,6 +408,11 @@ registerAction2(class extends NotebookCellAction {
|
||||
weight: KeybindingWeight.WorkbenchContrib
|
||||
},
|
||||
precondition: ContextKeyExpr.and(NOTEBOOK_IS_ACTIVE_EDITOR),
|
||||
menu: {
|
||||
id: MenuId.NotebookCellTitle,
|
||||
when: ContextKeyExpr.and(NOTEBOOK_EDITOR_FOCUSED, NOTEBOOK_EDITOR_EDITABLE, NOTEBOOK_CELL_EDITABLE),
|
||||
group: '2_edit',
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@@ -425,6 +431,11 @@ registerAction2(class extends NotebookCellAction {
|
||||
primary: KeyCode.KEY_M,
|
||||
weight: KeybindingWeight.WorkbenchContrib
|
||||
},
|
||||
menu: {
|
||||
id: MenuId.NotebookCellTitle,
|
||||
when: ContextKeyExpr.and(NOTEBOOK_EDITOR_FOCUSED, NOTEBOOK_EDITOR_EDITABLE, NOTEBOOK_CELL_EDITABLE),
|
||||
group: '2_edit',
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@@ -601,7 +612,7 @@ registerAction2(class extends NotebookCellAction {
|
||||
NOTEBOOK_CELL_MARKDOWN_EDIT_MODE.toNegated(),
|
||||
NOTEBOOK_CELL_EDITABLE),
|
||||
order: CellToolbarOrder.EditCell,
|
||||
group: CELL_TITLE_GROUP_ID
|
||||
group: CELL_TITLE_CELL_GROUP_ID
|
||||
},
|
||||
icon: { id: 'codicon/pencil' }
|
||||
});
|
||||
@@ -625,7 +636,7 @@ registerAction2(class extends NotebookCellAction {
|
||||
NOTEBOOK_CELL_MARKDOWN_EDIT_MODE,
|
||||
NOTEBOOK_CELL_EDITABLE),
|
||||
order: CellToolbarOrder.SaveCell,
|
||||
group: CELL_TITLE_GROUP_ID
|
||||
group: CELL_TITLE_CELL_GROUP_ID
|
||||
},
|
||||
icon: { id: 'codicon/check' },
|
||||
keybinding: {
|
||||
@@ -659,7 +670,7 @@ registerAction2(class extends NotebookCellAction {
|
||||
id: MenuId.NotebookCellTitle,
|
||||
order: CellToolbarOrder.DeleteCell,
|
||||
when: NOTEBOOK_EDITOR_EDITABLE,
|
||||
group: CELL_TITLE_GROUP_ID
|
||||
group: CELL_TITLE_CELL_GROUP_ID
|
||||
},
|
||||
keybinding: {
|
||||
primary: KeyCode.Delete,
|
||||
@@ -758,6 +769,11 @@ registerAction2(class extends NotebookCellAction {
|
||||
primary: KeyMod.CtrlCmd | KeyCode.KEY_C,
|
||||
weight: EDITOR_WIDGET_ACTION_WEIGHT
|
||||
},
|
||||
menu: {
|
||||
id: MenuId.NotebookCellTitle,
|
||||
when: NOTEBOOK_EDITOR_FOCUSED,
|
||||
group: '1_copy',
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@@ -780,6 +796,11 @@ registerAction2(class extends NotebookCellAction {
|
||||
primary: KeyMod.CtrlCmd | KeyCode.KEY_X,
|
||||
weight: EDITOR_WIDGET_ACTION_WEIGHT
|
||||
},
|
||||
menu: {
|
||||
id: MenuId.NotebookCellTitle,
|
||||
when: ContextKeyExpr.and(NOTEBOOK_EDITOR_FOCUSED, NOTEBOOK_EDITOR_EDITABLE, NOTEBOOK_CELL_EDITABLE),
|
||||
group: '1_copy',
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@@ -864,6 +885,11 @@ registerAction2(class extends NotebookAction {
|
||||
primary: KeyMod.CtrlCmd | KeyCode.KEY_V,
|
||||
weight: EDITOR_WIDGET_ACTION_WEIGHT
|
||||
},
|
||||
menu: {
|
||||
id: MenuId.NotebookCellTitle,
|
||||
when: ContextKeyExpr.and(NOTEBOOK_EDITOR_FOCUSED, NOTEBOOK_EDITOR_EDITABLE),
|
||||
group: '1_copy',
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@@ -1176,7 +1202,7 @@ registerAction2(class extends NotebookCellAction {
|
||||
id: MenuId.NotebookCellTitle,
|
||||
when: ContextKeyExpr.and(NOTEBOOK_CELL_TYPE.isEqualTo('code'), NOTEBOOK_EDITOR_RUNNABLE),
|
||||
order: CellToolbarOrder.ClearCellOutput,
|
||||
group: CELL_TITLE_GROUP_ID
|
||||
group: CELL_TITLE_OUTPUT_GROUP_ID
|
||||
},
|
||||
keybinding: {
|
||||
when: ContextKeyExpr.and(NOTEBOOK_EDITOR_FOCUSED, ContextKeyExpr.not(InputFocusedContextKey), NOTEBOOK_CELL_HAS_OUTPUTS),
|
||||
@@ -1339,7 +1365,11 @@ registerAction2(class extends NotebookCellAction {
|
||||
id: MenuId.NotebookCellTitle,
|
||||
when: ContextKeyExpr.and(NOTEBOOK_EDITOR_FOCUSED, NOTEBOOK_EDITOR_EDITABLE, NOTEBOOK_CELL_EDITABLE, InputFocusedContext),
|
||||
order: CellToolbarOrder.SplitCell,
|
||||
group: CELL_TITLE_GROUP_ID
|
||||
group: CELL_TITLE_CELL_GROUP_ID,
|
||||
// alt: {
|
||||
// id: JOIN_CELL_BELOW_COMMAND_ID,
|
||||
// title: localize('notebookActions.joinCellBelow', "Join with Next Cell")
|
||||
// }
|
||||
},
|
||||
icon: { id: 'codicon/split-vertical' },
|
||||
keybinding: {
|
||||
@@ -1392,6 +1422,11 @@ registerAction2(class extends NotebookCellAction {
|
||||
when: NOTEBOOK_EDITOR_FOCUSED,
|
||||
primary: KeyMod.WinCtrl | KeyMod.Alt | KeyCode.KEY_J,
|
||||
weight: KeybindingWeight.WorkbenchContrib
|
||||
},
|
||||
menu: {
|
||||
id: MenuId.NotebookCellTitle,
|
||||
when: ContextKeyExpr.and(NOTEBOOK_EDITOR_FOCUSED, NOTEBOOK_EDITOR_EDITABLE, NOTEBOOK_CELL_EDITABLE),
|
||||
group: '2_edit',
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@@ -166,8 +166,7 @@ export class KernelStatus extends Disposable implements IWorkbenchContribution {
|
||||
|
||||
const activeEditor = getActiveNotebookEditor(this._editorService);
|
||||
|
||||
if (activeEditor && activeEditor.multipleKernelsAvailable) {
|
||||
this.showKernelStatus(activeEditor.activeKernel);
|
||||
if (activeEditor) {
|
||||
this._editorDisposable.add(activeEditor.onDidChangeKernel(() => {
|
||||
if (activeEditor.multipleKernelsAvailable) {
|
||||
this.showKernelStatus(activeEditor.activeKernel);
|
||||
@@ -175,6 +174,18 @@ export class KernelStatus extends Disposable implements IWorkbenchContribution {
|
||||
this.kernelInfoElement.clear();
|
||||
}
|
||||
}));
|
||||
|
||||
this._editorDisposable.add(activeEditor.onDidChangeAvailableKernels(() => {
|
||||
if (activeEditor.multipleKernelsAvailable) {
|
||||
this.showKernelStatus(activeEditor.activeKernel);
|
||||
} else {
|
||||
this.kernelInfoElement.clear();
|
||||
}
|
||||
}));
|
||||
}
|
||||
|
||||
if (activeEditor && activeEditor.multipleKernelsAvailable) {
|
||||
this.showKernelStatus(activeEditor.activeKernel);
|
||||
} else {
|
||||
this.kernelInfoElement.clear();
|
||||
}
|
||||
|
||||
@@ -488,6 +488,9 @@
|
||||
.monaco-workbench .notebookOverlay > .cell-list-container > .monaco-list > .monaco-scrollable-element > .monaco-list-rows > .monaco-list-row .cell-bottom-toolbar-container {
|
||||
position: absolute;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
z-index: 30; /* over the focus outline on the editor */
|
||||
width: 100%;
|
||||
opacity: 0;
|
||||
transition: opacity 0.2s ease-in-out;
|
||||
cursor: auto;
|
||||
@@ -531,19 +534,8 @@
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.monaco-workbench .notebookOverlay > .cell-list-container > .monaco-list > .monaco-scrollable-element > .monaco-list-rows > .monaco-list-row .cell-bottom-toolbar-container .separator {
|
||||
height: 1px;
|
||||
flex-grow: 1;
|
||||
align-self: center;
|
||||
}
|
||||
|
||||
.monaco-workbench .notebookOverlay > .cell-list-container > .monaco-list > .monaco-scrollable-element > .monaco-list-rows > .monaco-list-row .cell-bottom-toolbar-container .action-item:first-child::after {
|
||||
content: ' ';
|
||||
display: block;
|
||||
height: 1px;
|
||||
width: 16px;
|
||||
align-self: center;
|
||||
margin: 0px 8px;
|
||||
.monaco-workbench .notebookOverlay > .cell-list-container > .monaco-list > .monaco-scrollable-element > .monaco-list-rows > .monaco-list-row .cell-bottom-toolbar-container .action-item:first-child {
|
||||
margin-right: 16px;
|
||||
}
|
||||
|
||||
.monaco-workbench .notebookOverlay > .cell-list-container > .monaco-list > .monaco-scrollable-element > .monaco-list-rows > .monaco-list-row .cell-bottom-toolbar-container span.codicon {
|
||||
@@ -699,7 +691,7 @@
|
||||
|
||||
.monaco-workbench .notebookOverlay > .cell-list-container .notebook-folding-indicator .codicon {
|
||||
visibility: visible;
|
||||
padding: 8px 0 0 10px;
|
||||
padding: 10px 0 0 10px;
|
||||
}
|
||||
|
||||
/** Theming */
|
||||
@@ -739,3 +731,11 @@
|
||||
.monaco-workbench.vs-dark .monaco-workbench .notebookOverlay .cell.markdown table > tbody > tr > td {
|
||||
border-color: rgba(255, 255, 255, 0.18);
|
||||
} */
|
||||
|
||||
.monaco-action-bar .action-item.verticalSeparator {
|
||||
width: 1px !important;
|
||||
background-color: #bbb;
|
||||
height: 16px !important;
|
||||
margin: 5px 4px !important;
|
||||
cursor: none;
|
||||
}
|
||||
|
||||
@@ -180,6 +180,7 @@ export interface INotebookEditor extends IEditor {
|
||||
isNotebookEditor: boolean;
|
||||
activeKernel: INotebookKernelInfo | INotebookKernelInfo2 | undefined;
|
||||
multipleKernelsAvailable: boolean;
|
||||
readonly onDidChangeAvailableKernels: Event<void>;
|
||||
readonly onDidChangeKernel: Event<void>;
|
||||
|
||||
isDisposed: boolean;
|
||||
@@ -240,10 +241,16 @@ export interface INotebookEditor extends IEditor {
|
||||
moveCellDown(cell: ICellViewModel): Promise<ICellViewModel | null>;
|
||||
|
||||
/**
|
||||
* @deprecated Note that this method doesn't support batch operations, use #moveCellToIdx instead.
|
||||
* Move a cell above or below another cell
|
||||
*/
|
||||
moveCell(cell: ICellViewModel, relativeToCell: ICellViewModel, direction: 'above' | 'below'): Promise<ICellViewModel | null>;
|
||||
|
||||
/**
|
||||
* Move a cell to a specific position
|
||||
*/
|
||||
moveCellToIdx(cell: ICellViewModel, index: number): Promise<ICellViewModel | null>;
|
||||
|
||||
/**
|
||||
* Focus the container of a cell (the monaco editor inside is not focused).
|
||||
*/
|
||||
|
||||
@@ -75,6 +75,8 @@ export class NotebookEditorWidget extends Disposable implements INotebookEditor
|
||||
private _overlayContainer!: HTMLElement;
|
||||
private _body!: HTMLElement;
|
||||
private _webview: BackLayerWebView | null = null;
|
||||
private _webviewResolved: boolean = false;
|
||||
private _webviewResolvePromise: Promise<BackLayerWebView | null> | null = null;
|
||||
private _webviewTransparentCover: HTMLElement | null = null;
|
||||
private _list: INotebookCellList | undefined;
|
||||
private _dndController: CellDragAndDropController | null = null;
|
||||
@@ -135,6 +137,8 @@ export class NotebookEditorWidget extends Disposable implements INotebookEditor
|
||||
private _activeKernel: INotebookKernelInfo | INotebookKernelInfo2 | undefined = undefined;
|
||||
private readonly _onDidChangeKernel = this._register(new Emitter<void>());
|
||||
readonly onDidChangeKernel: Event<void> = this._onDidChangeKernel.event;
|
||||
private readonly _onDidChangeAvailableKernels = this._register(new Emitter<void>());
|
||||
readonly onDidChangeAvailableKernels: Event<void> = this._onDidChangeAvailableKernels.event;
|
||||
|
||||
get activeKernel() {
|
||||
return this._activeKernel;
|
||||
@@ -150,7 +154,16 @@ export class NotebookEditorWidget extends Disposable implements INotebookEditor
|
||||
}
|
||||
|
||||
private _currentKernelTokenSource: CancellationTokenSource | undefined = undefined;
|
||||
multipleKernelsAvailable: boolean = false;
|
||||
private _multipleKernelsAvailable: boolean = false;
|
||||
|
||||
get multipleKernelsAvailable() {
|
||||
return this._multipleKernelsAvailable;
|
||||
}
|
||||
|
||||
set multipleKernelsAvailable(state: boolean) {
|
||||
this._multipleKernelsAvailable = state;
|
||||
this._onDidChangeAvailableKernels.fire();
|
||||
}
|
||||
|
||||
private readonly _onDidChangeActiveEditor = this._register(new Emitter<this>());
|
||||
readonly onDidChangeActiveEditor: Event<this> = this._onDidChangeActiveEditor.event;
|
||||
@@ -572,7 +585,7 @@ export class NotebookEditorWidget extends Disposable implements INotebookEditor
|
||||
// @deprecated
|
||||
if (provider && provider.kernel) {
|
||||
// it has a builtin kernel, don't automatically choose a kernel
|
||||
this._loadKernelPreloads(provider.providerExtensionLocation, provider.kernel);
|
||||
await this._loadKernelPreloads(provider.providerExtensionLocation, provider.kernel);
|
||||
tokenSource.dispose();
|
||||
return;
|
||||
}
|
||||
@@ -591,7 +604,7 @@ export class NotebookEditorWidget extends Disposable implements INotebookEditor
|
||||
// the provider doesn't have a builtin kernel, choose a kernel
|
||||
this.activeKernel = availableKernels[0];
|
||||
if (this.activeKernel) {
|
||||
this._loadKernelPreloads(this.activeKernel.extensionLocation, this.activeKernel);
|
||||
await this._loadKernelPreloads(this.activeKernel.extensionLocation, this.activeKernel);
|
||||
}
|
||||
|
||||
tokenSource.dispose();
|
||||
@@ -611,7 +624,7 @@ export class NotebookEditorWidget extends Disposable implements INotebookEditor
|
||||
}
|
||||
|
||||
if (this.activeKernel) {
|
||||
this._loadKernelPreloads(this.activeKernel.extensionLocation, this.activeKernel);
|
||||
await this._loadKernelPreloads(this.activeKernel.extensionLocation, this.activeKernel);
|
||||
await (this.activeKernel as INotebookKernelInfo2).resolve(this.viewModel!.uri, this.getId(), tokenSource.token); // {{SQL CARBON EDIT}} strict-null-checks
|
||||
}
|
||||
|
||||
@@ -624,7 +637,7 @@ export class NotebookEditorWidget extends Disposable implements INotebookEditor
|
||||
if (kernelsFromSameExtension.length) {
|
||||
const preferedKernel = kernelsFromSameExtension.find(kernel => kernel.isPreferred) || kernelsFromSameExtension[0];
|
||||
this.activeKernel = preferedKernel;
|
||||
this._loadKernelPreloads(this.activeKernel.extensionLocation, this.activeKernel);
|
||||
await this._loadKernelPreloads(this.activeKernel.extensionLocation, this.activeKernel);
|
||||
await preferedKernel.resolve(this.viewModel!.uri, this.getId(), tokenSource.token);
|
||||
tokenSource.dispose();
|
||||
return;
|
||||
@@ -633,15 +646,16 @@ export class NotebookEditorWidget extends Disposable implements INotebookEditor
|
||||
// the provider doesn't have a builtin kernel, choose a kernel
|
||||
this.activeKernel = kernels[0];
|
||||
if (this.activeKernel) {
|
||||
this._loadKernelPreloads(this.activeKernel.extensionLocation, this.activeKernel);
|
||||
await this._loadKernelPreloads(this.activeKernel.extensionLocation, this.activeKernel);
|
||||
await this.activeKernel.resolve(this.viewModel!.uri, this.getId(), tokenSource.token);
|
||||
}
|
||||
|
||||
tokenSource.dispose();
|
||||
}
|
||||
|
||||
private _loadKernelPreloads(extensionLocation: URI, kernel: INotebookKernelInfoDto) {
|
||||
if (kernel.preloads) {
|
||||
private async _loadKernelPreloads(extensionLocation: URI, kernel: INotebookKernelInfoDto) {
|
||||
if (kernel.preloads && kernel.preloads.length) {
|
||||
await this._resolveWebview();
|
||||
this._webview?.updateKernelPreloads([extensionLocation], kernel.preloads.map(preload => URI.revive(preload)));
|
||||
}
|
||||
}
|
||||
@@ -656,34 +670,63 @@ export class NotebookEditorWidget extends Disposable implements INotebookEditor
|
||||
this._notebookExecuting?.set(notebookMetadata.runState === NotebookRunState.Running);
|
||||
}
|
||||
|
||||
private async _resolveWebview(): Promise<BackLayerWebView | null> {
|
||||
if (!this.textModel) {
|
||||
return null;
|
||||
}
|
||||
|
||||
if (this._webviewResolvePromise) {
|
||||
return this._webviewResolvePromise;
|
||||
}
|
||||
|
||||
if (!this._webview) {
|
||||
this._webview = this.instantiationService.createInstance(BackLayerWebView, this, this.getId(), this.textModel!.uri);
|
||||
// attach the webview container to the DOM tree first
|
||||
this._list?.rowsContainer.insertAdjacentElement('afterbegin', this._webview.element);
|
||||
}
|
||||
|
||||
this._webviewResolvePromise = new Promise(async resolve => {
|
||||
await this._webview!.createWebview();
|
||||
this._webview!.webview!.onDidBlur(() => {
|
||||
this._outputFocus?.set(false);
|
||||
this.updateEditorFocus();
|
||||
|
||||
if (this._overlayContainer.contains(document.activeElement)) {
|
||||
this._webiewFocused = false;
|
||||
}
|
||||
});
|
||||
this._webview!.webview!.onDidFocus(() => {
|
||||
this._outputFocus?.set(true);
|
||||
this.updateEditorFocus();
|
||||
this._onDidFocusEmitter.fire();
|
||||
|
||||
if (this._overlayContainer.contains(document.activeElement)) {
|
||||
this._webiewFocused = true;
|
||||
}
|
||||
});
|
||||
|
||||
this._localStore.add(this._webview!.onMessage(({ message, forRenderer }) => {
|
||||
if (this.viewModel) {
|
||||
this.notebookService.onDidReceiveMessage(this.viewModel.viewType, this.getId(), forRenderer, message);
|
||||
}
|
||||
}));
|
||||
|
||||
if (this.viewModel && this.viewModel!.renderers.size) {
|
||||
this._webview?.updateRendererPreloads(this.viewModel!.renderers);
|
||||
}
|
||||
|
||||
this._webviewResolved = true;
|
||||
|
||||
resolve(this._webview!);
|
||||
});
|
||||
|
||||
return this._webviewResolvePromise;
|
||||
}
|
||||
|
||||
private async _createWebview(id: string, resource: URI): Promise<void> {
|
||||
this._webview = this.instantiationService.createInstance(BackLayerWebView, this, id, resource);
|
||||
// attach the webview container to the DOM tree first
|
||||
this._list?.rowsContainer.insertAdjacentElement('afterbegin', this._webview.element);
|
||||
await this._webview.createWebview();
|
||||
this._webview.webview.onDidBlur(() => {
|
||||
this._outputFocus?.set(false);
|
||||
this.updateEditorFocus();
|
||||
|
||||
if (this._overlayContainer.contains(document.activeElement)) {
|
||||
this._webiewFocused = false;
|
||||
}
|
||||
});
|
||||
this._webview.webview.onDidFocus(() => {
|
||||
this._outputFocus?.set(true);
|
||||
this.updateEditorFocus();
|
||||
this._onDidFocusEmitter.fire();
|
||||
|
||||
if (this._overlayContainer.contains(document.activeElement)) {
|
||||
this._webiewFocused = true;
|
||||
}
|
||||
});
|
||||
|
||||
this._localStore.add(this._webview.onMessage(({ message, forRenderer }) => {
|
||||
if (this.viewModel) {
|
||||
this.notebookService.onDidReceiveMessage(this.viewModel.viewType, this.getId(), forRenderer, message);
|
||||
}
|
||||
}));
|
||||
}
|
||||
|
||||
private async _attachModel(textModel: NotebookTextModel, viewState: INotebookEditorViewState | undefined) {
|
||||
@@ -717,10 +760,17 @@ export class NotebookEditorWidget extends Disposable implements INotebookEditor
|
||||
}
|
||||
}
|
||||
|
||||
this._webview?.updateRendererPreloads(this.viewModel.renderers);
|
||||
if (this.viewModel.renderers.size) {
|
||||
await this._resolveWebview();
|
||||
this._webview?.updateRendererPreloads(this.viewModel.renderers);
|
||||
}
|
||||
|
||||
this._localStore.add(this._list!.onWillScroll(e => {
|
||||
this._webview!.updateViewScrollTop(-e.scrollTop, []);
|
||||
if (!this._webviewResolved) {
|
||||
return;
|
||||
}
|
||||
|
||||
this._webview?.updateViewScrollTop(-e.scrollTop, []);
|
||||
this._webviewTransparentCover!.style.top = `${e.scrollTop}px`;
|
||||
}));
|
||||
|
||||
@@ -732,6 +782,11 @@ export class NotebookEditorWidget extends Disposable implements INotebookEditor
|
||||
|
||||
const scrollTop = this._list?.scrollTop || 0;
|
||||
const scrollHeight = this._list?.scrollHeight || 0;
|
||||
|
||||
if (!this._webviewResolved) {
|
||||
return;
|
||||
}
|
||||
|
||||
this._webview!.element.style.height = `${scrollHeight}px`;
|
||||
|
||||
if (this._webview?.insetMapping) {
|
||||
@@ -1128,6 +1183,15 @@ export class NotebookEditorWidget extends Disposable implements INotebookEditor
|
||||
return this._moveCellToIndex(originalIdx, newIdx);
|
||||
}
|
||||
|
||||
async moveCellToIdx(cell: ICellViewModel, index: number): Promise<ICellViewModel | null> {
|
||||
if (!this._notebookViewModel!.metadata.editable) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const originalIdx = this._notebookViewModel!.getCellIndex(cell);
|
||||
return this._moveCellToIndex(originalIdx, index);
|
||||
}
|
||||
|
||||
private async _moveCellToIndex(index: number, newIdx: number): Promise<ICellViewModel | null> {
|
||||
if (index === newIdx) {
|
||||
return null;
|
||||
@@ -1356,6 +1420,8 @@ export class NotebookEditorWidget extends Disposable implements INotebookEditor
|
||||
return;
|
||||
}
|
||||
|
||||
await this._resolveWebview();
|
||||
|
||||
let preloads = this._notebookViewModel!.renderers;
|
||||
|
||||
if (!this._webview!.insetMapping.has(output)) {
|
||||
@@ -1370,7 +1436,7 @@ export class NotebookEditorWidget extends Disposable implements INotebookEditor
|
||||
}
|
||||
|
||||
removeInset(output: IProcessedOutput) {
|
||||
if (!this._webview) {
|
||||
if (!this._webview || !this._webviewResolved) {
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -1378,7 +1444,7 @@ export class NotebookEditorWidget extends Disposable implements INotebookEditor
|
||||
}
|
||||
|
||||
hideInset(output: IProcessedOutput) {
|
||||
if (!this._webview) {
|
||||
if (!this._webview || !this._webviewResolved) {
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -1390,10 +1456,14 @@ export class NotebookEditorWidget extends Disposable implements INotebookEditor
|
||||
}
|
||||
|
||||
postMessage(forRendererId: string | undefined, message: any) {
|
||||
if (!this._webview || !this._webviewResolved) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (forRendererId === undefined) {
|
||||
this._webview?.webview.postMessage(message);
|
||||
this._webview.webview?.postMessage(message);
|
||||
} else {
|
||||
this._webview?.postRendererMessage(forRendererId, message);
|
||||
this._webview.postRendererMessage(forRendererId, message);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1600,13 +1670,13 @@ registerThemingParticipant((theme, collector) => {
|
||||
collector.addRule(`.notebookOverlay .cell-statusbar-container { border-top: solid 1px ${editorBackgroundColor}; }`);
|
||||
collector.addRule(`.notebookOverlay .monaco-list-row > .monaco-toolbar { background-color: ${editorBackgroundColor}; }`);
|
||||
collector.addRule(`.notebookOverlay .monaco-list-row.cell-drag-image { background-color: ${editorBackgroundColor}; }`);
|
||||
collector.addRule(`.notebookOverlay .cell-bottom-toolbar-container .action-item { background-color: ${editorBackgroundColor} }`);
|
||||
}
|
||||
|
||||
const cellToolbarSeperator = theme.getColor(CELL_TOOLBAR_SEPERATOR);
|
||||
if (cellToolbarSeperator) {
|
||||
collector.addRule(`.notebookOverlay .cell-bottom-toolbar-container .separator { background-color: ${cellToolbarSeperator} }`);
|
||||
collector.addRule(`.notebookOverlay .cell-bottom-toolbar-container .action-item:first-child::after { background-color: ${cellToolbarSeperator} }`);
|
||||
collector.addRule(`.notebookOverlay .monaco-list-row > .monaco-toolbar { border: solid 1px ${cellToolbarSeperator}; }`);
|
||||
collector.addRule(`.notebookOverlay .cell-bottom-toolbar-container .action-item { border: solid 1px ${cellToolbarSeperator} }`);
|
||||
}
|
||||
|
||||
const focusedCellBackgroundColor = theme.getColor(focusedCellBackground);
|
||||
@@ -1643,14 +1713,10 @@ registerThemingParticipant((theme, collector) => {
|
||||
collector.addRule(`.notebookOverlay .monaco-list-row.cell-editor-focus .cell-editor-part:before { outline: solid 1px ${focusedEditorBorderColorColor}; }`);
|
||||
}
|
||||
|
||||
const editorBorderColor = theme.getColor(notebookCellBorder);
|
||||
if (editorBorderColor) {
|
||||
collector.addRule(`.notebookOverlay .monaco-list-row .cell-editor-part:before { outline: solid 1px ${editorBorderColor}; }`);
|
||||
}
|
||||
|
||||
const headingBorderColor = theme.getColor(notebookCellBorder);
|
||||
if (headingBorderColor) {
|
||||
collector.addRule(`.notebookOverlay .cell.markdown h1 { border-color: ${headingBorderColor}; }`);
|
||||
const cellBorderColor = theme.getColor(notebookCellBorder);
|
||||
if (cellBorderColor) {
|
||||
collector.addRule(`.notebookOverlay .cell.markdown h1 { border-color: ${cellBorderColor}; }`);
|
||||
collector.addRule(`.notebookOverlay .monaco-list-row .cell-editor-part:before { outline: solid 1px ${cellBorderColor}; }`);
|
||||
}
|
||||
|
||||
const cellStatusSuccessIcon = theme.getColor(cellStatusIconSuccess);
|
||||
@@ -1701,10 +1767,8 @@ registerThemingParticipant((theme, collector) => {
|
||||
collector.addRule(`.notebookOverlay .cell-list-container > .monaco-list > .monaco-scrollable-element > .monaco-list-rows > .monaco-list-row > div.cell.code { margin-left: ${CODE_CELL_LEFT_MARGIN}px; }`);
|
||||
collector.addRule(`.notebookOverlay .cell-list-container > .monaco-list > .monaco-scrollable-element > .monaco-list-rows > .monaco-list-row { padding-top: ${EDITOR_TOP_MARGIN}px; }`);
|
||||
collector.addRule(`.notebookOverlay .cell-list-container > .monaco-list > .monaco-scrollable-element > .monaco-list-rows > .markdown-cell-row { padding-bottom: ${CELL_BOTTOM_MARGIN}px; }`);
|
||||
collector.addRule(`.notebookOverlay .cell-list-container > .monaco-list > .monaco-scrollable-element > .monaco-list-rows > .markdown-cell-row .cell-bottom-toolbar-container { margin-top: ${CELL_BOTTOM_MARGIN}px; }`);
|
||||
collector.addRule(`.notebookOverlay .output { margin: 0px ${CELL_MARGIN}px 0px ${CODE_CELL_LEFT_MARGIN + CELL_RUN_GUTTER}px; }`);
|
||||
collector.addRule(`.notebookOverlay .output { width: calc(100% - ${CODE_CELL_LEFT_MARGIN + CELL_RUN_GUTTER + (CELL_MARGIN * 2)}px); }`);
|
||||
collector.addRule(`.notebookOverlay .cell-bottom-toolbar-container { width: calc(100% - ${CELL_MARGIN * 2 + CELL_RUN_GUTTER}px); margin: 0px ${CELL_MARGIN * 2}px 0px ${CELL_MARGIN + CELL_RUN_GUTTER}px; }`);
|
||||
|
||||
collector.addRule(`.notebookOverlay .cell-list-container > .monaco-list > .monaco-scrollable-element > .monaco-list-rows > .monaco-list-row > div.cell.markdown { padding-left: ${CELL_RUN_GUTTER}px; }`);
|
||||
collector.addRule(`.notebookOverlay .cell .run-button-container { width: ${CELL_RUN_GUTTER}px; }`);
|
||||
|
||||
@@ -219,7 +219,7 @@ export interface INotebookWebviewMessage {
|
||||
let version = 0;
|
||||
export class BackLayerWebView extends Disposable {
|
||||
element: HTMLElement;
|
||||
webview!: WebviewElement;
|
||||
webview: WebviewElement | undefined = undefined;
|
||||
insetMapping: Map<IProcessedOutput, ICachedInset> = new Map();
|
||||
hiddenInsetMapping: Set<IProcessedOutput> = new Set();
|
||||
reversedInsetMapping: Map<string, IProcessedOutput> = new Map();
|
||||
@@ -714,7 +714,7 @@ ${loaderJs}
|
||||
return;
|
||||
}
|
||||
|
||||
this.webview.focus();
|
||||
this.webview?.focus();
|
||||
}
|
||||
|
||||
focusOutput(cellId: string) {
|
||||
@@ -722,7 +722,7 @@ ${loaderJs}
|
||||
return;
|
||||
}
|
||||
|
||||
this.webview.focus();
|
||||
this.webview?.focus();
|
||||
setTimeout(() => { // Need this, or focus decoration is not shown. No clue.
|
||||
this._sendMessageToWebview({
|
||||
type: 'focus-output',
|
||||
@@ -814,6 +814,10 @@ ${loaderJs}
|
||||
}
|
||||
|
||||
private _updatePreloads(resources: IPreloadResource[], source: 'renderer' | 'kernel') {
|
||||
if (!this.webview) {
|
||||
return;
|
||||
}
|
||||
|
||||
const mixedResourceRoots = [...(this.localResourceRootsCache || []), ...this.rendererRootsCache, ...this.kernelRootsCache];
|
||||
|
||||
this.webview.localResourcesRoot = mixedResourceRoots;
|
||||
@@ -830,7 +834,7 @@ ${loaderJs}
|
||||
return;
|
||||
}
|
||||
|
||||
this.webview.postMessage(message);
|
||||
this.webview?.postMessage(message);
|
||||
}
|
||||
|
||||
clearPreloadsCache() {
|
||||
@@ -839,7 +843,7 @@ ${loaderJs}
|
||||
|
||||
dispose() {
|
||||
this._disposed = true;
|
||||
this.webview.dispose();
|
||||
this.webview?.dispose();
|
||||
super.dispose();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,74 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import * as DOM from 'vs/base/browser/dom';
|
||||
import { Action, IAction } from 'vs/base/common/actions';
|
||||
import { BaseActionViewItem, Separator } from 'vs/base/browser/ui/actionbar/actionbar';
|
||||
import { IMenu, IMenuActionOptions, MenuItemAction, SubmenuItemAction } from 'vs/platform/actions/common/actions';
|
||||
import { DisposableStore, IDisposable } from 'vs/base/common/lifecycle';
|
||||
|
||||
export class VerticalSeparator extends Action {
|
||||
static readonly ID = 'vs.actions.verticalSeparator';
|
||||
|
||||
constructor(
|
||||
label?: string
|
||||
) {
|
||||
super(VerticalSeparator.ID, label, label ? 'verticalSeparator text' : 'verticalSeparator');
|
||||
this.checked = false;
|
||||
this.enabled = false;
|
||||
}
|
||||
}
|
||||
|
||||
export class VerticalSeparatorViewItem extends BaseActionViewItem {
|
||||
render(container: HTMLElement) {
|
||||
DOM.addClass(container, 'verticalSeparator');
|
||||
// const iconContainer = DOM.append(container, $('.verticalSeparator'));
|
||||
// DOM.addClasses(iconContainer, 'codicon', 'codicon-chrome-minimize');
|
||||
}
|
||||
}
|
||||
|
||||
export function createAndFillInActionBarActionsWithVerticalSeparators(menu: IMenu, options: IMenuActionOptions | undefined, target: IAction[] | { primary: IAction[]; secondary: IAction[]; }, isPrimaryGroup?: (group: string) => boolean): IDisposable {
|
||||
const groups = menu.getActions(options);
|
||||
// Action bars handle alternative actions on their own so the alternative actions should be ignored
|
||||
fillInActions(groups, target, false, isPrimaryGroup);
|
||||
return asDisposable(groups);
|
||||
}
|
||||
|
||||
function fillInActions(groups: ReadonlyArray<[string, ReadonlyArray<MenuItemAction | SubmenuItemAction>]>, target: IAction[] | { primary: IAction[]; secondary: IAction[]; }, useAlternativeActions: boolean, isPrimaryGroup: (group: string) => boolean = group => group === 'navigation'): void {
|
||||
for (let tuple of groups) {
|
||||
let [group, actions] = tuple;
|
||||
if (useAlternativeActions) {
|
||||
actions = actions.map(a => (a instanceof MenuItemAction) && !!a.alt ? a.alt : a);
|
||||
}
|
||||
|
||||
if (isPrimaryGroup(group)) {
|
||||
const to = Array.isArray<IAction>(target) ? target : target.primary;
|
||||
|
||||
if (to.length > 0) {
|
||||
to.push(new VerticalSeparator());
|
||||
}
|
||||
|
||||
to.push(...actions);
|
||||
} else {
|
||||
const to = Array.isArray<IAction>(target) ? target : target.secondary;
|
||||
|
||||
if (to.length > 0) {
|
||||
to.push(new Separator());
|
||||
}
|
||||
|
||||
to.push(...actions);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function asDisposable(groups: ReadonlyArray<[string, ReadonlyArray<MenuItemAction | SubmenuItemAction>]>): IDisposable {
|
||||
const disposables = new DisposableStore();
|
||||
for (const [, actions] of groups) {
|
||||
for (const action of actions) {
|
||||
disposables.add(action);
|
||||
}
|
||||
}
|
||||
return disposables;
|
||||
}
|
||||
@@ -3,16 +3,12 @@
|
||||
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import { IAction } from 'vs/base/common/actions';
|
||||
import { createAndFillInContextMenuActions } from 'vs/platform/actions/browser/menuEntryActionViewItem';
|
||||
import { IMenu, IMenuService, MenuId } from 'vs/platform/actions/common/actions';
|
||||
import { IContextKeyService } from 'vs/platform/contextkey/common/contextkey';
|
||||
import { IContextMenuService } from 'vs/platform/contextview/browser/contextView';
|
||||
|
||||
export class CellMenus {
|
||||
constructor(
|
||||
@IMenuService private readonly menuService: IMenuService,
|
||||
@IContextMenuService private readonly contextMenuService: IContextMenuService
|
||||
) { }
|
||||
|
||||
getCellTitleMenu(contextKeyService: IContextKeyService): IMenu {
|
||||
@@ -26,11 +22,6 @@ export class CellMenus {
|
||||
private getMenu(menuId: MenuId, contextKeyService: IContextKeyService): IMenu {
|
||||
const menu = this.menuService.createMenu(menuId, contextKeyService);
|
||||
|
||||
const primary: IAction[] = [];
|
||||
const secondary: IAction[] = [];
|
||||
const result = { primary, secondary };
|
||||
|
||||
createAndFillInContextMenuActions(menu, { shouldForwardArgs: true }, result, this.contextMenuService, g => /^inline/.test(g));
|
||||
|
||||
return menu;
|
||||
}
|
||||
|
||||
@@ -36,17 +36,18 @@ import { IInstantiationService } from 'vs/platform/instantiation/common/instanti
|
||||
import { ServiceCollection } from 'vs/platform/instantiation/common/serviceCollection';
|
||||
import { IKeybindingService } from 'vs/platform/keybinding/common/keybinding';
|
||||
import { INotificationService } from 'vs/platform/notification/common/notification';
|
||||
import { BOTTOM_CELL_TOOLBAR_HEIGHT, EDITOR_BOTTOM_PADDING, EDITOR_TOOLBAR_HEIGHT, EDITOR_TOP_MARGIN, EDITOR_TOP_PADDING, CELL_BOTTOM_MARGIN } from 'vs/workbench/contrib/notebook/browser/constants';
|
||||
import { CancelCellAction, ChangeCellLanguageAction, ExecuteCellAction, INotebookCellActionContext, CELL_TITLE_GROUP_ID } from 'vs/workbench/contrib/notebook/browser/contrib/coreActions';
|
||||
import { BaseCellRenderTemplate, CellEditState, CodeCellRenderTemplate, ICellViewModel, INotebookCellList, INotebookEditor, MarkdownCellRenderTemplate, isCodeCellRenderTemplate } from 'vs/workbench/contrib/notebook/browser/notebookBrowser';
|
||||
import { BOTTOM_CELL_TOOLBAR_HEIGHT, CELL_BOTTOM_MARGIN, EDITOR_BOTTOM_PADDING, EDITOR_TOOLBAR_HEIGHT, EDITOR_TOP_MARGIN, EDITOR_TOP_PADDING } from 'vs/workbench/contrib/notebook/browser/constants';
|
||||
import { CancelCellAction, ChangeCellLanguageAction, ExecuteCellAction, INotebookCellActionContext } from 'vs/workbench/contrib/notebook/browser/contrib/coreActions';
|
||||
import { BaseCellRenderTemplate, CellEditState, CodeCellRenderTemplate, ICellViewModel, INotebookCellList, INotebookEditor, isCodeCellRenderTemplate, MarkdownCellRenderTemplate } from 'vs/workbench/contrib/notebook/browser/notebookBrowser';
|
||||
import { CellContextKeyManager } from 'vs/workbench/contrib/notebook/browser/view/renderers/cellContextKeys';
|
||||
import { CellMenus } from 'vs/workbench/contrib/notebook/browser/view/renderers/cellMenus';
|
||||
import { CodeCell } from 'vs/workbench/contrib/notebook/browser/view/renderers/codeCell';
|
||||
import { StatefullMarkdownCell } from 'vs/workbench/contrib/notebook/browser/view/renderers/markdownCell';
|
||||
import { StatefulMarkdownCell } from 'vs/workbench/contrib/notebook/browser/view/renderers/markdownCell';
|
||||
import { CodeCellViewModel } from 'vs/workbench/contrib/notebook/browser/viewModel/codeCellViewModel';
|
||||
import { MarkdownCellViewModel } from 'vs/workbench/contrib/notebook/browser/viewModel/markdownCellViewModel';
|
||||
import { CellViewModel } from 'vs/workbench/contrib/notebook/browser/viewModel/notebookViewModel';
|
||||
import { CellKind, NotebookCellRunState, NotebookCellMetadata } from 'vs/workbench/contrib/notebook/common/notebookCommon';
|
||||
import { CellContextKeyManager } from 'vs/workbench/contrib/notebook/browser/view/renderers/cellContextKeys';
|
||||
import { CellKind, NotebookCellMetadata, NotebookCellRunState } from 'vs/workbench/contrib/notebook/common/notebookCommon';
|
||||
import { VerticalSeparator, createAndFillInActionBarActionsWithVerticalSeparators, VerticalSeparatorViewItem } from './cellActionView';
|
||||
|
||||
const $ = DOM.$;
|
||||
|
||||
@@ -204,9 +205,6 @@ abstract class AbstractCellRenderer {
|
||||
}
|
||||
});
|
||||
|
||||
toolbar.getContainer().style.height = `${BOTTOM_CELL_TOOLBAR_HEIGHT}px`;
|
||||
container.style.height = `${BOTTOM_CELL_TOOLBAR_HEIGHT}px`;
|
||||
|
||||
const cellMenu = this.instantiationService.createInstance(CellMenus);
|
||||
const menu = disposables.add(cellMenu.getCellInsertionMenu(contextKeyService));
|
||||
|
||||
@@ -220,25 +218,28 @@ abstract class AbstractCellRenderer {
|
||||
templateData.betweenCellToolbar.context = context;
|
||||
|
||||
const container = templateData.bottomCellContainer;
|
||||
if (element instanceof CodeCellViewModel) {
|
||||
const bottomToolbarOffset = element.layoutInfo.bottomToolbarOffset;
|
||||
container.style.top = `${bottomToolbarOffset}px`;
|
||||
|
||||
templateData.elementDisposables.add(element.onDidChangeLayout(() => {
|
||||
const bottomToolbarOffset = element.layoutInfo.bottomToolbarOffset;
|
||||
container.style.top = `${bottomToolbarOffset}px`;
|
||||
|
||||
templateData.elementDisposables.add(element.onDidChangeLayout(() => {
|
||||
const bottomToolbarOffset = element.layoutInfo.bottomToolbarOffset;
|
||||
container.style.top = `${bottomToolbarOffset}px`;
|
||||
}));
|
||||
}
|
||||
}));
|
||||
}
|
||||
|
||||
protected createToolbar(container: HTMLElement): ToolBar {
|
||||
const toolbar = new ToolBar(container, this.contextMenuService, {
|
||||
getKeyBinding: action => this.keybindingService.lookupKeybinding(action.id),
|
||||
actionViewItemProvider: action => {
|
||||
if (action instanceof MenuItemAction) {
|
||||
const item = new ContextAwareMenuEntryActionViewItem(action, this.keybindingService, this.notificationService, this.contextMenuService);
|
||||
return item;
|
||||
}
|
||||
|
||||
if (action.id === VerticalSeparator.ID) {
|
||||
return new VerticalSeparatorViewItem(undefined, action);
|
||||
}
|
||||
|
||||
return undefined;
|
||||
}
|
||||
});
|
||||
@@ -249,16 +250,11 @@ abstract class AbstractCellRenderer {
|
||||
private getCellToolbarActions(menu: IMenu): { primary: IAction[], secondary: IAction[] } {
|
||||
const primary: IAction[] = [];
|
||||
const secondary: IAction[] = [];
|
||||
const actions = menu.getActions({ shouldForwardArgs: true });
|
||||
for (let [id, menuActions] of actions) {
|
||||
if (id === CELL_TITLE_GROUP_ID) {
|
||||
primary.push(...menuActions);
|
||||
} else {
|
||||
secondary.push(...menuActions);
|
||||
}
|
||||
}
|
||||
const result = { primary, secondary };
|
||||
|
||||
return { primary, secondary };
|
||||
createAndFillInActionBarActionsWithVerticalSeparators(menu, { shouldForwardArgs: true }, result, g => /^inline/.test(g));
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
protected setupCellToolbarActions(templateData: BaseCellRenderTemplate, disposables: DisposableStore): void {
|
||||
@@ -351,9 +347,7 @@ export class MarkdownCellRenderer extends AbstractCellRenderer implements IListR
|
||||
const foldingIndicator = DOM.append(focusIndicator, DOM.$('.notebook-folding-indicator'));
|
||||
|
||||
const bottomCellContainer = DOM.append(container, $('.cell-bottom-toolbar-container'));
|
||||
DOM.append(bottomCellContainer, $('.separator'));
|
||||
const betweenCellToolbar = disposables.add(this.createBetweenCellToolbar(bottomCellContainer, disposables, contextKeyService));
|
||||
DOM.append(bottomCellContainer, $('.separator'));
|
||||
|
||||
const statusBar = this.instantiationService.createInstance(CellEditorStatusBar, editorPart);
|
||||
const titleMenu = disposables.add(this.cellMenus.getCellTitleMenu(contextKeyService));
|
||||
@@ -439,7 +433,8 @@ export class MarkdownCellRenderer extends AbstractCellRenderer implements IListR
|
||||
|
||||
this.setBetweenCellToolbarContext(templateData, element, toolbarContext);
|
||||
|
||||
const markdownCell = this.instantiationService.createInstance(StatefullMarkdownCell, this.notebookEditor, element, templateData, this.editorOptions.value, this.renderedEditors);
|
||||
const scopedInstaService = this.instantiationService.createChild(new ServiceCollection([IContextKeyService, templateData.contextKeyService]));
|
||||
const markdownCell = scopedInstaService.createInstance(StatefulMarkdownCell, this.notebookEditor, element, templateData, this.editorOptions.value, this.renderedEditors);
|
||||
elementDisposables.add(this.editorOptions.onDidChange(newValue => markdownCell.updateEditorOptions(newValue)));
|
||||
elementDisposables.add(markdownCell);
|
||||
|
||||
@@ -611,6 +606,18 @@ export class CellDragAndDropController extends Disposable {
|
||||
|
||||
private onCellDrop(event: CellDragEvent): void {
|
||||
const draggedCell = this.currentDraggedCell!;
|
||||
let draggedCells: ICellViewModel[] = [draggedCell];
|
||||
|
||||
if (draggedCell.cellKind === CellKind.Markdown) {
|
||||
const currCellIndex = this.notebookEditor.viewModel!.getCellIndex(draggedCell);
|
||||
const nextVisibleCellIndex = this.notebookEditor.viewModel!.getNextVisibleCellIndex(currCellIndex);
|
||||
|
||||
if (nextVisibleCellIndex > currCellIndex + 1) {
|
||||
// folding ;)
|
||||
draggedCells = this.notebookEditor.viewModel!.viewCells.slice(currCellIndex, nextVisibleCellIndex);
|
||||
}
|
||||
}
|
||||
|
||||
this.dragCleanup();
|
||||
|
||||
const isCopy = (event.browserEvent.ctrlKey && !platform.isMacintosh) || (event.browserEvent.altKey && platform.isMacintosh);
|
||||
@@ -625,9 +632,9 @@ export class CellDragAndDropController extends Disposable {
|
||||
}
|
||||
|
||||
if (isCopy) {
|
||||
this.copyCell(draggedCell, event.draggedOverCell, dropDirection);
|
||||
this.copyCells(draggedCells, event.draggedOverCell, dropDirection);
|
||||
} else {
|
||||
this.moveCell(draggedCell, event.draggedOverCell, dropDirection);
|
||||
this.moveCells(draggedCells, event.draggedOverCell, dropDirection);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -673,16 +680,37 @@ export class CellDragAndDropController extends Disposable {
|
||||
}));
|
||||
}
|
||||
|
||||
private async moveCell(draggedCell: ICellViewModel, ontoCell: ICellViewModel, direction: 'above' | 'below') {
|
||||
await this.notebookEditor.moveCell(draggedCell, ontoCell, direction);
|
||||
private async moveCells(draggedCells: ICellViewModel[], ontoCell: ICellViewModel, direction: 'above' | 'below') {
|
||||
const relativeToIndex = this.notebookEditor!.viewModel!.getCellIndex(ontoCell);
|
||||
const newIdx = direction === 'above' ? relativeToIndex : relativeToIndex + 1;
|
||||
|
||||
this.notebookEditor.textModel!.pushStackElement('Move Cells');
|
||||
for (let i = draggedCells.length - 1; i >= 0; i--) {
|
||||
await this.notebookEditor.moveCellToIdx(draggedCells[i], newIdx);
|
||||
}
|
||||
|
||||
this.notebookEditor.textModel!.pushStackElement('Move Cells');
|
||||
}
|
||||
|
||||
private copyCell(draggedCell: ICellViewModel, ontoCell: ICellViewModel, direction: 'above' | 'below') {
|
||||
const editState = draggedCell.editState;
|
||||
const newCell = this.notebookEditor.insertNotebookCell(ontoCell, draggedCell.cellKind, direction, draggedCell.getText());
|
||||
if (newCell) {
|
||||
this.notebookEditor.focusNotebookCell(newCell, editState === CellEditState.Editing ? 'editor' : 'container');
|
||||
private copyCells(draggedCells: ICellViewModel[], ontoCell: ICellViewModel, direction: 'above' | 'below') {
|
||||
this.notebookEditor.textModel!.pushStackElement('Copy Cells');
|
||||
let firstNewCell: ICellViewModel | undefined = undefined;
|
||||
let firstNewCellState: CellEditState = CellEditState.Preview;
|
||||
for (let i = 0; i < draggedCells.length; i++) {
|
||||
const draggedCell = draggedCells[i];
|
||||
const newCell = this.notebookEditor.insertNotebookCell(ontoCell, draggedCell.cellKind, direction, draggedCell.getText());
|
||||
|
||||
if (newCell && !firstNewCell) {
|
||||
firstNewCell = newCell;
|
||||
firstNewCellState = draggedCell.editState;
|
||||
}
|
||||
}
|
||||
|
||||
if (firstNewCell) {
|
||||
this.notebookEditor.focusNotebookCell(firstNewCell, firstNewCellState === CellEditState.Editing ? 'editor' : 'container');
|
||||
}
|
||||
|
||||
this.notebookEditor.textModel!.pushStackElement('Copy Cells');
|
||||
}
|
||||
}
|
||||
|
||||
@@ -912,11 +940,8 @@ export class CodeCellRenderer extends AbstractCellRenderer implements IListRende
|
||||
const focusSinkElement = DOM.append(container, $('.cell-editor-focus-sink'));
|
||||
focusSinkElement.setAttribute('tabindex', '0');
|
||||
const bottomCellContainer = DOM.append(container, $('.cell-bottom-toolbar-container'));
|
||||
DOM.append(bottomCellContainer, $('.separator'));
|
||||
const betweenCellToolbar = this.createBetweenCellToolbar(bottomCellContainer, disposables, contextKeyService);
|
||||
DOM.append(bottomCellContainer, $('.separator'));
|
||||
|
||||
const focusIndicatorBottom = DOM.append(container, $('.cell-focus-indicator.cell-focus-indicator-bottom'));
|
||||
const betweenCellToolbar = this.createBetweenCellToolbar(bottomCellContainer, disposables, contextKeyService);
|
||||
|
||||
const titleMenu = disposables.add(this.cellMenus.getCellTitleMenu(contextKeyService));
|
||||
|
||||
|
||||
@@ -21,7 +21,7 @@ import { ServiceCollection } from 'vs/platform/instantiation/common/serviceColle
|
||||
import { EditorContextKeys } from 'vs/editor/common/editorContextKeys';
|
||||
import { getResizesObserver } from 'vs/workbench/contrib/notebook/browser/view/renderers/sizeObserver';
|
||||
|
||||
export class StatefullMarkdownCell extends Disposable {
|
||||
export class StatefulMarkdownCell extends Disposable {
|
||||
|
||||
private editor: CodeEditorWidget | null = null;
|
||||
private markdownContainer: HTMLElement;
|
||||
@@ -95,7 +95,7 @@ export class StatefullMarkdownCell extends Disposable {
|
||||
|
||||
this._register(viewCell.onDidChangeLayout((e) => {
|
||||
const layoutInfo = this.editor?.getLayoutInfo();
|
||||
if (e.outerWidth && layoutInfo && layoutInfo.width !== viewCell.layoutInfo.editorWidth) {
|
||||
if (e.outerWidth && this.viewCell.editState === CellEditState.Editing && layoutInfo && layoutInfo.width !== viewCell.layoutInfo.editorWidth) {
|
||||
this.onCellEditorWidthChange();
|
||||
} else if (e.totalHeight || e.outerWidth) {
|
||||
this.relayoutCell();
|
||||
|
||||
@@ -8,7 +8,7 @@ import * as UUID from 'vs/base/common/uuid';
|
||||
import * as editorCommon from 'vs/editor/common/editorCommon';
|
||||
import * as model from 'vs/editor/common/model';
|
||||
import { PrefixSumComputer } from 'vs/editor/common/viewModel/prefixSumComputer';
|
||||
import { BOTTOM_CELL_TOOLBAR_HEIGHT, CELL_MARGIN, CELL_RUN_GUTTER, CELL_STATUSBAR_HEIGHT, EDITOR_BOTTOM_PADDING, EDITOR_TOOLBAR_HEIGHT, EDITOR_TOP_MARGIN, EDITOR_TOP_PADDING, CELL_BOTTOM_MARGIN, CODE_CELL_LEFT_MARGIN } from 'vs/workbench/contrib/notebook/browser/constants';
|
||||
import { BOTTOM_CELL_TOOLBAR_HEIGHT, CELL_MARGIN, CELL_RUN_GUTTER, CELL_STATUSBAR_HEIGHT, EDITOR_BOTTOM_PADDING, EDITOR_TOOLBAR_HEIGHT, EDITOR_TOP_MARGIN, EDITOR_TOP_PADDING, CELL_BOTTOM_MARGIN, CODE_CELL_LEFT_MARGIN, BOTTOM_CELL_TOOLBAR_OFFSET } from 'vs/workbench/contrib/notebook/browser/constants';
|
||||
import { CellEditState, CellFindMatch, CodeCellLayoutChangeEvent, CodeCellLayoutInfo, ICellViewModel, NotebookLayoutInfo, CodeCellLayoutState } from 'vs/workbench/contrib/notebook/browser/notebookBrowser';
|
||||
import { NotebookCellTextModel } from 'vs/workbench/contrib/notebook/common/model/notebookCellTextModel';
|
||||
import { CellKind, NotebookCellOutputsSplice, INotebookSearchOptions } from 'vs/workbench/contrib/notebook/common/notebookCommon';
|
||||
@@ -122,7 +122,7 @@ export class CodeCellViewModel extends BaseCellViewModel implements ICellViewMod
|
||||
|
||||
const indicatorHeight = editorHeight + CELL_STATUSBAR_HEIGHT + outputTotalHeight;
|
||||
const outputContainerOffset = EDITOR_TOOLBAR_HEIGHT + EDITOR_TOP_MARGIN + editorHeight + CELL_STATUSBAR_HEIGHT;
|
||||
const bottomToolbarOffset = totalHeight - BOTTOM_CELL_TOOLBAR_HEIGHT;
|
||||
const bottomToolbarOffset = totalHeight - BOTTOM_CELL_TOOLBAR_HEIGHT - BOTTOM_CELL_TOOLBAR_OFFSET;
|
||||
const editorWidth = state.outerWidth !== undefined ? this.computeEditorWidth(state.outerWidth) : this._layoutInfo?.editorWidth;
|
||||
|
||||
this._layoutInfo = {
|
||||
|
||||
@@ -8,7 +8,7 @@ import { Emitter, Event } from 'vs/base/common/event';
|
||||
import * as UUID from 'vs/base/common/uuid';
|
||||
import * as editorCommon from 'vs/editor/common/editorCommon';
|
||||
import * as model from 'vs/editor/common/model';
|
||||
import { BOTTOM_CELL_TOOLBAR_HEIGHT, CELL_MARGIN, CELL_STATUSBAR_HEIGHT, EDITOR_TOP_MARGIN, CELL_BOTTOM_MARGIN, CODE_CELL_LEFT_MARGIN } from 'vs/workbench/contrib/notebook/browser/constants';
|
||||
import { BOTTOM_CELL_TOOLBAR_HEIGHT, CELL_MARGIN, CELL_STATUSBAR_HEIGHT, EDITOR_TOP_MARGIN, CELL_BOTTOM_MARGIN, CODE_CELL_LEFT_MARGIN, BOTTOM_CELL_TOOLBAR_OFFSET } from 'vs/workbench/contrib/notebook/browser/constants';
|
||||
import { CellFindMatch, ICellViewModel, MarkdownCellLayoutChangeEvent, MarkdownCellLayoutInfo, NotebookLayoutInfo } from 'vs/workbench/contrib/notebook/browser/notebookBrowser';
|
||||
import { MarkdownRenderer } from 'vs/workbench/contrib/notebook/browser/view/renderers/mdRenderer';
|
||||
import { BaseCellViewModel } from 'vs/workbench/contrib/notebook/browser/viewModel/baseCellViewModel';
|
||||
@@ -93,13 +93,14 @@ export class MarkdownCellViewModel extends BaseCellViewModel implements ICellVie
|
||||
layoutChange(state: MarkdownCellLayoutChangeEvent) {
|
||||
// recompute
|
||||
const editorWidth = state.outerWidth !== undefined ? this.computeEditorWidth(state.outerWidth) : this._layoutInfo.editorWidth;
|
||||
const totalHeight = state.totalHeight === undefined ? this._layoutInfo.totalHeight : state.totalHeight;
|
||||
|
||||
this._layoutInfo = {
|
||||
fontInfo: state.font || this._layoutInfo.fontInfo,
|
||||
editorWidth,
|
||||
editorHeight: this._editorHeight,
|
||||
bottomToolbarOffset: BOTTOM_CELL_TOOLBAR_HEIGHT,
|
||||
totalHeight: state.totalHeight === undefined ? this._layoutInfo.totalHeight : state.totalHeight
|
||||
bottomToolbarOffset: totalHeight - BOTTOM_CELL_TOOLBAR_HEIGHT - BOTTOM_CELL_TOOLBAR_OFFSET,
|
||||
totalHeight
|
||||
};
|
||||
|
||||
this._onDidChangeLayout.fire(state);
|
||||
@@ -115,6 +116,7 @@ export class MarkdownCellViewModel extends BaseCellViewModel implements ICellVie
|
||||
totalHeight: totalHeight,
|
||||
editorHeight: this._editorHeight
|
||||
};
|
||||
this.layoutChange({});
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -31,7 +31,7 @@ export class InsertCellEdit implements IResourceUndoRedoElement {
|
||||
) {
|
||||
}
|
||||
|
||||
undo(): void | Promise<void> {
|
||||
undo(): void {
|
||||
if (!this.editingDelegate.deleteCell) {
|
||||
throw new Error('Notebook Delete Cell not implemented for Undo/Redo');
|
||||
}
|
||||
@@ -41,7 +41,7 @@ export class InsertCellEdit implements IResourceUndoRedoElement {
|
||||
this.editingDelegate.emitSelections(this.beforedSelections);
|
||||
}
|
||||
}
|
||||
redo(): void | Promise<void> {
|
||||
redo(): void {
|
||||
if (!this.editingDelegate.insertCell) {
|
||||
throw new Error('Notebook Insert Cell not implemented for Undo/Redo');
|
||||
}
|
||||
@@ -70,7 +70,7 @@ export class DeleteCellEdit implements IResourceUndoRedoElement {
|
||||
// this._rawCell.source = [cell.getText()];
|
||||
}
|
||||
|
||||
undo(): void | Promise<void> {
|
||||
undo(): void {
|
||||
if (!this.editingDelegate.insertCell) {
|
||||
throw new Error('Notebook Insert Cell not implemented for Undo/Redo');
|
||||
}
|
||||
@@ -81,7 +81,7 @@ export class DeleteCellEdit implements IResourceUndoRedoElement {
|
||||
}
|
||||
}
|
||||
|
||||
redo(): void | Promise<void> {
|
||||
redo(): void {
|
||||
if (!this.editingDelegate.deleteCell) {
|
||||
throw new Error('Notebook Delete Cell not implemented for Undo/Redo');
|
||||
}
|
||||
@@ -95,7 +95,7 @@ export class DeleteCellEdit implements IResourceUndoRedoElement {
|
||||
|
||||
export class MoveCellEdit implements IResourceUndoRedoElement {
|
||||
type: UndoRedoElementType.Resource = UndoRedoElementType.Resource;
|
||||
label: string = 'Delete Cell';
|
||||
label: string = 'Move Cell';
|
||||
|
||||
constructor(
|
||||
public resource: URI,
|
||||
@@ -107,7 +107,7 @@ export class MoveCellEdit implements IResourceUndoRedoElement {
|
||||
) {
|
||||
}
|
||||
|
||||
undo(): void | Promise<void> {
|
||||
undo(): void {
|
||||
if (!this.editingDelegate.moveCell) {
|
||||
throw new Error('Notebook Move Cell not implemented for Undo/Redo');
|
||||
}
|
||||
@@ -118,7 +118,7 @@ export class MoveCellEdit implements IResourceUndoRedoElement {
|
||||
}
|
||||
}
|
||||
|
||||
redo(): void | Promise<void> {
|
||||
redo(): void {
|
||||
if (!this.editingDelegate.moveCell) {
|
||||
throw new Error('Notebook Move Cell not implemented for Undo/Redo');
|
||||
}
|
||||
@@ -142,7 +142,7 @@ export class SpliceCellsEdit implements IResourceUndoRedoElement {
|
||||
) {
|
||||
}
|
||||
|
||||
undo(): void | Promise<void> {
|
||||
undo(): void {
|
||||
if (!this.editingDelegate.deleteCell || !this.editingDelegate.insertCell) {
|
||||
throw new Error('Notebook Insert/Delete Cell not implemented for Undo/Redo');
|
||||
}
|
||||
@@ -162,7 +162,7 @@ export class SpliceCellsEdit implements IResourceUndoRedoElement {
|
||||
}
|
||||
}
|
||||
|
||||
redo(): void | Promise<void> {
|
||||
redo(): void {
|
||||
if (!this.editingDelegate.deleteCell || !this.editingDelegate.insertCell) {
|
||||
throw new Error('Notebook Insert/Delete Cell not implemented for Undo/Redo');
|
||||
}
|
||||
|
||||
@@ -10,7 +10,7 @@ import { URI } from 'vs/base/common/uri';
|
||||
import { NotebookCellTextModel } from 'vs/workbench/contrib/notebook/common/model/notebookCellTextModel';
|
||||
import { INotebookTextModel, NotebookCellOutputsSplice, NotebookCellTextModelSplice, NotebookDocumentMetadata, NotebookCellMetadata, ICellEditOperation, CellEditType, CellUri, ICellInsertEdit, NotebookCellsChangedEvent, CellKind, IProcessedOutput, notebookDocumentMetadataDefaults, diff, ICellDeleteEdit, NotebookCellsChangeType, ICellDto2, IMainCellDto } from 'vs/workbench/contrib/notebook/common/notebookCommon';
|
||||
import { ITextSnapshot } from 'vs/editor/common/model';
|
||||
import { IUndoRedoService, UndoRedoElementType } from 'vs/platform/undoRedo/common/undoRedo';
|
||||
import { IUndoRedoService, UndoRedoElementType, IUndoRedoElement, IResourceUndoRedoElement } from 'vs/platform/undoRedo/common/undoRedo';
|
||||
import { InsertCellEdit, DeleteCellEdit, MoveCellEdit, SpliceCellsEdit } from 'vs/workbench/contrib/notebook/common/model/cellEdit';
|
||||
import { ITextModelService } from 'vs/editor/common/services/resolverService';
|
||||
|
||||
@@ -66,6 +66,53 @@ export class NotebookTextModelSnapshot implements ITextSnapshot {
|
||||
|
||||
}
|
||||
|
||||
class StackOperation implements IResourceUndoRedoElement {
|
||||
type: UndoRedoElementType.Resource;
|
||||
|
||||
private _operations: IUndoRedoElement[] = [];
|
||||
|
||||
constructor(readonly resource: URI, readonly label: string) {
|
||||
this.type = UndoRedoElementType.Resource;
|
||||
}
|
||||
|
||||
pushEditOperation(element: IUndoRedoElement) {
|
||||
this._operations.push(element);
|
||||
}
|
||||
|
||||
undo(): void {
|
||||
this._operations.reverse().forEach(o => o.undo());
|
||||
}
|
||||
redo(): void | Promise<void> {
|
||||
this._operations.forEach(o => o.redo());
|
||||
}
|
||||
}
|
||||
|
||||
export class NotebookOperationManager {
|
||||
private _pendingStackOperation: StackOperation | null = null;
|
||||
constructor(private _undoService: IUndoRedoService, private _resource: URI) {
|
||||
|
||||
}
|
||||
|
||||
pushStackElement(label: string) {
|
||||
if (this._pendingStackOperation) {
|
||||
this._undoService.pushElement(this._pendingStackOperation);
|
||||
this._pendingStackOperation = null;
|
||||
return;
|
||||
}
|
||||
|
||||
this._pendingStackOperation = new StackOperation(this._resource, label);
|
||||
}
|
||||
|
||||
pushEditOperation(element: IUndoRedoElement) {
|
||||
if (this._pendingStackOperation) {
|
||||
this._pendingStackOperation.pushEditOperation(element);
|
||||
return;
|
||||
}
|
||||
|
||||
this._undoService.pushElement(element);
|
||||
}
|
||||
}
|
||||
|
||||
export class NotebookTextModel extends Disposable implements INotebookTextModel {
|
||||
|
||||
private _cellhandlePool: number = 0;
|
||||
@@ -112,6 +159,8 @@ export class NotebookTextModel extends Disposable implements INotebookTextModel
|
||||
protected readonly _onDidChangeDirty = this._register(new Emitter<void>());
|
||||
readonly onDidChangeDirty = this._onDidChangeDirty.event;
|
||||
|
||||
private _operationManager: NotebookOperationManager;
|
||||
|
||||
constructor(
|
||||
public handle: number,
|
||||
public viewType: string,
|
||||
@@ -122,6 +171,8 @@ export class NotebookTextModel extends Disposable implements INotebookTextModel
|
||||
) {
|
||||
super();
|
||||
this.cells = [];
|
||||
|
||||
this._operationManager = new NotebookOperationManager(this._undoService, uri);
|
||||
}
|
||||
|
||||
get isDirty() {
|
||||
@@ -173,6 +224,10 @@ export class NotebookTextModel extends Disposable implements INotebookTextModel
|
||||
this._increaseVersionId();
|
||||
}
|
||||
|
||||
pushStackElement(label: string) {
|
||||
this._operationManager.pushStackElement(label);
|
||||
}
|
||||
|
||||
$applyEdit(modelVersionId: number, rawEdits: ICellEditOperation[], synchronous: boolean): boolean {
|
||||
if (modelVersionId !== this._versionId) {
|
||||
return false;
|
||||
@@ -255,7 +310,7 @@ export class NotebookTextModel extends Disposable implements INotebookTextModel
|
||||
return [diff[0], deletedCells, diff[2]] as [number, NotebookCellTextModel[], NotebookCellTextModel[]];
|
||||
});
|
||||
|
||||
this._undoService.pushElement(new SpliceCellsEdit(this.uri, undoDiff, {
|
||||
this._operationManager.pushEditOperation(new SpliceCellsEdit(this.uri, undoDiff, {
|
||||
insertCell: this._insertCellDelegate.bind(this),
|
||||
deleteCell: this._deleteCellDelegate.bind(this),
|
||||
emitSelections: this._emitSelectionsDelegate.bind(this)
|
||||
@@ -266,7 +321,7 @@ export class NotebookTextModel extends Disposable implements INotebookTextModel
|
||||
}
|
||||
|
||||
$handleEdit(label: string | undefined, undo: () => void, redo: () => void): void {
|
||||
this._undoService.pushElement({
|
||||
this._operationManager.pushEditOperation({
|
||||
type: UndoRedoElementType.Resource,
|
||||
resource: this.uri,
|
||||
label: label ?? nls.localize('defaultEditLabel', "Edit"),
|
||||
@@ -502,7 +557,7 @@ export class NotebookTextModel extends Disposable implements INotebookTextModel
|
||||
const cell = this.createCellTextModel(source, language, type, [], metadata);
|
||||
|
||||
if (pushUndoStop) {
|
||||
this._undoService.pushElement(new InsertCellEdit(this.uri, index, cell, {
|
||||
this._operationManager.pushEditOperation(new InsertCellEdit(this.uri, index, cell, {
|
||||
insertCell: this._insertCellDelegate.bind(this),
|
||||
deleteCell: this._deleteCellDelegate.bind(this),
|
||||
emitSelections: this._emitSelectionsDelegate.bind(this)
|
||||
@@ -522,7 +577,7 @@ export class NotebookTextModel extends Disposable implements INotebookTextModel
|
||||
|
||||
insertCell2(index: number, cell: NotebookCellTextModel, synchronous: boolean, pushUndoStop: boolean): void {
|
||||
if (pushUndoStop) {
|
||||
this._undoService.pushElement(new InsertCellEdit(this.uri, index, cell, {
|
||||
this._operationManager.pushEditOperation(new InsertCellEdit(this.uri, index, cell, {
|
||||
insertCell: this._insertCellDelegate.bind(this),
|
||||
deleteCell: this._deleteCellDelegate.bind(this),
|
||||
emitSelections: this._emitSelectionsDelegate.bind(this)
|
||||
@@ -536,7 +591,7 @@ export class NotebookTextModel extends Disposable implements INotebookTextModel
|
||||
deleteCell2(index: number, synchronous: boolean, pushUndoStop: boolean, beforeSelections: number[] | undefined, endSelections: number[] | undefined) {
|
||||
const cell = this.cells[index];
|
||||
if (pushUndoStop) {
|
||||
this._undoService.pushElement(new DeleteCellEdit(this.uri, index, cell, {
|
||||
this._operationManager.pushEditOperation(new DeleteCellEdit(this.uri, index, cell, {
|
||||
insertCell: this._insertCellDelegate.bind(this),
|
||||
deleteCell: this._deleteCellDelegate.bind(this),
|
||||
emitSelections: this._emitSelectionsDelegate.bind(this)
|
||||
@@ -553,7 +608,7 @@ export class NotebookTextModel extends Disposable implements INotebookTextModel
|
||||
moveCellToIdx2(index: number, newIdx: number, synchronous: boolean, pushedToUndoStack: boolean, beforeSelections: number[] | undefined, endSelections: number[] | undefined): boolean {
|
||||
const cell = this.cells[index];
|
||||
if (pushedToUndoStack) {
|
||||
this._undoService.pushElement(new MoveCellEdit(this.uri, index, newIdx, {
|
||||
this._operationManager.pushEditOperation(new MoveCellEdit(this.uri, index, newIdx, {
|
||||
moveCell: (fromIndex: number, toIndex: number, beforeSelections: number[] | undefined, endSelections: number[] | undefined) => {
|
||||
this.moveCellToIdx2(fromIndex, toIndex, true, false, beforeSelections, endSelections);
|
||||
},
|
||||
|
||||
@@ -63,6 +63,8 @@ export class TestNotebookEditor implements INotebookEditor {
|
||||
) { }
|
||||
|
||||
multipleKernelsAvailable: boolean = false;
|
||||
onDidChangeAvailableKernels: Event<void> = new Emitter<void>().event;
|
||||
|
||||
|
||||
uri?: URI | undefined;
|
||||
textModel?: NotebookTextModel | undefined;
|
||||
@@ -158,6 +160,10 @@ export class TestNotebookEditor implements INotebookEditor {
|
||||
throw new Error('Method not implemented.');
|
||||
}
|
||||
|
||||
moveCellToIdx(cell: ICellViewModel, index: number): Promise<ICellViewModel | null> {
|
||||
throw new Error('Method not implemented.');
|
||||
}
|
||||
|
||||
moveCell(cell: ICellViewModel, relativeToCell: ICellViewModel, direction: 'above' | 'below'): Promise<ICellViewModel | null> {
|
||||
throw new Error('Method not implemented.');
|
||||
}
|
||||
|
||||
@@ -883,7 +883,7 @@ export abstract class AbstractTaskService extends Disposable implements ITaskSer
|
||||
resolve(undefined);
|
||||
}
|
||||
} else {
|
||||
resolve(this.executeTask(task, resolver));
|
||||
resolve(this.executeTask(task, resolver, runSource));
|
||||
}
|
||||
}).then((value) => {
|
||||
if (runSource === TaskRunSource.User) {
|
||||
@@ -1452,7 +1452,7 @@ export abstract class AbstractTaskService extends Disposable implements ITaskSer
|
||||
};
|
||||
}
|
||||
|
||||
private executeTask(task: Task, resolver: ITaskResolver): Promise<ITaskSummary> {
|
||||
private executeTask(task: Task, resolver: ITaskResolver, runSource?: TaskRunSource): Promise<ITaskSummary> {
|
||||
enum SaveBeforeRunConfigOptions {
|
||||
Always = 'always',
|
||||
Never = 'never',
|
||||
@@ -1464,7 +1464,7 @@ export abstract class AbstractTaskService extends Disposable implements ITaskSer
|
||||
const execTask = async (task: Task, resolver: ITaskResolver): Promise<ITaskSummary> => {
|
||||
return ProblemMatcherRegistry.onReady().then(() => {
|
||||
let executeResult = this.getTaskSystem().run(task, resolver);
|
||||
return this.handleExecuteResult(executeResult);
|
||||
return this.handleExecuteResult(executeResult, runSource);
|
||||
});
|
||||
};
|
||||
|
||||
@@ -1501,7 +1501,7 @@ export abstract class AbstractTaskService extends Disposable implements ITaskSer
|
||||
}
|
||||
}
|
||||
|
||||
private async handleExecuteResult(executeResult: ITaskExecuteResult): Promise<ITaskSummary> {
|
||||
private async handleExecuteResult(executeResult: ITaskExecuteResult, runSource?: TaskRunSource): Promise<ITaskSummary> {
|
||||
if (executeResult.task.taskLoadMessages && executeResult.task.taskLoadMessages.length > 0) {
|
||||
executeResult.task.taskLoadMessages.forEach(loadMessage => {
|
||||
this._outputChannel.append(loadMessage + '\n');
|
||||
@@ -1509,7 +1509,9 @@ export abstract class AbstractTaskService extends Disposable implements ITaskSer
|
||||
this.showOutput();
|
||||
}
|
||||
|
||||
await this.setRecentlyUsedTask(executeResult.task);
|
||||
if (runSource === TaskRunSource.User) {
|
||||
await this.setRecentlyUsedTask(executeResult.task);
|
||||
}
|
||||
if (executeResult.kind === TaskExecuteKind.Active) {
|
||||
let active = executeResult.active;
|
||||
if (active && active.same) {
|
||||
|
||||
@@ -840,6 +840,9 @@ export class TerminalInstance extends Disposable implements ITerminalInstance {
|
||||
setTimeout(() => this.layout(this._timeoutDimension!), 0);
|
||||
}
|
||||
}
|
||||
if (!visible) {
|
||||
this._widgetManager.hideHovers();
|
||||
}
|
||||
}
|
||||
|
||||
public scrollDownLine(): void {
|
||||
|
||||
@@ -110,6 +110,8 @@ export class TerminalViewPane extends ViewPane {
|
||||
} else {
|
||||
this.layoutBody(this._bodyDimensions.height, this._bodyDimensions.width);
|
||||
}
|
||||
} else {
|
||||
this._terminalService.getActiveTab()?.setVisible(false);
|
||||
}
|
||||
}));
|
||||
|
||||
|
||||
@@ -5,11 +5,15 @@
|
||||
|
||||
import { IDisposable } from 'vs/base/common/lifecycle';
|
||||
import { ITerminalWidget } from 'vs/workbench/contrib/terminal/browser/widgets/widgets';
|
||||
import { IHoverService } from 'vs/workbench/services/hover/browser/hover';
|
||||
|
||||
export class TerminalWidgetManager implements IDisposable {
|
||||
private _container: HTMLElement | undefined;
|
||||
private _attached: Map<string, ITerminalWidget> = new Map();
|
||||
|
||||
constructor(@IHoverService private readonly _hoverService: IHoverService) {
|
||||
}
|
||||
|
||||
attachToElement(terminalWrapper: HTMLElement) {
|
||||
if (!this._container) {
|
||||
this._container = document.createElement('div');
|
||||
@@ -25,6 +29,10 @@ export class TerminalWidgetManager implements IDisposable {
|
||||
}
|
||||
}
|
||||
|
||||
hideHovers(): void {
|
||||
this._hoverService.hideHover();
|
||||
}
|
||||
|
||||
attachWidget(widget: ITerminalWidget): IDisposable | undefined {
|
||||
if (!this._container) {
|
||||
return undefined; // {{SQL CARBON EDIT}} strict-null-check
|
||||
|
||||
@@ -16,7 +16,7 @@ import { IEditorService } from 'vs/workbench/services/editor/common/editorServic
|
||||
import { Emitter, Event } from 'vs/base/common/event';
|
||||
import { Disposable, dispose } from 'vs/base/common/lifecycle';
|
||||
import { Codicon } from 'vs/base/common/codicons';
|
||||
import { IUserDataSyncWorkbenchService, getSyncAreaLabel, IUserDataSyncPreview, IUserDataSyncResource, MANUAL_SYNC_VIEW_ID } from 'vs/workbench/services/userDataSync/common/userDataSync';
|
||||
import { IUserDataSyncWorkbenchService, getSyncAreaLabel, IUserDataSyncPreview, IUserDataSyncResource, SYNC_MERGES_VIEW_ID } from 'vs/workbench/services/userDataSync/common/userDataSync';
|
||||
import { isEqual, basename } from 'vs/base/common/resources';
|
||||
import { IDecorationsProvider, IDecorationData, IDecorationsService } from 'vs/workbench/services/decorations/browser/decorations';
|
||||
import { IProgressService } from 'vs/platform/progress/common/progress';
|
||||
@@ -39,7 +39,7 @@ import { registerEditorContribution } from 'vs/editor/browser/editorExtensions';
|
||||
import { Severity } from 'vs/platform/notification/common/notification';
|
||||
import { IDialogService } from 'vs/platform/dialogs/common/dialogs';
|
||||
|
||||
export class UserDataManualSyncViewPane extends TreeViewPane {
|
||||
export class UserDataSyncMergesViewPane extends TreeViewPane {
|
||||
|
||||
private userDataSyncPreview: IUserDataSyncPreview;
|
||||
|
||||
@@ -83,7 +83,7 @@ export class UserDataManualSyncViewPane extends TreeViewPane {
|
||||
this.createButtons(container);
|
||||
|
||||
const that = this;
|
||||
this.treeView.message = localize('explanation', "Please go through each entry and accept the change to enable sync.");
|
||||
this.treeView.message = localize('explanation', "Please go through each entry and merge to enable sync.");
|
||||
this.treeView.dataProvider = { getChildren() { return that.getTreeItems(); } };
|
||||
}
|
||||
|
||||
@@ -164,7 +164,7 @@ export class UserDataManualSyncViewPane extends TreeViewPane {
|
||||
icon: Codicon.cloudDownload,
|
||||
menu: {
|
||||
id: MenuId.ViewItemContext,
|
||||
when: ContextKeyExpr.and(ContextKeyEqualsExpr.create('view', MANUAL_SYNC_VIEW_ID), ContextKeyExpr.equals('viewItem', 'sync-resource-preview')),
|
||||
when: ContextKeyExpr.and(ContextKeyEqualsExpr.create('view', SYNC_MERGES_VIEW_ID), ContextKeyExpr.equals('viewItem', 'sync-resource-preview')),
|
||||
group: 'inline',
|
||||
order: 1,
|
||||
},
|
||||
@@ -184,7 +184,7 @@ export class UserDataManualSyncViewPane extends TreeViewPane {
|
||||
icon: Codicon.cloudUpload,
|
||||
menu: {
|
||||
id: MenuId.ViewItemContext,
|
||||
when: ContextKeyExpr.and(ContextKeyEqualsExpr.create('view', MANUAL_SYNC_VIEW_ID), ContextKeyExpr.equals('viewItem', 'sync-resource-preview')),
|
||||
when: ContextKeyExpr.and(ContextKeyEqualsExpr.create('view', SYNC_MERGES_VIEW_ID), ContextKeyExpr.equals('viewItem', 'sync-resource-preview')),
|
||||
group: 'inline',
|
||||
order: 2,
|
||||
},
|
||||
@@ -204,7 +204,7 @@ export class UserDataManualSyncViewPane extends TreeViewPane {
|
||||
icon: Codicon.merge,
|
||||
menu: {
|
||||
id: MenuId.ViewItemContext,
|
||||
when: ContextKeyExpr.and(ContextKeyEqualsExpr.create('view', MANUAL_SYNC_VIEW_ID), ContextKeyExpr.equals('viewItem', 'sync-resource-preview')),
|
||||
when: ContextKeyExpr.and(ContextKeyEqualsExpr.create('view', SYNC_MERGES_VIEW_ID), ContextKeyExpr.equals('viewItem', 'sync-resource-preview')),
|
||||
group: 'inline',
|
||||
order: 3,
|
||||
},
|
||||
@@ -224,7 +224,7 @@ export class UserDataManualSyncViewPane extends TreeViewPane {
|
||||
icon: Codicon.discard,
|
||||
menu: {
|
||||
id: MenuId.ViewItemContext,
|
||||
when: ContextKeyExpr.and(ContextKeyEqualsExpr.create('view', MANUAL_SYNC_VIEW_ID), ContextKeyExpr.or(ContextKeyExpr.equals('viewItem', 'sync-resource-accepted'), ContextKeyExpr.equals('viewItem', 'sync-resource-conflict'))),
|
||||
when: ContextKeyExpr.and(ContextKeyEqualsExpr.create('view', SYNC_MERGES_VIEW_ID), ContextKeyExpr.or(ContextKeyExpr.equals('viewItem', 'sync-resource-accepted'), ContextKeyExpr.equals('viewItem', 'sync-resource-conflict'))),
|
||||
group: 'inline',
|
||||
order: 3,
|
||||
},
|
||||
@@ -270,7 +270,7 @@ export class UserDataManualSyncViewPane extends TreeViewPane {
|
||||
previewResource = this.userDataSyncPreview.resources.find(({ local }) => isEqual(local, previewResource.local))!;
|
||||
await this.reopen(previewResource);
|
||||
if (previewResource.mergeState === MergeState.Conflict) {
|
||||
await this.dialogService.show(Severity.Warning, localize('conflicts detected', "Conflicts Detected."), [], {
|
||||
await this.dialogService.show(Severity.Warning, localize('conflicts detected', "Conflicts Detected"), [], {
|
||||
detail: localize('resolve', "Unable to merge due to conflicts. Please resolve them to continue.")
|
||||
});
|
||||
}
|
||||
@@ -373,7 +373,7 @@ export class UserDataManualSyncViewPane extends TreeViewPane {
|
||||
}
|
||||
|
||||
private withProgress(task: () => Promise<void>): Promise<void> {
|
||||
return this.progressService.withProgress({ location: MANUAL_SYNC_VIEW_ID, delay: 500 }, task);
|
||||
return this.progressService.withProgress({ location: SYNC_MERGES_VIEW_ID, delay: 500 }, task);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -30,13 +30,13 @@ import { IStorageService } from 'vs/platform/storage/common/storage';
|
||||
import { IWorkspaceContextService } from 'vs/platform/workspace/common/workspace';
|
||||
import { IExtensionService } from 'vs/workbench/services/extensions/common/extensions';
|
||||
import { IAction, Action } from 'vs/base/common/actions';
|
||||
import { IUserDataSyncWorkbenchService, CONTEXT_SYNC_STATE, getSyncAreaLabel, CONTEXT_ACCOUNT_STATE, AccountStatus, CONTEXT_ENABLE_ACTIVITY_VIEWS, SHOW_SYNC_LOG_COMMAND_ID, CONFIGURE_SYNC_COMMAND_ID, MANUAL_SYNC_VIEW_ID, CONTEXT_ENABLE_MANUAL_SYNC_VIEW } from 'vs/workbench/services/userDataSync/common/userDataSync';
|
||||
import { IUserDataSyncWorkbenchService, CONTEXT_SYNC_STATE, getSyncAreaLabel, CONTEXT_ACCOUNT_STATE, AccountStatus, CONTEXT_ENABLE_ACTIVITY_VIEWS, SHOW_SYNC_LOG_COMMAND_ID, CONFIGURE_SYNC_COMMAND_ID, SYNC_MERGES_VIEW_ID, CONTEXT_ENABLE_SYNC_MERGES_VIEW } from 'vs/workbench/services/userDataSync/common/userDataSync';
|
||||
import { IUserDataSyncMachinesService, IUserDataSyncMachine } from 'vs/platform/userDataSync/common/userDataSyncMachines';
|
||||
import { IQuickInputService } from 'vs/platform/quickinput/common/quickInput';
|
||||
import { INotificationService, Severity } from 'vs/platform/notification/common/notification';
|
||||
import { TreeView } from 'vs/workbench/contrib/views/browser/treeView';
|
||||
import { flatten } from 'vs/base/common/arrays';
|
||||
import { UserDataManualSyncViewPane } from 'vs/workbench/contrib/userDataSync/browser/userDataManualSyncView';
|
||||
import { UserDataSyncMergesViewPane } from 'vs/workbench/contrib/userDataSync/browser/userDataSyncMergesView';
|
||||
|
||||
export class UserDataSyncViewPaneContainer extends ViewPaneContainer {
|
||||
|
||||
@@ -86,7 +86,7 @@ export class UserDataSyncDataViews extends Disposable {
|
||||
}
|
||||
|
||||
private registerViews(container: ViewContainer): void {
|
||||
this.registerManualSyncView(container);
|
||||
this.registerMergesView(container);
|
||||
|
||||
this.registerActivityView(container, true);
|
||||
this.registerMachinesView(container);
|
||||
@@ -94,17 +94,17 @@ export class UserDataSyncDataViews extends Disposable {
|
||||
this.registerActivityView(container, false);
|
||||
}
|
||||
|
||||
private registerManualSyncView(container: ViewContainer): void {
|
||||
private registerMergesView(container: ViewContainer): void {
|
||||
const viewsRegistry = Registry.as<IViewsRegistry>(Extensions.ViewsRegistry);
|
||||
const viewName = localize('manual sync', "Manual Sync");
|
||||
const viewName = localize('merges', "Merges");
|
||||
viewsRegistry.registerViews([<ITreeViewDescriptor>{
|
||||
id: MANUAL_SYNC_VIEW_ID,
|
||||
id: SYNC_MERGES_VIEW_ID,
|
||||
name: viewName,
|
||||
ctorDescriptor: new SyncDescriptor(UserDataManualSyncViewPane),
|
||||
when: CONTEXT_ENABLE_MANUAL_SYNC_VIEW,
|
||||
ctorDescriptor: new SyncDescriptor(UserDataSyncMergesViewPane),
|
||||
when: CONTEXT_ENABLE_SYNC_MERGES_VIEW,
|
||||
canToggleVisibility: false,
|
||||
canMoveView: false,
|
||||
treeView: this.instantiationService.createInstance(TreeView, MANUAL_SYNC_VIEW_ID, viewName),
|
||||
treeView: this.instantiationService.createInstance(TreeView, SYNC_MERGES_VIEW_ID, viewName),
|
||||
collapsed: false,
|
||||
order: 100,
|
||||
}], container);
|
||||
|
||||
@@ -49,7 +49,12 @@ export async function openEditorWith(
|
||||
return undefined; // {{SQL CARBON EDIT}} strict-null-checks
|
||||
}
|
||||
|
||||
const overrideToUse = typeof id === 'string' && allEditorOverrides.find(([_, entry]) => entry.id === id);
|
||||
let overrideToUse;
|
||||
if (typeof id === 'string') {
|
||||
overrideToUse = allEditorOverrides.find(([_, entry]) => entry.id === id);
|
||||
} else if (allEditorOverrides.length === 1) {
|
||||
overrideToUse = allEditorOverrides[0];
|
||||
}
|
||||
if (overrideToUse) {
|
||||
return overrideToUse[0].open(input, overrideOptions, group, OpenEditorContext.NEW_EDITOR)?.override;
|
||||
}
|
||||
|
||||
@@ -184,6 +184,7 @@ export class ExtensionHostManager extends Disposable {
|
||||
getProxy: <T>(identifier: ProxyIdentifier<T>): T => this._rpcProtocol!.getProxy(identifier),
|
||||
set: <T, R extends T>(identifier: ProxyIdentifier<T>, instance: R): R => this._rpcProtocol!.set(identifier, instance),
|
||||
assertRegistered: (identifiers: ProxyIdentifier<any>[]): void => this._rpcProtocol!.assertRegistered(identifiers),
|
||||
drain: (): Promise<void> => this._rpcProtocol!.drain(),
|
||||
};
|
||||
|
||||
// Named customers
|
||||
|
||||
@@ -18,6 +18,11 @@ export interface IRPCProtocol {
|
||||
* Assert these identifiers are already registered via `.set`.
|
||||
*/
|
||||
assertRegistered(identifiers: ProxyIdentifier<any>[]): void;
|
||||
|
||||
/**
|
||||
* Wait for the write buffer (if applicable) to become empty.
|
||||
*/
|
||||
drain(): Promise<void>;
|
||||
}
|
||||
|
||||
export class ProxyIdentifier<T> {
|
||||
|
||||
@@ -115,6 +115,13 @@ export class RPCProtocol extends Disposable implements IRPCProtocol {
|
||||
});
|
||||
}
|
||||
|
||||
public drain(): Promise<void> {
|
||||
if (typeof this._protocol.drain === 'function') {
|
||||
return this._protocol.drain();
|
||||
}
|
||||
return Promise.resolve();
|
||||
}
|
||||
|
||||
private _onWillSendRequest(req: number): void {
|
||||
if (this._unacknowledgedCount === 0) {
|
||||
// Since this is the first request we are sending in a while,
|
||||
|
||||
@@ -96,10 +96,10 @@ let onTerminate = function () {
|
||||
nativeExit();
|
||||
};
|
||||
|
||||
function _createExtHostProtocol(): Promise<IMessagePassingProtocol> {
|
||||
function _createExtHostProtocol(): Promise<PersistentProtocol> {
|
||||
if (process.env.VSCODE_EXTHOST_WILL_SEND_SOCKET) {
|
||||
|
||||
return new Promise<IMessagePassingProtocol>((resolve, reject) => {
|
||||
return new Promise<PersistentProtocol>((resolve, reject) => {
|
||||
|
||||
let protocol: PersistentProtocol | null = null;
|
||||
|
||||
@@ -163,7 +163,7 @@ function _createExtHostProtocol(): Promise<IMessagePassingProtocol> {
|
||||
|
||||
const pipeName = process.env.VSCODE_IPC_HOOK_EXTHOST!;
|
||||
|
||||
return new Promise<IMessagePassingProtocol>((resolve, reject) => {
|
||||
return new Promise<PersistentProtocol>((resolve, reject) => {
|
||||
|
||||
const socket = net.createConnection(pipeName, () => {
|
||||
socket.removeListener('error', reject);
|
||||
@@ -203,6 +203,10 @@ async function createExtHostProtocol(): Promise<IMessagePassingProtocol> {
|
||||
protocol.send(msg);
|
||||
}
|
||||
}
|
||||
|
||||
drain(): Promise<void> {
|
||||
return protocol.drain();
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
import { IUserDataSyncService, IAuthenticationProvider, getUserDataSyncStore, isAuthenticationProvider, IUserDataAutoSyncService, SyncResource, IResourcePreview, ISyncResourcePreview, Change, IManualSyncTask } from 'vs/platform/userDataSync/common/userDataSync';
|
||||
import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry';
|
||||
import { registerSingleton } from 'vs/platform/instantiation/common/extensions';
|
||||
import { IUserDataSyncWorkbenchService, IUserDataSyncAccount, AccountStatus, CONTEXT_SYNC_ENABLEMENT, CONTEXT_SYNC_STATE, CONTEXT_ACCOUNT_STATE, SHOW_SYNC_LOG_COMMAND_ID, getSyncAreaLabel, IUserDataSyncPreview, IUserDataSyncResource, CONTEXT_ENABLE_MANUAL_SYNC_VIEW, MANUAL_SYNC_VIEW_ID, CONTEXT_ENABLE_ACTIVITY_VIEWS, SYNC_VIEW_CONTAINER_ID } from 'vs/workbench/services/userDataSync/common/userDataSync';
|
||||
import { IUserDataSyncWorkbenchService, IUserDataSyncAccount, AccountStatus, CONTEXT_SYNC_ENABLEMENT, CONTEXT_SYNC_STATE, CONTEXT_ACCOUNT_STATE, SHOW_SYNC_LOG_COMMAND_ID, getSyncAreaLabel, IUserDataSyncPreview, IUserDataSyncResource, CONTEXT_ENABLE_SYNC_MERGES_VIEW, SYNC_MERGES_VIEW_ID, CONTEXT_ENABLE_ACTIVITY_VIEWS, SYNC_VIEW_CONTAINER_ID } from 'vs/workbench/services/userDataSync/common/userDataSync';
|
||||
import { AuthenticationSession, AuthenticationSessionsChangeEvent } from 'vs/editor/common/modes';
|
||||
import { Disposable, DisposableStore } from 'vs/base/common/lifecycle';
|
||||
import { Emitter, Event } from 'vs/base/common/event';
|
||||
@@ -79,7 +79,7 @@ export class UserDataSyncWorkbenchService extends Disposable implements IUserDat
|
||||
private readonly syncEnablementContext: IContextKey<boolean>;
|
||||
private readonly syncStatusContext: IContextKey<string>;
|
||||
private readonly accountStatusContext: IContextKey<string>;
|
||||
private readonly manualSyncViewEnablementContext: IContextKey<boolean>;
|
||||
private readonly mergesViewEnablementContext: IContextKey<boolean>;
|
||||
private readonly activityViewsEnablementContext: IContextKey<boolean>;
|
||||
|
||||
readonly userDataSyncPreview: UserDataSyncPreview = this._register(new UserDataSyncPreview(this.userDataSyncService));
|
||||
@@ -110,7 +110,7 @@ export class UserDataSyncWorkbenchService extends Disposable implements IUserDat
|
||||
this.syncStatusContext = CONTEXT_SYNC_STATE.bindTo(contextKeyService);
|
||||
this.accountStatusContext = CONTEXT_ACCOUNT_STATE.bindTo(contextKeyService);
|
||||
this.activityViewsEnablementContext = CONTEXT_ENABLE_ACTIVITY_VIEWS.bindTo(contextKeyService);
|
||||
this.manualSyncViewEnablementContext = CONTEXT_ENABLE_MANUAL_SYNC_VIEW.bindTo(contextKeyService);
|
||||
this.mergesViewEnablementContext = CONTEXT_ENABLE_SYNC_MERGES_VIEW.bindTo(contextKeyService);
|
||||
|
||||
if (this.authenticationProviders.length) {
|
||||
|
||||
@@ -302,16 +302,16 @@ export class UserDataSyncWorkbenchService extends Disposable implements IUserDat
|
||||
|
||||
const result = await this.dialogService.show(
|
||||
Severity.Info,
|
||||
localize('preferences sync', "Preferences Sync"),
|
||||
localize('merge or replace', "Merge or Replace"),
|
||||
[
|
||||
localize('merge', "Merge"),
|
||||
localize('replace local', "Replace Local"),
|
||||
localize('sync manually', "Sync Manually..."),
|
||||
localize('merge Manually', "Merge Manually..."),
|
||||
localize('cancel', "Cancel"),
|
||||
],
|
||||
{
|
||||
cancelId: 3,
|
||||
detail: localize('first time sync detail', "It looks like you last synced from another machine.\nWould you like to replace or merge with your data in the cloud or sync manually?"),
|
||||
detail: localize('first time sync detail', "It looks like you last synced from another machine.\nWould you like to merge or replace with your data in the cloud?"),
|
||||
}
|
||||
);
|
||||
switch (result.choice) {
|
||||
@@ -333,18 +333,18 @@ export class UserDataSyncWorkbenchService extends Disposable implements IUserDat
|
||||
const visibleViewContainer = this.viewsService.getVisibleViewContainer(ViewContainerLocation.Sidebar);
|
||||
this.userDataSyncPreview.setManualSyncPreview(task, preview);
|
||||
|
||||
this.manualSyncViewEnablementContext.set(true);
|
||||
this.mergesViewEnablementContext.set(true);
|
||||
await this.waitForActiveSyncViews();
|
||||
await this.viewsService.openView(MANUAL_SYNC_VIEW_ID);
|
||||
await this.viewsService.openView(SYNC_MERGES_VIEW_ID);
|
||||
|
||||
const error = await Event.toPromise(this.userDataSyncPreview.onDidCompleteManualSync);
|
||||
this.userDataSyncPreview.unsetManualSyncPreview();
|
||||
|
||||
this.manualSyncViewEnablementContext.set(false);
|
||||
this.mergesViewEnablementContext.set(false);
|
||||
if (visibleViewContainer) {
|
||||
this.viewsService.openViewContainer(visibleViewContainer.id);
|
||||
} else {
|
||||
const viewContainer = this.viewDescriptorService.getViewContainerByViewId(MANUAL_SYNC_VIEW_ID);
|
||||
const viewContainer = this.viewDescriptorService.getViewContainerByViewId(SYNC_MERGES_VIEW_ID);
|
||||
this.viewsService.closeViewContainer(viewContainer!.id);
|
||||
}
|
||||
|
||||
|
||||
@@ -82,7 +82,7 @@ export const CONTEXT_SYNC_STATE = new RawContextKey<string>('syncStatus', SyncSt
|
||||
export const CONTEXT_SYNC_ENABLEMENT = new RawContextKey<boolean>('syncEnabled', false);
|
||||
export const CONTEXT_ACCOUNT_STATE = new RawContextKey<string>('userDataSyncAccountStatus', AccountStatus.Uninitialized);
|
||||
export const CONTEXT_ENABLE_ACTIVITY_VIEWS = new RawContextKey<boolean>(`enableSyncActivityViews`, false);
|
||||
export const CONTEXT_ENABLE_MANUAL_SYNC_VIEW = new RawContextKey<boolean>(`enableManualSyncView`, false);
|
||||
export const CONTEXT_ENABLE_SYNC_MERGES_VIEW = new RawContextKey<boolean>(`enableSyncMergesView`, false);
|
||||
|
||||
// Commands
|
||||
export const CONFIGURE_SYNC_COMMAND_ID = 'workbench.userDataSync.actions.configure';
|
||||
@@ -90,4 +90,4 @@ export const SHOW_SYNC_LOG_COMMAND_ID = 'workbench.userDataSync.actions.showLog'
|
||||
|
||||
// VIEWS
|
||||
export const SYNC_VIEW_CONTAINER_ID = 'workbench.view.sync';
|
||||
export const MANUAL_SYNC_VIEW_ID = 'workbench.views.manualSyncView';
|
||||
export const SYNC_MERGES_VIEW_ID = 'workbench.views.sync.merges';
|
||||
|
||||
@@ -389,6 +389,9 @@ suite('ExtHostDiagnostics', () => {
|
||||
assertRegistered(): void {
|
||||
|
||||
}
|
||||
drain() {
|
||||
return undefined!;
|
||||
}
|
||||
}, new NullLogService());
|
||||
|
||||
let collection1 = diags.createDiagnosticCollection(nullExtensionDescription.identifier, 'foo');
|
||||
@@ -438,6 +441,9 @@ suite('ExtHostDiagnostics', () => {
|
||||
assertRegistered(): void {
|
||||
|
||||
}
|
||||
drain() {
|
||||
return undefined!;
|
||||
}
|
||||
}, new NullLogService());
|
||||
|
||||
|
||||
|
||||
@@ -15,7 +15,8 @@ suite('ExtHostFileSystemEventService', () => {
|
||||
const protocol: IMainContext = {
|
||||
getProxy: () => { return undefined!; },
|
||||
set: undefined!,
|
||||
assertRegistered: undefined!
|
||||
assertRegistered: undefined!,
|
||||
drain: undefined!
|
||||
};
|
||||
|
||||
const watcher1 = new ExtHostFileSystemEventService(protocol, new NullLogService(), undefined!).createFileSystemWatcher('**/somethingInteresting', false, false, false);
|
||||
|
||||
@@ -298,7 +298,8 @@ suite('ExtHostWorkspace', function () {
|
||||
const protocol: IMainContext = {
|
||||
getProxy: () => { return undefined!; },
|
||||
set: () => { return undefined!; },
|
||||
assertRegistered: () => { }
|
||||
assertRegistered: () => { },
|
||||
drain: () => { return undefined!; },
|
||||
};
|
||||
|
||||
const ws = createExtHostWorkspace(protocol, { id: 'foo', name: 'Test', folders: [] }, new NullLogService());
|
||||
|
||||
@@ -32,6 +32,7 @@ suite('MainThreadDiagnostics', function () {
|
||||
$acceptMarkersChange() { }
|
||||
};
|
||||
}
|
||||
drain(): any { return null; }
|
||||
},
|
||||
markerService,
|
||||
new class extends mock<IUriIdentityService>() {
|
||||
|
||||
@@ -66,6 +66,7 @@ suite('MainThreadHostTreeView', function () {
|
||||
getProxy(): any {
|
||||
return extHostTreeViewsShape;
|
||||
}
|
||||
drain(): any { return null; }
|
||||
}, new TestViewsService(), new TestNotificationService(), testExtensionService, new NullLogService());
|
||||
mainThreadTreeViews.$registerTreeViewDataProvider(testTreeViewId, { showCollapseAll: false, canSelectMany: false });
|
||||
await testExtensionService.whenInstalledExtensionsRegistered();
|
||||
|
||||
@@ -19,7 +19,8 @@ export function SingleProxyRPCProtocol(thing: any): IExtHostContext & IExtHostRp
|
||||
set<T, R extends T>(identifier: ProxyIdentifier<T>, value: R): R {
|
||||
return value;
|
||||
},
|
||||
assertRegistered: undefined!
|
||||
assertRegistered: undefined!,
|
||||
drain: undefined!
|
||||
};
|
||||
}
|
||||
|
||||
@@ -40,6 +41,10 @@ export class TestRPCProtocol implements IExtHostContext, IExtHostRpcService {
|
||||
this._proxies = Object.create(null);
|
||||
}
|
||||
|
||||
drain(): Promise<void> {
|
||||
return Promise.resolve();
|
||||
}
|
||||
|
||||
private get _callCount(): number {
|
||||
return this._callCountValue;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user