Merge branch 'main' into notebook/dev

This commit is contained in:
Johannes Rieken
2021-06-10 11:33:04 +02:00
122 changed files with 2024 additions and 1458 deletions
+13
View File
@@ -104,6 +104,7 @@
"restrictions": [
"assert",
"sinon",
"sinon-test",
"vs/nls",
"**/vs/base/common/**",
"**/vs/base/test/common/**"
@@ -139,6 +140,7 @@
"restrictions": [
"assert",
"sinon",
"sinon-test",
"vs/nls",
"**/vs/base/{common,browser}/**",
"**/vs/base/test/{common,browser}/**"
@@ -212,6 +214,7 @@
"restrictions": [
"assert",
"sinon",
"sinon-test",
"vs/nls",
"**/vs/base/common/**",
"**/vs/base/parts/*/common/**",
@@ -225,6 +228,7 @@
"restrictions": [
"assert",
"sinon",
"sinon-test",
"vs/nls",
"**/vs/base/{common,browser}/**",
"**/vs/base/parts/*/{common,browser}/**",
@@ -289,6 +293,7 @@
"restrictions": [
"assert",
"sinon",
"sinon-test",
"vs/nls",
"**/vs/base/{common,browser}/**",
"**/vs/base/parts/*/{common,browser}/**",
@@ -311,6 +316,7 @@
"restrictions": [
"assert",
"sinon",
"sinon-test",
"vs/nls",
"**/vs/base/common/**",
"**/vs/platform/*/common/**",
@@ -334,6 +340,7 @@
"restrictions": [
"assert",
"sinon",
"sinon-test",
"vs/nls",
"**/vs/base/{common,browser}/**",
"**/vs/platform/*/{common,browser}/**",
@@ -357,6 +364,7 @@
"restrictions": [
"assert",
"sinon",
"sinon-test",
"vs/nls",
"**/vs/base/common/**",
"**/vs/platform/*/common/**",
@@ -383,6 +391,7 @@
"restrictions": [
"assert",
"sinon",
"sinon-test",
"vs/nls",
"**/vs/base/{common,browser}/**",
"**/vs/platform/*/{common,browser}/**",
@@ -397,6 +406,7 @@
"restrictions": [
"assert",
"sinon",
"sinon-test",
"vs/nls",
"**/vs/base/{common,browser}/**",
"**/vs/base/test/{common,browser}/**",
@@ -921,6 +931,7 @@
"**/vs/**",
"assert",
"sinon",
"sinon-test",
"crypto",
"vscode"
]
@@ -952,6 +963,7 @@
"**/vs/**",
"assert",
"sinon",
"sinon-test",
"crypto",
"xterm*"
]
@@ -962,6 +974,7 @@
"**/vs/**",
"assert",
"sinon",
"sinon-test",
"crypto",
"xterm*"
]
+1 -1
View File
@@ -7,7 +7,7 @@
"labels": {
"L10N": {"assign": []},
"VIM": {"assign": []},
"accessibility": { "assign": ["isidorn"]},
"accessibility": { "assign": ["isidorn", "sana-ajani"]},
"api": {"assign": ["jrieken"]},
"api-finalization": {"assign": []},
"api-proposal": {"assign": ["jrieken"]},
+6
View File
@@ -409,5 +409,11 @@
"gjsjohnmurray",
"IllusionMH"
]
},
{
"type": "label",
"name": "*workspace-trust-docs",
"action": "close",
"comment": "This issue appears to be the result of the new workspace trust feature shipped in June 2021. This security-focused feature has major impact on the functionality of VS Code. Due to the volume of issues, we ask that you take some time to review our [comprehensive documentation](https://aka.ms/vscode-workspace-trust) on the feature. If your issue is still not resolved, please let us know."
}
]
+3 -3
View File
@@ -148,9 +148,9 @@ fsevents@~2.3.1:
integrity sha512-YR47Eg4hChJGAB1O3yEAOkGO+rlzutoICGqGo9EZ4lKWokzZRSyIW1QmTzqjtw8MJdj9srP869CuWw/hyzSiBw==
glob-parent@^5.1.1, glob-parent@~5.1.0:
version "5.1.1"
resolved "https://registry.yarnpkg.com/glob-parent/-/glob-parent-5.1.1.tgz#b6c1ef417c4e5663ea498f1c45afac6916bbc229"
integrity sha512-FnI+VGOpnlGHWZxthPGR+QhR78fuiK0sNLkHQv+bL9fQi57lNNdquIbna/WrfROrolq8GK5Ek6BiMwqL/voRYQ==
version "5.1.2"
resolved "https://registry.yarnpkg.com/glob-parent/-/glob-parent-5.1.2.tgz#869832c58034fe68a4093c17dc15e8340d8401c4"
integrity sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==
dependencies:
is-glob "^4.0.1"
+3 -3
View File
@@ -1488,9 +1488,9 @@ node-fetch@^2.6.0:
integrity sha512-V4aYg89jEoVRxRb2fJdAg8FHvI7cEyYdVAh94HH0UIK8oJxUfkjlDQN9RbMx+bEjP7+ggMiFRprSti032Oipxw==
normalize-url@^4.1.0:
version "4.5.0"
resolved "https://registry.yarnpkg.com/normalize-url/-/normalize-url-4.5.0.tgz#453354087e6ca96957bd8f5baf753f5982142129"
integrity sha512-2s47yzUxdexf1OhyRi4Em83iQk0aPvwTddtFz4hnSSw9dCEsLEGf6SwIO8ss/19S9iBb5sJaOuTvTGDeZI00BQ==
version "4.5.1"
resolved "https://registry.yarnpkg.com/normalize-url/-/normalize-url-4.5.1.tgz#0dd90cf1288ee1d1313b87081c9a5932ee48518a"
integrity sha512-9UZCFRHQdNrfTpGg8+1INIg93B6zE0aXMVFkw1WFwvO4SlZywU6aLg5Of0Ap/PgcbSw4LNxvMWXMeugwMCX0AA==
nth-check@~1.0.1:
version "1.0.2"
@@ -11,7 +11,6 @@ export function activate() {
});
const style = document.createElement('style');
style.classList.add('markdown-style');
style.textContent = `
.emptyMarkdownCell::before {
content: "${document.documentElement.style.getPropertyValue('--notebook-cell-markup-empty-content')}";
@@ -134,7 +133,10 @@ export function activate() {
white-space: pre-wrap;
}
`;
document.head.append(style);
const template = document.createElement('template');
template.classList.add('markdown-style');
template.content.appendChild(style);
document.head.appendChild(template);
return {
renderOutputItem: (outputInfo: { text(): string }, element: HTMLElement) => {
@@ -148,8 +150,12 @@ export function activate() {
previewRoot.appendChild(defaultStyles.cloneNode(true));
// And then contributed styles
for (const markdownStyleNode of document.getElementsByClassName('markdown-style')) {
previewRoot.appendChild(markdownStyleNode.cloneNode(true));
for (const element of document.getElementsByClassName('markdown-style')) {
if (element instanceof HTMLTemplateElement) {
previewRoot.appendChild(element.content.cloneNode(true));
} else {
previewRoot.appendChild(element.cloneNode(true));
}
}
previewNode = document.createElement('div');
+7 -3
View File
@@ -18,16 +18,20 @@ export async function activate(ctx: {
link.rel = 'stylesheet';
link.classList.add('markdown-style');
link.href = styleHref;
document.head.append(link);
const style = document.createElement('style');
style.classList.add('markdown-style');
style.textContent = `
.katex-error {
color: var(--vscode-editorError-foreground);
}
`;
document.head.append(style);
// Put Everything into a template
const styleTemplate = document.createElement('template');
styleTemplate.classList.add('markdown-style');
styleTemplate.content.appendChild(style);
styleTemplate.content.appendChild(link);
document.head.appendChild(styleTemplate);
const katex = require('@iktakahiro/markdown-it-katex');
markdownItRenderer.extendMarkdownIt((md: markdownIt.MarkdownIt) => {
@@ -137,7 +137,7 @@ class DiagnosticSettings {
const currentSettings = this.get(language);
const newSettings = f(currentSettings);
this._languageSettings.set(language, newSettings);
return areLanguageDiagnosticSettingsEqual(currentSettings, newSettings);
return !areLanguageDiagnosticSettingsEqual(currentSettings, newSettings);
}
}
@@ -668,8 +668,7 @@ import { assertNoRpc } from '../utils';
});
});
// https://github.com/microsoft/vscode/issues/119826
suite.skip('environmentVariableCollection', () => {
suite('environmentVariableCollection', () => {
test('should have collection variables apply to terminals immediately after setting', (done) => {
// Text to match on before passing the test
const expectedText = [
+6 -4
View File
@@ -1,7 +1,7 @@
{
"name": "code-oss-dev",
"version": "1.58.0",
"distro": "3f43781e788d694f33746808cc5182852222f935",
"distro": "f9acd3d731fc630bf6b665d551d5fa12ce0560e6",
"author": {
"name": "Microsoft Corporation"
},
@@ -103,7 +103,8 @@
"@types/minimist": "^1.2.1",
"@types/mocha": "^8.2.0",
"@types/node": "14.x",
"@types/sinon": "^1.16.36",
"@types/sinon": "^10.0.2",
"@types/sinon-test": "^2.4.2",
"@types/trusted-types": "^1.0.6",
"@types/vscode-windows-registry": "^1.0.0",
"@types/webpack": "^4.41.25",
@@ -183,7 +184,8 @@
"rcedit": "^1.1.0",
"request": "^2.85.0",
"rimraf": "^2.2.8",
"sinon": "^1.17.2",
"sinon": "^11.1.1",
"sinon-test": "^3.1.0",
"source-map": "0.6.1",
"source-map-support": "^0.3.2",
"style-loader": "^1.0.0",
@@ -196,7 +198,7 @@
"vinyl-fs": "^3.0.0",
"vscode-debugprotocol": "1.47.0",
"vscode-nls-dev": "^3.3.1",
"vscode-telemetry-extractor": "^1.7.0",
"vscode-telemetry-extractor": "^1.8.0",
"webpack": "^4.43.0",
"webpack-cli": "^3.3.12",
"webpack-stream": "^5.2.1",
+1 -1
View File
@@ -46,7 +46,7 @@ if %errorlevel% neq 0 exit /b %errorlevel%
:: Tests in the extension host
set ALL_PLATFORMS_API_TESTS_EXTRA_ARGS=--disable-telemetry --crash-reporter-directory=%VSCODECRASHDIR% --no-sandbox --no-cached-data --disable-updates --disable-keytar --disable-extensions --disable-workspace-trust --user-data-dir=%VSCODEUSERDATADIR%
set ALL_PLATFORMS_API_TESTS_EXTRA_ARGS=--disable-telemetry --skip-welcome --crash-reporter-directory=%VSCODECRASHDIR% --no-cached-data --disable-updates --disable-keytar --disable-extensions --disable-workspace-trust --user-data-dir=%VSCODEUSERDATADIR%
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 %ALL_PLATFORMS_API_TESTS_EXTRA_ARGS%
if %errorlevel% neq 0 exit /b %errorlevel%
+1 -1
View File
@@ -62,7 +62,7 @@ after_suite
# Tests in the extension host
ALL_PLATFORMS_API_TESTS_EXTRA_ARGS="--disable-telemetry --crash-reporter-directory=$VSCODECRASHDIR --no-cached-data --disable-updates --disable-keytar --disable-extensions --disable-workspace-trust --user-data-dir=$VSCODEUSERDATADIR"
ALL_PLATFORMS_API_TESTS_EXTRA_ARGS="--disable-telemetry --skip-welcome --crash-reporter-directory=$VSCODECRASHDIR --no-cached-data --disable-updates --disable-keytar --disable-extensions --disable-workspace-trust --user-data-dir=$VSCODEUSERDATADIR"
"$INTEGRATION_TEST_ELECTRON_PATH" $LINUX_EXTRA_ARGS $ROOT/extensions/vscode-api-tests/testWorkspace --enable-proposed-api=vscode.vscode-api-tests --extensionDevelopmentPath=$ROOT/extensions/vscode-api-tests --extensionTestsPath=$ROOT/extensions/vscode-api-tests/out/singlefolder-tests $ALL_PLATFORMS_API_TESTS_EXTRA_ARGS
after_suite
+3 -2
View File
@@ -3,8 +3,9 @@
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import { Disposable } from 'vs/base/common/lifecycle';
import { addDisposableListener } from 'vs/base/browser/dom';
import { Disposable } from 'vs/base/common/lifecycle';
import { Mimes } from 'vs/base/common/mime';
/**
* A helper that will execute a provided function when the provided HTMLElement receives
@@ -70,7 +71,7 @@ export const DataTransfers = {
/**
* Typically transfer type for copy/paste transfers.
*/
TEXT: 'text/plain'
TEXT: Mimes.text
};
export function applyDragImage(event: DragEvent, label: string | null, clazz: string): void {
+13 -14
View File
@@ -4,7 +4,6 @@
*--------------------------------------------------------------------------------------------*/
import * as browser from 'vs/base/browser/browser';
import { domEvent } from 'vs/base/browser/event';
import { IKeyboardEvent, StandardKeyboardEvent } from 'vs/base/browser/keyboardEvent';
import { IMouseEvent, StandardMouseEvent } from 'vs/base/browser/mouseEvent';
import { TimeoutTimer } from 'vs/base/common/async';
@@ -975,8 +974,8 @@ class FocusTracker extends Disposable implements IFocusTracker {
}
};
this._register(domEvent(element, EventType.FOCUS, true)(onFocus));
this._register(domEvent(element, EventType.BLUR, true)(onBlur));
this._register(addDisposableListener(element, EventType.FOCUS, onFocus, true));
this._register(addDisposableListener(element, EventType.BLUR, onBlur, true));
}
refreshState() {
@@ -1480,7 +1479,7 @@ export class ModifierKeyEmitter extends Emitter<IModifierKeyStatus> {
metaKey: false
};
this._subscriptions.add(domEvent(window, 'keydown', true)(e => {
this._subscriptions.add(addDisposableListener(window, 'keydown', e => {
if (e.defaultPrevented) {
return;
}
@@ -1515,9 +1514,9 @@ export class ModifierKeyEmitter extends Emitter<IModifierKeyStatus> {
this._keyStatus.event = e;
this.fire(this._keyStatus);
}
}));
}, true));
this._subscriptions.add(domEvent(window, 'keyup', true)(e => {
this._subscriptions.add(addDisposableListener(window, 'keyup', e => {
if (e.defaultPrevented) {
return;
}
@@ -1547,23 +1546,23 @@ export class ModifierKeyEmitter extends Emitter<IModifierKeyStatus> {
this._keyStatus.event = e;
this.fire(this._keyStatus);
}
}));
}, true));
this._subscriptions.add(domEvent(document.body, 'mousedown', true)(e => {
this._subscriptions.add(addDisposableListener(document.body, 'mousedown', () => {
this._keyStatus.lastKeyPressed = undefined;
}));
}, true));
this._subscriptions.add(domEvent(document.body, 'mouseup', true)(e => {
this._subscriptions.add(addDisposableListener(document.body, 'mouseup', () => {
this._keyStatus.lastKeyPressed = undefined;
}));
}, true));
this._subscriptions.add(domEvent(document.body, 'mousemove', true)(e => {
this._subscriptions.add(addDisposableListener(document.body, 'mousemove', e => {
if (e.buttons) {
this._keyStatus.lastKeyPressed = undefined;
}
}));
}, true));
this._subscriptions.add(domEvent(window, 'blur')(e => {
this._subscriptions.add(addDisposableListener(window, 'blur', () => {
this.resetKeyStatus();
}));
}
+3 -18
View File
@@ -14,24 +14,7 @@ export interface IDomEvent {
(element: EventHandler, type: string, useCapture?: boolean): BaseEvent<unknown>;
}
/**
* @deprecated Use `DomEmitter` instead
*/
export const domEvent: IDomEvent = (element: EventHandler, type: string, useCapture?: boolean) => {
const fn = (e: Event) => emitter.fire(e);
const emitter = new Emitter<Event>({
onFirstListenerAdd: () => {
element.addEventListener(type, fn, useCapture);
},
onLastListenerRemove: () => {
element.removeEventListener(type, fn, useCapture);
}
});
return emitter.event;
};
export interface DOMEventMap extends HTMLElementEventMap {
export interface DOMEventMap extends HTMLElementEventMap, DocumentEventMap {
'-monaco-gesturetap': GestureEvent;
'-monaco-gesturechange': GestureEvent;
'-monaco-gesturestart': GestureEvent;
@@ -47,6 +30,8 @@ export class DomEmitter<K extends keyof DOMEventMap> implements IDisposable {
return this.emitter.event;
}
constructor(element: Document, type: DocumentEventMap, useCapture?: boolean);
constructor(element: EventHandler, type: K, useCapture?: boolean);
constructor(element: EventHandler, type: K, useCapture?: boolean) {
const fn = (e: Event) => this.emitter.fire(e as DOMEventMap[K]);
this.emitter = new Emitter({
+4 -2
View File
@@ -20,7 +20,7 @@ import { resolvePath } from 'vs/base/common/resources';
import { StandardMouseEvent } from 'vs/base/browser/mouseEvent';
import { renderLabelWithIcons } from 'vs/base/browser/ui/iconLabel/iconLabels';
import { Event } from 'vs/base/common/event';
import { domEvent } from 'vs/base/browser/event';
import { DomEmitter } from 'vs/base/browser/event';
export interface MarkedOptions extends marked.MarkedOptions {
baseUrl?: never;
@@ -186,7 +186,9 @@ export function renderMarkdown(markdown: IMarkdownString, options: MarkdownRende
}
if (options.actionHandler) {
options.actionHandler.disposeables.add(Event.any<MouseEvent>(domEvent(element, 'click'), domEvent(element, 'auxclick'))(e => {
const onClick = options.actionHandler.disposeables.add(new DomEmitter(element, 'click'));
const onAuxClick = options.actionHandler.disposeables.add(new DomEmitter(element, 'auxclick'));
options.actionHandler.disposeables.add(Event.any(onClick.event, onAuxClick.event)(e => {
const mouseEvent = new StandardMouseEvent(e);
if (!mouseEvent.leftButton && !mouseEvent.middleButton) {
return;
+6 -7
View File
@@ -7,7 +7,6 @@ import 'vs/css!./dialog';
import * as nls from 'vs/nls';
import { Disposable } from 'vs/base/common/lifecycle';
import { $, hide, show, EventHelper, clearNode, isAncestor, addDisposableListener, EventType } from 'vs/base/browser/dom';
import { domEvent } from 'vs/base/browser/event';
import { StandardKeyboardEvent } from 'vs/base/browser/keyboardEvent';
import { KeyCode, KeyMod } from 'vs/base/common/keyCodes';
import { Color } from 'vs/base/common/color';
@@ -220,7 +219,7 @@ export class Dialog extends Disposable {
});
// Handle keyboard events gloably: Tab, Arrow-Left/Right
this._register(domEvent(window, 'keydown', true)((e: KeyboardEvent) => {
this._register(addDisposableListener(window, 'keydown', e => {
const evt = new StandardKeyboardEvent(e);
if (evt.equals(KeyMod.Alt)) {
@@ -321,9 +320,9 @@ export class Dialog extends Disposable {
} else if (this.options.keyEventProcessor) {
this.options.keyEventProcessor(evt);
}
}));
}, true));
this._register(domEvent(window, 'keyup', true)((e: KeyboardEvent) => {
this._register(addDisposableListener(window, 'keyup', e => {
EventHelper.stop(e, true);
const evt = new StandardKeyboardEvent(e);
@@ -333,10 +332,10 @@ export class Dialog extends Disposable {
checkboxChecked: this.checkbox ? this.checkbox.checked : undefined
});
}
}));
}, true));
// Detect focus out
this._register(domEvent(this.element, 'focusout', false)((e: FocusEvent) => {
this._register(addDisposableListener(this.element, 'focusout', e => {
if (!!e.relatedTarget && !!this.element) {
if (!isAncestor(e.relatedTarget as HTMLElement, this.element)) {
this.focusToReturn = e.relatedTarget as HTMLElement;
@@ -347,7 +346,7 @@ export class Dialog extends Disposable {
}
}
}
}));
}, false));
const spinModifierClassName = 'codicon-modifier-spin';
@@ -6,13 +6,13 @@
import { isFunction, isString } from 'vs/base/common/types';
import * as dom from 'vs/base/browser/dom';
import { IIconLabelMarkdownString } from 'vs/base/browser/ui/iconLabel/iconLabel';
import { IHoverDelegate, IHoverDelegateOptions, IHoverDelegateTarget } from 'vs/base/browser/ui/iconLabel/iconHoverDelegate';
import { IHoverDelegate, IHoverDelegateTarget } from 'vs/base/browser/ui/iconLabel/iconHoverDelegate';
import { CancellationToken, CancellationTokenSource } from 'vs/base/common/cancellation';
import { IDisposable } from 'vs/base/common/lifecycle';
import { DomEmitter } from 'vs/base/browser/event';
import { IDisposable, toDisposable } from 'vs/base/common/lifecycle';
import { HoverPosition } from 'vs/base/browser/ui/hover/hoverWidget';
import { localize } from 'vs/nls';
import { IMarkdownString } from 'vs/base/common/htmlContent';
import { RunOnceScheduler } from 'vs/base/common/async';
export function setupNativeHover(htmlElement: HTMLElement, tooltip: string | IIconLabelMarkdownString | undefined): void {
@@ -32,79 +32,90 @@ export function setupCustomHover(hoverDelegate: IHoverDelegate, htmlElement: HTM
const tooltip = getTooltipForCustom(markdownTooltip);
let hoverOptions: IHoverDelegateOptions | undefined;
let mouseX: number | undefined;
let isHovering = false;
let tokenSource: CancellationTokenSource;
let hoverDisposable: IDisposable | undefined;
let hoverPreparation: IDisposable | undefined;
const mouseOverDomEmitter = new DomEmitter(htmlElement, dom.EventType.MOUSE_OVER, true);
mouseOverDomEmitter.event((e: MouseEvent) => {
if (isHovering) {
let hoverWidget: IDisposable | undefined;
const mouseEnter = (e: MouseEvent) => {
if (hoverPreparation) {
return;
}
tokenSource = new CancellationTokenSource();
function mouseLeaveOrDown(e: MouseEvent): void {
const tokenSource = new CancellationTokenSource();
const mouseLeaveOrDown = (e: MouseEvent) => {
const isMouseDown = e.type === dom.EventType.MOUSE_DOWN;
if (isMouseDown) {
hoverDisposable?.dispose();
hoverDisposable = undefined;
hoverWidget?.dispose();
hoverWidget = undefined;
}
if (isMouseDown || (<any>e).fromElement === htmlElement) {
isHovering = false;
hoverOptions = undefined;
tokenSource.dispose(true);
mouseLeaveDomEmitter.dispose();
mouseDownDomEmitter.dispose();
hoverPreparation?.dispose();
hoverPreparation = undefined;
}
}
const mouseLeaveDomEmitter = new DomEmitter(htmlElement, dom.EventType.MOUSE_LEAVE, true);
mouseLeaveDomEmitter.event(mouseLeaveOrDown);
const mouseDownDomEmitter = new DomEmitter(htmlElement, dom.EventType.MOUSE_DOWN, true);
mouseDownDomEmitter.event(mouseLeaveOrDown);
isHovering = true;
};
const mouseLeaveDomListener = dom.addDisposableListener(htmlElement, dom.EventType.MOUSE_LEAVE, mouseLeaveOrDown, true);
const mouseDownDownListener = dom.addDisposableListener(htmlElement, dom.EventType.MOUSE_DOWN, mouseLeaveOrDown, true);
function mouseMove(e: MouseEvent): void {
mouseX = e.x;
const target: IHoverDelegateTarget = {
targetElements: [htmlElement],
dispose: () => { }
};
let mouseMoveDomListener: IDisposable | undefined;
if (hoverDelegate.placement === undefined || hoverDelegate.placement === 'mouse') {
const mouseMove = (e: MouseEvent) => target.x = e.x + 10;
mouseMoveDomListener = dom.addDisposableListener(htmlElement, dom.EventType.MOUSE_MOVE, mouseMove, true);
}
const mouseMoveDomEmitter = new DomEmitter(htmlElement, dom.EventType.MOUSE_MOVE, true);
mouseMoveDomEmitter.event(mouseMove);
setTimeout(async () => {
if (isHovering && tooltip) {
// Re-use the already computed hover options if they exist.
if (!hoverOptions) {
const target: IHoverDelegateTarget = {
targetElements: [htmlElement],
dispose: () => { }
};
hoverOptions = {
text: localize('iconLabel.loading', "Loading..."),
const showHover = async () => {
if (hoverPreparation) {
const hoverOptions = {
text: localize('iconLabel.loading', "Loading..."),
target,
hoverPosition: HoverPosition.BELOW
};
hoverWidget?.dispose();
hoverWidget = hoverDelegate.showHover(hoverOptions);
const resolvedTooltip = (await tooltip(tokenSource.token)) ?? (!isString(markdownTooltip) ? markdownTooltip.markdownNotSupportedFallback : undefined);
hoverWidget?.dispose();
hoverWidget = undefined;
// awaiting the tooltip could take a while. Make sure we're still preparing to hover.
if (resolvedTooltip && hoverPreparation) {
const hoverOptions = {
text: resolvedTooltip,
target,
showPointer: hoverDelegate.placement === 'element',
hoverPosition: HoverPosition.BELOW
};
hoverDisposable = adjustXAndShowCustomHover(hoverOptions, mouseX, hoverDelegate, isHovering);
const resolvedTooltip = (await tooltip(tokenSource.token)) ?? (!isString(markdownTooltip) ? markdownTooltip.markdownNotSupportedFallback : undefined);
if (resolvedTooltip) {
hoverOptions = {
text: resolvedTooltip,
target,
showPointer: hoverDelegate.placement === 'element',
hoverPosition: HoverPosition.BELOW
};
// awaiting the tooltip could take a while. Make sure we're still hovering.
hoverDisposable = adjustXAndShowCustomHover(hoverOptions, mouseX, hoverDelegate, isHovering);
} else if (hoverDisposable) {
hoverDisposable.dispose();
hoverDisposable = undefined;
}
hoverWidget = hoverDelegate.showHover(hoverOptions);
}
}
mouseMoveDomEmitter.dispose();
}, hoverDelegate.delay);
mouseMoveDomListener?.dispose();
};
const timeout = new RunOnceScheduler(showHover, hoverDelegate.delay);
timeout.schedule();
hoverPreparation = toDisposable(() => {
timeout.dispose();
mouseMoveDomListener?.dispose();
mouseDownDownListener.dispose();
mouseLeaveDomListener.dispose();
tokenSource.dispose(true);
});
};
const mouseOverDomEmitter = dom.addDisposableListener(htmlElement, dom.EventType.MOUSE_OVER, mouseEnter, true);
return toDisposable(() => {
mouseOverDomEmitter.dispose();
hoverPreparation?.dispose();
hoverWidget?.dispose();
});
return mouseOverDomEmitter;
}
@@ -118,13 +129,3 @@ function getTooltipForCustom(markdownTooltip: string | IIconLabelMarkdownString)
return async () => markdown;
}
}
function adjustXAndShowCustomHover(hoverOptions: IHoverDelegateOptions | undefined, mouseX: number | undefined, hoverDelegate: IHoverDelegate, isHovering: boolean): IDisposable | undefined {
if (hoverOptions && isHovering) {
if (mouseX !== undefined && (hoverDelegate.placement === undefined || hoverDelegate.placement === 'mouse')) {
(<IHoverDelegateTarget>hoverOptions.target).x = mouseX + 10;
}
return hoverDelegate.showHover(hoverOptions);
}
return undefined;
}
+4 -3
View File
@@ -21,7 +21,7 @@ import { HistoryNavigator } from 'vs/base/common/history';
import { IHistoryNavigationWidget } from 'vs/base/browser/history';
import { ScrollableElement } from 'vs/base/browser/ui/scrollbar/scrollableElement';
import { ScrollbarVisibility } from 'vs/base/common/scrollable';
import { domEvent } from 'vs/base/browser/event';
import { DomEmitter } from 'vs/base/browser/event';
const $ = dom.$;
@@ -189,13 +189,14 @@ export class InputBox extends Widget {
// from ScrollableElement to DOM
this._register(this.scrollableElement.onScroll(e => this.input.scrollTop = e.scrollTop));
const onSelectionChange = Event.filter(domEvent(document, 'selectionchange'), () => {
const onSelectionChange = this._register(new DomEmitter(document, 'selectionchange'));
const onAnchoredSelectionChange = Event.filter(onSelectionChange.event, () => {
const selection = document.getSelection();
return selection?.anchorNode === wrapper;
});
// from DOM to ScrollableElement
this._register(onSelectionChange(this.updateScrollDimensions, this));
this._register(onAnchoredSelectionChange(this.updateScrollDimensions, this));
this._register(this.onDidHeightChange(this.updateScrollDimensions, this));
} else {
this.input.type = this.options.type || 'text';
+20 -22
View File
@@ -7,7 +7,6 @@ import { getOrDefault } from 'vs/base/common/objects';
import { IDisposable, dispose, Disposable, toDisposable, DisposableStore } from 'vs/base/common/lifecycle';
import { Gesture, EventType as TouchEventType, GestureEvent } from 'vs/base/browser/touch';
import { Event, Emitter } from 'vs/base/common/event';
import { domEvent } from 'vs/base/browser/event';
import { SmoothScrollableElement } from 'vs/base/browser/ui/scrollbar/scrollableElement';
import { ScrollEvent, ScrollbarVisibility, INewScrollDimensions, Scrollable } from 'vs/base/common/scrollable';
import { RangeMap, shift } from './rangeMap';
@@ -21,7 +20,8 @@ import { DataTransfers, StaticDND, IDragAndDropData } from 'vs/base/browser/dnd'
import { disposableTimeout, Delayer } from 'vs/base/common/async';
import { isFirefox } from 'vs/base/browser/browser';
import { IMouseWheelEvent } from 'vs/base/browser/mouseEvent';
import { $, animate, getContentHeight, getContentWidth, getTopLeftOffset, scheduleAtNextAnimationFrame } from 'vs/base/browser/dom';
import { $, addDisposableListener, animate, getContentHeight, getContentWidth, getTopLeftOffset, scheduleAtNextAnimationFrame } from 'vs/base/browser/dom';
import { DomEmitter } from 'vs/base/browser/event';
interface IItem<T> {
readonly id: string;
@@ -339,17 +339,16 @@ export class ListView<T> implements ISpliceable<T>, IDisposable {
container.appendChild(this.domNode);
this.scrollableElement.onScroll(this.onScroll, this, this.disposables);
domEvent(this.rowsContainer, TouchEventType.Change)(e => this.onTouchChange(e as GestureEvent), this, this.disposables);
this.disposables.add(addDisposableListener(this.rowsContainer, TouchEventType.Change, e => this.onTouchChange(e as GestureEvent)));
// Prevent the monaco-scrollable-element from scrolling
// https://github.com/microsoft/vscode/issues/44181
domEvent(this.scrollableElement.getDomNode(), 'scroll')
(e => (e.target as HTMLElement).scrollTop = 0, null, this.disposables);
this.disposables.add(addDisposableListener(this.scrollableElement.getDomNode(), 'scroll', e => (e.target as HTMLElement).scrollTop = 0));
Event.map(domEvent(this.domNode, 'dragover'), e => this.toDragEvent(e))(this.onDragOver, this, this.disposables);
Event.map(domEvent(this.domNode, 'drop'), e => this.toDragEvent(e))(this.onDrop, this, this.disposables);
domEvent(this.domNode, 'dragleave')(this.onDragLeave, this, this.disposables);
domEvent(window, 'dragend')(this.onDragEnd, this, this.disposables);
this.disposables.add(addDisposableListener(this.domNode, 'dragover', e => this.onDragOver(this.toDragEvent(e))));
this.disposables.add(addDisposableListener(this.domNode, 'drop', e => this.onDrop(this.toDragEvent(e))));
this.disposables.add(addDisposableListener(this.domNode, 'dragleave', _ => this.onDragLeave()));
this.disposables.add(addDisposableListener(this.domNode, 'dragend', e => this.onDragEnd(e)));
this.setRowLineHeight = getOrDefault(options, o => o.setRowLineHeight, DefaultOptions.setRowLineHeight);
this.setRowHeight = getOrDefault(options, o => o.setRowHeight, DefaultOptions.setRowHeight);
@@ -775,8 +774,7 @@ export class ListView<T> implements ISpliceable<T>, IDisposable {
item.row.domNode.draggable = !!uri;
if (uri) {
const onDragStart = domEvent(item.row.domNode, 'dragstart');
item.dragStartDisposable = onDragStart(event => this.onDragStart(item.element, uri, event));
item.dragStartDisposable = addDisposableListener(item.row.domNode, 'dragstart', event => this.onDragStart(item.element, uri, event));
}
if (this.horizontalScrolling) {
@@ -890,17 +888,17 @@ export class ListView<T> implements ISpliceable<T>, IDisposable {
// Events
@memoize get onMouseClick(): Event<IListMouseEvent<T>> { return Event.map(domEvent(this.domNode, 'click'), e => this.toMouseEvent(e)); }
@memoize get onMouseDblClick(): Event<IListMouseEvent<T>> { return Event.map(domEvent(this.domNode, 'dblclick'), e => this.toMouseEvent(e)); }
@memoize get onMouseMiddleClick(): Event<IListMouseEvent<T>> { return Event.filter(Event.map(domEvent(this.domNode, 'auxclick'), e => this.toMouseEvent(e as MouseEvent)), e => e.browserEvent.button === 1); }
@memoize get onMouseUp(): Event<IListMouseEvent<T>> { return Event.map(domEvent(this.domNode, 'mouseup'), e => this.toMouseEvent(e)); }
@memoize get onMouseDown(): Event<IListMouseEvent<T>> { return Event.map(domEvent(this.domNode, 'mousedown'), e => this.toMouseEvent(e)); }
@memoize get onMouseOver(): Event<IListMouseEvent<T>> { return Event.map(domEvent(this.domNode, 'mouseover'), e => this.toMouseEvent(e)); }
@memoize get onMouseMove(): Event<IListMouseEvent<T>> { return Event.map(domEvent(this.domNode, 'mousemove'), e => this.toMouseEvent(e)); }
@memoize get onMouseOut(): Event<IListMouseEvent<T>> { return Event.map(domEvent(this.domNode, 'mouseout'), e => this.toMouseEvent(e)); }
@memoize get onContextMenu(): Event<IListMouseEvent<T> | IListGestureEvent<T>> { return Event.any(Event.map(domEvent(this.domNode, 'contextmenu'), e => this.toMouseEvent(e)), Event.map(domEvent(this.domNode, TouchEventType.Contextmenu) as Event<GestureEvent>, e => this.toGestureEvent(e))); }
@memoize get onTouchStart(): Event<IListTouchEvent<T>> { return Event.map(domEvent(this.domNode, 'touchstart'), e => this.toTouchEvent(e)); }
@memoize get onTap(): Event<IListGestureEvent<T>> { return Event.map(domEvent(this.rowsContainer, TouchEventType.Tap), e => this.toGestureEvent(e as GestureEvent)); }
@memoize get onMouseClick(): Event<IListMouseEvent<T>> { return Event.map(this.disposables.add(new DomEmitter(this.domNode, 'click')).event, e => this.toMouseEvent(e)); }
@memoize get onMouseDblClick(): Event<IListMouseEvent<T>> { return Event.map(this.disposables.add(new DomEmitter(this.domNode, 'dblclick')).event, e => this.toMouseEvent(e)); }
@memoize get onMouseMiddleClick(): Event<IListMouseEvent<T>> { return Event.filter(Event.map(this.disposables.add(new DomEmitter(this.domNode, 'auxclick')).event, e => this.toMouseEvent(e as MouseEvent)), e => e.browserEvent.button === 1); }
@memoize get onMouseUp(): Event<IListMouseEvent<T>> { return Event.map(this.disposables.add(new DomEmitter(this.domNode, 'mouseup')).event, e => this.toMouseEvent(e)); }
@memoize get onMouseDown(): Event<IListMouseEvent<T>> { return Event.map(this.disposables.add(new DomEmitter(this.domNode, 'mousedown')).event, e => this.toMouseEvent(e)); }
@memoize get onMouseOver(): Event<IListMouseEvent<T>> { return Event.map(this.disposables.add(new DomEmitter(this.domNode, 'mouseover')).event, e => this.toMouseEvent(e)); }
@memoize get onMouseMove(): Event<IListMouseEvent<T>> { return Event.map(this.disposables.add(new DomEmitter(this.domNode, 'mousemove')).event, e => this.toMouseEvent(e)); }
@memoize get onMouseOut(): Event<IListMouseEvent<T>> { return Event.map(this.disposables.add(new DomEmitter(this.domNode, 'mouseout')).event, e => this.toMouseEvent(e)); }
@memoize get onContextMenu(): Event<IListMouseEvent<T> | IListGestureEvent<T>> { return Event.any(Event.map(this.disposables.add(new DomEmitter(this.domNode, 'contextmenu')).event, e => this.toMouseEvent(e)), Event.map(this.disposables.add(new DomEmitter(this.domNode, TouchEventType.Contextmenu)).event as Event<GestureEvent>, e => this.toGestureEvent(e))); }
@memoize get onTouchStart(): Event<IListTouchEvent<T>> { return Event.map(this.disposables.add(new DomEmitter(this.domNode, 'touchstart')).event, e => this.toTouchEvent(e)); }
@memoize get onTap(): Event<IListGestureEvent<T>> { return Event.map(this.disposables.add(new DomEmitter(this.rowsContainer, TouchEventType.Tap)).event, e => this.toGestureEvent(e as GestureEvent)); }
private toMouseEvent(browserEvent: MouseEvent): IListMouseEvent<T> {
const index = this.getItemIndexFromEventTarget(browserEvent.target || null);
+11 -14
View File
@@ -13,7 +13,7 @@ import { Gesture } from 'vs/base/browser/touch';
import { KeyCode } from 'vs/base/common/keyCodes';
import { StandardKeyboardEvent, IKeyboardEvent } from 'vs/base/browser/keyboardEvent';
import { Event, Emitter, EventBufferer } from 'vs/base/common/event';
import { domEvent, stopEvent } from 'vs/base/browser/event';
import { DomEmitter, stopEvent } from 'vs/base/browser/event';
import { IListVirtualDelegate, IListRenderer, IListEvent, IListContextMenuEvent, IListMouseEvent, IListTouchEvent, IListGestureEvent, IIdentityProvider, IKeyboardNavigationLabelProvider, IListDragAndDrop, IListDragOverReaction, ListError, IKeyboardNavigationDelegate } from './list';
import { ListView, IListViewOptions, IListViewDragAndDrop, IListViewAccessibilityProvider, IListViewOptionsUpdate } from './listView';
import { Color } from 'vs/base/common/color';
@@ -257,7 +257,7 @@ class KeyboardController<T> implements IDisposable {
) {
const multipleSelectionSupport = options.multipleSelectionSupport !== false;
const onKeyDown = Event.chain(domEvent(view.domNode, 'keydown'))
const onKeyDown = Event.chain(this.disposables.add(new DomEmitter(view.domNode, 'keydown')).event)
.filter(e => !isInputElement(e.target as HTMLElement))
.map(e => new StandardKeyboardEvent(e));
@@ -394,7 +394,7 @@ class TypeLabelController<T> implements IDisposable {
return;
}
const onChar = Event.chain(domEvent(this.view.domNode, 'keydown'))
const onChar = Event.chain(this.enabledDisposables.add(new DomEmitter(this.view.domNode, 'keydown')).event)
.filter(e => !isInputElement(e.target as HTMLElement))
.filter(() => this.automaticKeyboardNavigation || this.triggered)
.map(event => new StandardKeyboardEvent(event))
@@ -477,7 +477,7 @@ class DOMFocusController<T> implements IDisposable {
private list: List<T>,
private view: ListView<T>
) {
const onKeyDown = Event.chain(domEvent(view.domNode, 'keydown'))
const onKeyDown = Event.chain(this.disposables.add(new DomEmitter(view.domNode, 'keydown')).event)
.filter(e => !isInputElement(e.target as HTMLElement))
.map(e => new StandardKeyboardEvent(e));
@@ -1184,14 +1184,14 @@ export class List<T> implements ISpliceable<T>, IThemable, IDisposable {
@memoize get onContextMenu(): Event<IListContextMenuEvent<T>> {
let didJustPressContextMenuKey = false;
const fromKeyDown = Event.chain(domEvent(this.view.domNode, 'keydown'))
const fromKeyDown = Event.chain(this.disposables.add(new DomEmitter(this.view.domNode, 'keydown')).event)
.map(e => new StandardKeyboardEvent(e))
.filter(e => didJustPressContextMenuKey = e.keyCode === KeyCode.ContextMenu || (e.shiftKey && e.keyCode === KeyCode.F10))
.map(stopEvent)
.filter(() => false)
.event as Event<any>;
const fromKeyUp = Event.chain(domEvent(this.view.domNode, 'keyup'))
const fromKeyUp = Event.chain(this.disposables.add(new DomEmitter(this.view.domNode, 'keyup')).event)
.forEach(() => didJustPressContextMenuKey = false)
.map(e => new StandardKeyboardEvent(e))
.filter(e => e.keyCode === KeyCode.ContextMenu || (e.shiftKey && e.keyCode === KeyCode.F10))
@@ -1213,12 +1213,12 @@ export class List<T> implements ISpliceable<T>, IThemable, IDisposable {
return Event.any<IListContextMenuEvent<T>>(fromKeyDown, fromKeyUp, fromMouse);
}
get onKeyDown(): Event<KeyboardEvent> { return domEvent(this.view.domNode, 'keydown'); }
get onKeyUp(): Event<KeyboardEvent> { return domEvent(this.view.domNode, 'keyup'); }
get onKeyPress(): Event<KeyboardEvent> { return domEvent(this.view.domNode, 'keypress'); }
@memoize get onKeyDown(): Event<KeyboardEvent> { return this.disposables.add(new DomEmitter(this.view.domNode, 'keydown')).event; }
@memoize get onKeyUp(): Event<KeyboardEvent> { return this.disposables.add(new DomEmitter(this.view.domNode, 'keyup')).event; }
@memoize get onKeyPress(): Event<KeyboardEvent> { return this.disposables.add(new DomEmitter(this.view.domNode, 'keypress')).event; }
readonly onDidFocus: Event<void>;
readonly onDidBlur: Event<void>;
@memoize get onDidFocus(): Event<void> { return Event.signal(this.disposables.add(new DomEmitter(this.view.domNode, 'focus', true)).event); }
@memoize get onDidBlur(): Event<void> { return Event.signal(this.disposables.add(new DomEmitter(this.view.domNode, 'blur', true)).event); }
private readonly _onDidDispose = new Emitter<void>();
readonly onDidDispose: Event<void> = this._onDidDispose.event;
@@ -1277,9 +1277,6 @@ export class List<T> implements ISpliceable<T>, IThemable, IDisposable {
this.disposables.add(this.view);
this.disposables.add(this._onDidDispose);
this.onDidFocus = Event.map(domEvent(this.view.domNode, 'focus', true), () => null!);
this.onDidBlur = Event.map(domEvent(this.view.domNode, 'blur', true), () => null!);
this.disposables.add(new DOMFocusController(this, this.view));
if (typeof _options.keyboardSupport !== 'boolean' || _options.keyboardSupport) {
@@ -14,7 +14,7 @@ import * as arrays from 'vs/base/common/arrays';
import { IContextViewProvider, AnchorPosition } from 'vs/base/browser/ui/contextview/contextview';
import { List } from 'vs/base/browser/ui/list/listWidget';
import { IListVirtualDelegate, IListRenderer, IListEvent } from 'vs/base/browser/ui/list/list';
import { domEvent } from 'vs/base/browser/event';
import { DomEmitter } from 'vs/base/browser/event';
import { ScrollbarVisibility } from 'vs/base/common/scrollable';
import { ISelectBoxDelegate, ISelectOptionItem, ISelectBoxOptions, ISelectBoxStyles, ISelectData } from 'vs/base/browser/ui/selectBox/selectBox';
import { isMacintosh } from 'vs/base/common/platform';
@@ -736,7 +736,8 @@ export class SelectBoxList extends Disposable implements ISelectBoxDelegate, ILi
}
// SetUp list keyboard controller - control navigation, disabled items, focus
const onSelectDropDownKeyDown = Event.chain(domEvent(this.selectDropDownListContainer, 'keydown'))
const onKeyDown = this._register(new DomEmitter(this.selectDropDownListContainer, 'keydown'));
const onSelectDropDownKeyDown = Event.chain(onKeyDown.event)
.filter(() => this.selectList.length > 0)
.map(e => new StandardKeyboardEvent(e));
@@ -752,7 +753,8 @@ export class SelectBoxList extends Disposable implements ISelectBoxDelegate, ILi
// SetUp list mouse controller - control navigation, disabled items, focus
this._register(Event.chain(domEvent(this.selectList.getHTMLElement(), 'mouseup'))
const onMouseUp = this._register(new DomEmitter(this.selectList.getHTMLElement(), 'mouseup'));
this._register(Event.chain(onMouseUp.event)
.filter(() => this.selectList.length > 0)
.on(e => this.onMouseUp(e), this));
+14 -15
View File
@@ -6,10 +6,9 @@
import 'vs/css!./paneview';
import { IDisposable, Disposable, DisposableStore } from 'vs/base/common/lifecycle';
import { Event, Emitter } from 'vs/base/common/event';
import { domEvent } from 'vs/base/browser/event';
import { StandardKeyboardEvent } from 'vs/base/browser/keyboardEvent';
import { KeyCode } from 'vs/base/common/keyCodes';
import { $, append, trackFocus, EventHelper, clearNode } from 'vs/base/browser/dom';
import { $, append, trackFocus, EventHelper, clearNode, addDisposableListener } from 'vs/base/browser/dom';
import { Color, RGBA } from 'vs/base/common/color';
import { SplitView, IView } from './splitview';
import { isFirefox } from 'vs/base/browser/browser';
@@ -17,6 +16,7 @@ import { DataTransfers } from 'vs/base/browser/dnd';
import { Orientation } from 'vs/base/browser/ui/sash/sash';
import { localize } from 'vs/nls';
import { ScrollEvent } from 'vs/base/common/scrollable';
import { DomEmitter } from 'vs/base/browser/event';
export interface IPaneOptions {
minimumBodySize?: number;
@@ -220,8 +220,8 @@ export abstract class Pane extends Disposable implements IView {
this.updateHeader();
const onHeaderKeyDown = Event.chain(domEvent(this.header, 'keydown'))
const onKeyDown = this._register(new DomEmitter(this.header, 'keydown'));
const onHeaderKeyDown = Event.chain(onKeyDown.event)
.map(e => new StandardKeyboardEvent(e));
this._register(onHeaderKeyDown.filter(e => e.keyCode === KeyCode.Enter || e.keyCode === KeyCode.Space)
@@ -233,12 +233,11 @@ export abstract class Pane extends Disposable implements IView {
this._register(onHeaderKeyDown.filter(e => e.keyCode === KeyCode.RightArrow)
.event(() => this.setExpanded(true), null));
this._register(domEvent(this.header, 'click')
(e => {
if (!e.defaultPrevented) {
this.setExpanded(!this.isExpanded());
}
}, null));
this._register(addDisposableListener(this.header, 'click', e => {
if (!e.defaultPrevented) {
this.setExpanded(!this.isExpanded());
}
}));
this.body = append(this.element, $('.pane-body'));
this.renderBody(this.body);
@@ -308,11 +307,11 @@ class PaneDraggable extends Disposable {
super();
pane.draggableElement.draggable = true;
this._register(domEvent(pane.draggableElement, 'dragstart')(this.onDragStart, this));
this._register(domEvent(pane.dropTargetElement, 'dragenter')(this.onDragEnter, this));
this._register(domEvent(pane.dropTargetElement, 'dragleave')(this.onDragLeave, this));
this._register(domEvent(pane.dropTargetElement, 'dragend')(this.onDragEnd, this));
this._register(domEvent(pane.dropTargetElement, 'drop')(this.onDrop, this));
this._register(addDisposableListener(pane.draggableElement, 'dragstart', e => this.onDragStart(e)));
this._register(addDisposableListener(pane.dropTargetElement, 'dragenter', e => this.onDragEnter(e)));
this._register(addDisposableListener(pane.dropTargetElement, 'dragleave', e => this.onDragLeave(e)));
this._register(addDisposableListener(pane.dropTargetElement, 'dragend', e => this.onDragEnd(e)));
this._register(addDisposableListener(pane.dropTargetElement, 'drop', e => this.onDrop(e)));
}
private onDragStart(e: DragEvent): void {
@@ -11,8 +11,7 @@ import { clamp } from 'vs/base/common/numbers';
import { range, pushToStart, pushToEnd } from 'vs/base/common/arrays';
import { Sash, Orientation, ISashEvent as IBaseSashEvent, SashState } from 'vs/base/browser/ui/sash/sash';
import { Color } from 'vs/base/common/color';
import { domEvent } from 'vs/base/browser/event';
import { $, append, scheduleAtNextAnimationFrame } from 'vs/base/browser/dom';
import { $, addDisposableListener, append, scheduleAtNextAnimationFrame } from 'vs/base/browser/dom';
import { SmoothScrollableElement } from 'vs/base/browser/ui/scrollbar/scrollableElement';
import { Scrollable, ScrollbarVisibility, ScrollEvent } from 'vs/base/common/scrollable';
export { Orientation } from 'vs/base/browser/ui/sash/sash';
@@ -488,8 +487,8 @@ export class SplitView<TLayoutContext = undefined> extends Disposable {
// This way, we can press Alt while we resize a sash, macOS style!
const disposable = combinedDisposable(
domEvent(document.body, 'keydown')(e => resetSashDragState(this.sashDragState!.current, e.altKey)),
domEvent(document.body, 'keyup')(() => resetSashDragState(this.sashDragState!.current, false))
addDisposableListener(document.body, 'keydown', e => resetSashDragState(this.sashDragState!.current, e.altKey)),
addDisposableListener(document.body, 'keyup', () => resetSashDragState(this.sashDragState!.current, false))
);
const resetSashDragState = (start: number, alt: boolean) => {
+10 -9
View File
@@ -7,7 +7,7 @@ import 'vs/css!./media/tree';
import { IDisposable, dispose, Disposable, toDisposable, DisposableStore } from 'vs/base/common/lifecycle';
import { IListOptions, List, IListStyles, MouseController, DefaultKeyboardNavigationDelegate, isInputElement, isMonacoEditor } from 'vs/base/browser/ui/list/listWidget';
import { IListVirtualDelegate, IListRenderer, IListMouseEvent, IListContextMenuEvent, IListDragAndDrop, IListDragOverReaction, IKeyboardNavigationLabelProvider, IIdentityProvider, IKeyboardNavigationDelegate } from 'vs/base/browser/ui/list/list';
import { append, $, getDomNodePagePosition, hasParentWithClass, createStyleSheet, clearNode } from 'vs/base/browser/dom';
import { append, $, getDomNodePagePosition, hasParentWithClass, createStyleSheet, clearNode, addDisposableListener } from 'vs/base/browser/dom';
import { Event, Relay, Emitter, EventBufferer } from 'vs/base/common/event';
import { StandardKeyboardEvent } from 'vs/base/browser/keyboardEvent';
import { KeyCode } from 'vs/base/common/keyCodes';
@@ -16,7 +16,7 @@ import { ISpliceable } from 'vs/base/common/sequence';
import { IDragAndDropData, StaticDND, DragAndDropData } from 'vs/base/browser/dnd';
import { range, equals, distinctES6, firstOrDefault } from 'vs/base/common/arrays';
import { ElementsDragAndDropData } from 'vs/base/browser/ui/list/listView';
import { domEvent } from 'vs/base/browser/event';
import { DomEmitter } from 'vs/base/browser/event';
import { fuzzyScore, FuzzyScore } from 'vs/base/common/filters';
import { getVisibleState, isFilterResult } from 'vs/base/browser/ui/tree/indexTreeModel';
import { localize } from 'vs/nls';
@@ -648,7 +648,7 @@ class TypeFilterController<T, TFilterData> implements IDisposable {
) {
this.domNode = $(`.monaco-list-type-filter.${this.positionClassName}`);
this.domNode.draggable = true;
domEvent(this.domNode, 'dragstart')(this.onDragStart, this, this.disposables);
this.disposables.add(addDisposableListener(this.domNode, 'dragstart', () => this.onDragStart()));
this.messageDomNode = append(view.getHTMLElement(), $(`.monaco-list-type-filter-message`));
@@ -661,7 +661,7 @@ class TypeFilterController<T, TFilterData> implements IDisposable {
this.filterOnTypeDomNode.checked = this._filterOnType;
this.filterOnTypeDomNode.tabIndex = -1;
this.updateFilterOnTypeTitleAndIcon();
domEvent(this.filterOnTypeDomNode, 'input')(this.onDidChangeFilterOnType, this, this.disposables);
this.disposables.add(addDisposableListener(this.filterOnTypeDomNode, 'input', () => this.onDidChangeFilterOnType()));
this.clearDomNode = append(controls, $<HTMLInputElement>('button.clear' + treeFilterClearIcon.cssSelector));
this.clearDomNode.tabIndex = -1;
@@ -711,7 +711,8 @@ class TypeFilterController<T, TFilterData> implements IDisposable {
return;
}
const onKeyDown = Event.chain(domEvent(this.view.getHTMLElement(), 'keydown'))
const onRawKeyDown = this.enabledDisposables.add(new DomEmitter(this.view.getHTMLElement(), 'keydown'));
const onKeyDown = Event.chain(onRawKeyDown.event)
.filter(e => !isInputElement(e.target as HTMLElement) || e.target === this.filterOnTypeDomNode)
.filter(e => e.key !== 'Dead' && !/^Media/.test(e.key))
.map(e => new StandardKeyboardEvent(e))
@@ -721,9 +722,9 @@ class TypeFilterController<T, TFilterData> implements IDisposable {
.forEach(e => { e.stopPropagation(); e.preventDefault(); })
.event;
const onClear = domEvent(this.clearDomNode, 'click');
const onClearClick = this.enabledDisposables.add(new DomEmitter(this.clearDomNode, 'click'));
Event.chain(Event.any<MouseEvent | StandardKeyboardEvent>(onKeyDown, onClear))
Event.chain(Event.any<MouseEvent | StandardKeyboardEvent>(onKeyDown, onClearClick.event))
.event(this.onEventOrInput, this, this.enabledDisposables);
this.filter.pattern = '';
@@ -849,8 +850,8 @@ class TypeFilterController<T, TFilterData> implements IDisposable {
this.domNode.classList.add('dragging');
disposables.add(toDisposable(() => this.domNode.classList.remove('dragging')));
domEvent(document, 'dragover')(onDragOver, null, disposables);
domEvent(this.domNode, 'dragend')(onDragEnd, null, disposables);
disposables.add(addDisposableListener(document, 'dragover', e => onDragOver(e)));
disposables.add(addDisposableListener(this.domNode, 'dragend', () => onDragEnd()));
StaticDND.CurrentDragAndDropData = new DragAndDropData('vscode-ui');
disposables.add(toDisposable(() => StaticDND.CurrentDragAndDropData = undefined));
+1 -1
View File
@@ -298,7 +298,7 @@ export class Delayer<T> implements IDisposable {
}
dispose(): void {
this.cancelTimeout();
this.cancel();
}
}
+12 -9
View File
@@ -10,9 +10,12 @@ import { URI } from 'vs/base/common/uri';
import { Schemas } from 'vs/base/common/network';
import { DataUri } from 'vs/base/common/resources';
export const MIME_TEXT = 'text/plain';
export const MIME_BINARY = 'application/octet-stream';
export const MIME_UNKNOWN = 'application/unknown';
export namespace Mimes {
export const text = 'text/plain';
export const binary = 'application/octet-stream';
export const unknown = 'application/unknown';
export const markdown = 'text/markdown';
}
export interface ITextMimeAssociation {
readonly id: string;
@@ -125,7 +128,7 @@ export function guessMimeTypes(resource: URI | null, firstLine?: string): string
}
if (!path) {
return [MIME_UNKNOWN];
return [Mimes.unknown];
}
path = path.toLowerCase();
@@ -135,24 +138,24 @@ export function guessMimeTypes(resource: URI | null, firstLine?: string): string
// 1.) User configured mappings have highest priority
const configuredMime = guessMimeTypeByPath(path, filename, userRegisteredAssociations);
if (configuredMime) {
return [configuredMime, MIME_TEXT];
return [configuredMime, Mimes.text];
}
// 2.) Registered mappings have middle priority
const registeredMime = guessMimeTypeByPath(path, filename, nonUserRegisteredAssociations);
if (registeredMime) {
return [registeredMime, MIME_TEXT];
return [registeredMime, Mimes.text];
}
// 3.) Firstline has lowest priority
if (firstLine) {
const firstlineMime = guessMimeTypeByFirstline(firstLine);
if (firstlineMime) {
return [firstlineMime, MIME_TEXT];
return [firstlineMime, Mimes.text];
}
}
return [MIME_UNKNOWN];
return [Mimes.unknown];
}
function guessMimeTypeByPath(path: string, filename: string, associations: ITextMimeAssociationItem[]): string | null {
@@ -240,7 +243,7 @@ export function isUnspecific(mime: string[] | string): boolean {
}
if (typeof mime === 'string') {
return mime === MIME_BINARY || mime === MIME_TEXT || mime === MIME_UNKNOWN;
return mime === Mimes.binary || mime === Mimes.text || mime === Mimes.unknown;
}
return mime.length === 1 && isUnspecific(mime[0]);
+50 -5
View File
@@ -10,9 +10,54 @@ import { VSBuffer } from 'vs/base/common/buffer';
import * as platform from 'vs/base/common/platform';
import * as process from 'vs/base/common/process';
export const enum SocketCloseEventType {
NodeSocketCloseEvent = 0,
WebSocketCloseEvent = 1
}
export interface NodeSocketCloseEvent {
/**
* The type of the event
*/
readonly type: SocketCloseEventType.NodeSocketCloseEvent;
/**
* `true` if the socket had a transmission error.
*/
readonly hadError: boolean;
/**
* Underlying error.
*/
readonly error: Error | undefined
}
export interface WebSocketCloseEvent {
/**
* The type of the event
*/
readonly type: SocketCloseEventType.WebSocketCloseEvent;
/**
* Returns the WebSocket connection close code provided by the server.
*/
readonly code: number;
/**
* Returns the WebSocket connection close reason provided by the server.
*/
readonly reason: string;
/**
* Returns true if the connection closed cleanly; false otherwise.
*/
readonly wasClean: boolean;
/**
* Underlying event.
*/
readonly event: any | undefined;
}
export type SocketCloseEvent = NodeSocketCloseEvent | WebSocketCloseEvent | undefined;
export interface ISocket extends IDisposable {
onData(listener: (e: VSBuffer) => void): IDisposable;
onClose(listener: () => void): IDisposable;
onClose(listener: (e: SocketCloseEvent) => void): IDisposable;
onEnd(listener: () => void): IDisposable;
write(buffer: VSBuffer): void;
end(): void;
@@ -624,8 +669,8 @@ export class PersistentProtocol implements IMessagePassingProtocol {
private readonly _onDidDispose = new BufferedEmitter<void>();
readonly onDidDispose: Event<void> = this._onDidDispose.event;
private readonly _onSocketClose = new BufferedEmitter<void>();
readonly onSocketClose: Event<void> = this._onSocketClose.event;
private readonly _onSocketClose = new BufferedEmitter<SocketCloseEvent>();
readonly onSocketClose: Event<SocketCloseEvent> = this._onSocketClose.event;
private readonly _onSocketTimeout = new BufferedEmitter<void>();
readonly onSocketTimeout: Event<void> = this._onSocketTimeout.event;
@@ -658,7 +703,7 @@ export class PersistentProtocol implements IMessagePassingProtocol {
this._socketReader = new ProtocolReader(this._socket);
this._socketDisposables.push(this._socketReader);
this._socketDisposables.push(this._socketReader.onMessage(msg => this._receiveMessage(msg)));
this._socketDisposables.push(this._socket.onClose(() => this._onSocketClose.fire()));
this._socketDisposables.push(this._socket.onClose((e) => this._onSocketClose.fire(e)));
if (initialChunk) {
this._socketReader.acceptChunk(initialChunk);
}
@@ -768,7 +813,7 @@ export class PersistentProtocol implements IMessagePassingProtocol {
this._socketReader = new ProtocolReader(this._socket);
this._socketDisposables.push(this._socketReader);
this._socketDisposables.push(this._socketReader.onMessage(msg => this._receiveMessage(msg)));
this._socketDisposables.push(this._socket.onClose(() => this._onSocketClose.fire()));
this._socketDisposables.push(this._socket.onClose((e) => this._onSocketClose.fire(e)));
this._socketReader.acceptChunk(initialDataChunk);
}
+24 -9
View File
@@ -13,7 +13,7 @@ import { tmpdir } from 'os';
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 { ISocket, Protocol, Client, ChunkStream, SocketCloseEvent, SocketCloseEventType } from 'vs/base/parts/ipc/common/ipc.net';
import { onUnexpectedError } from 'vs/base/common/errors';
import { Platform, platform } from 'vs/base/common/platform';
@@ -54,10 +54,17 @@ export class NodeSocket implements ISocket {
};
}
public onClose(listener: () => void): IDisposable {
this.socket.on('close', listener);
public onClose(listener: (e: SocketCloseEvent) => void): IDisposable {
const adapter = (hadError: boolean) => {
listener({
type: SocketCloseEventType.NodeSocketCloseEvent,
hadError: hadError,
error: undefined
});
};
this.socket.on('close', adapter);
return {
dispose: () => this.socket.off('close', listener)
dispose: () => this.socket.off('close', adapter)
};
}
@@ -167,7 +174,7 @@ export class WebSocketNodeSocket extends Disposable implements ISocket {
private readonly _pendingDeflateData: Buffer[] = [];
private readonly _incomingData: ChunkStream;
private readonly _onData = this._register(new Emitter<VSBuffer>());
private readonly _onClose = this._register(new Emitter<void>());
private readonly _onClose = this._register(new Emitter<SocketCloseEvent>());
private _isEnded: boolean = false;
private readonly _state = {
@@ -232,7 +239,11 @@ export class WebSocketNodeSocket extends Disposable implements ISocket {
// zlib errors are fatal, since we have no idea how to recover
console.error(err);
onUnexpectedError(err);
this._onClose.fire();
this._onClose.fire({
type: SocketCloseEventType.NodeSocketCloseEvent,
hadError: true,
error: err
});
});
this._zlibInflate.on('data', (data: Buffer) => {
this._pendingInflateData.push(data);
@@ -251,7 +262,11 @@ export class WebSocketNodeSocket extends Disposable implements ISocket {
// zlib errors are fatal, since we have no idea how to recover
console.error(err);
onUnexpectedError(err);
this._onClose.fire();
this._onClose.fire({
type: SocketCloseEventType.NodeSocketCloseEvent,
hadError: true,
error: err
});
});
this._zlibDeflate.on('data', (data: Buffer) => {
this._pendingDeflateData.push(data);
@@ -263,7 +278,7 @@ export class WebSocketNodeSocket extends Disposable implements ISocket {
this._zlibDeflateFlushWaitingCount = 0;
this._incomingData = new ChunkStream();
this._register(this.socket.onData(data => this._acceptChunk(data)));
this._register(this.socket.onClose(() => this._onClose.fire()));
this._register(this.socket.onClose((e) => this._onClose.fire(e)));
}
public override dispose(): void {
@@ -282,7 +297,7 @@ export class WebSocketNodeSocket extends Disposable implements ISocket {
return this._onData.event(listener);
}
public onClose(listener: () => void): IDisposable {
public onClose(listener: (e: SocketCloseEvent) => void): IDisposable {
return this._onClose.event(listener);
}
File diff suppressed because it is too large Load Diff
+1 -1
View File
@@ -161,7 +161,7 @@ suite('Decorators', () => {
clock.tick(200);
assert.deepStrictEqual(spy.args, [[1], [5]]);
spy.reset();
spy.resetHistory();
t.report(4);
t.report(5);
@@ -11,6 +11,7 @@ import { RunOnceScheduler } from 'vs/base/common/async';
import { Emitter, Event } from 'vs/base/common/event';
import { KeyCode } from 'vs/base/common/keyCodes';
import { Disposable, IDisposable } from 'vs/base/common/lifecycle';
import { Mimes } from 'vs/base/common/mime';
import * as platform from 'vs/base/common/platform';
import * as strings from 'vs/base/common/strings';
import { ITextAreaWrapper, ITypeData, TextAreaState, _debugComposition } from 'vs/editor/browser/controller/textAreaState';
@@ -653,7 +654,7 @@ class ClipboardEventUtils {
if (e.clipboardData) {
e.preventDefault();
const text = e.clipboardData.getData('text/plain');
const text = e.clipboardData.getData(Mimes.text);
let metadata: ClipboardStoredMetadata | null = null;
const rawmetadata = e.clipboardData.getData('vscode-editor-data');
if (typeof rawmetadata === 'string') {
@@ -681,7 +682,7 @@ class ClipboardEventUtils {
public static setTextData(e: ClipboardEvent, text: string, html: string | null | undefined, metadata: ClipboardStoredMetadata): void {
if (e.clipboardData) {
e.clipboardData.setData('text/plain', text);
e.clipboardData.setData(Mimes.text, text);
if (typeof html === 'string') {
e.clipboardData.setData('text/html', html);
}
+2 -1
View File
@@ -10,6 +10,7 @@ import { LanguageConfigurationRegistry } from 'vs/editor/common/modes/languageCo
import { ILanguageExtensionPoint } from 'vs/editor/common/services/modeService';
import { Registry } from 'vs/platform/registry/common/platform';
import { IDisposable } from 'vs/base/common/lifecycle';
import { Mimes } from 'vs/base/common/mime';
// Define extension point ids
export const Extensions = {
@@ -65,7 +66,7 @@ ModesRegistry.registerLanguage({
id: PLAINTEXT_MODE_ID,
extensions: [PLAINTEXT_EXTENSION],
aliases: [nls.localize('plainText.alias', "Plain Text"), 'text'],
mimetypes: ['text/plain']
mimetypes: [Mimes.text]
});
LanguageConfigurationRegistry.register(PLAINTEXT_LANGUAGE_IDENTIFIER, {
brackets: [
@@ -4,7 +4,6 @@
*--------------------------------------------------------------------------------------------*/
import * as dom from 'vs/base/browser/dom';
import { domEvent, stop } from 'vs/base/browser/event';
import * as aria from 'vs/base/browser/ui/aria/aria';
import { DomScrollableElement } from 'vs/base/browser/ui/scrollbar/scrollableElement';
import { Event } from 'vs/base/common/event';
@@ -90,11 +89,15 @@ export class ParameterHintsWidget extends Disposable implements IContentWidget {
const overloads = dom.append(controls, $('.overloads'));
const next = dom.append(controls, $('.button' + ThemeIcon.asCSSSelector(parameterHintsNextIcon)));
const onPreviousClick = stop(domEvent(previous, 'click'));
this._register(onPreviousClick(this.previous, this));
this._register(dom.addDisposableListener(previous, 'click', e => {
dom.EventHelper.stop(e);
this.previous();
}));
const onNextClick = stop(domEvent(next, 'click'));
this._register(onNextClick(this.next, this));
this._register(dom.addDisposableListener(next, 'click', e => {
dom.EventHelper.stop(e);
this.next();
}));
const body = $('.body');
const scrollbar = new DomScrollableElement(body, {});
@@ -26,6 +26,7 @@
/* See https://github.com/microsoft/monaco-editor/issues/2168#issuecomment-780078600 */
.monaco-aria-container {
position: absolute !important;
top: 0; /* avoid being placed underneath a sibling element */
height: 1px;
width: 1px;
margin: -1px;
@@ -35,6 +35,7 @@ import { IModelService } from 'vs/editor/common/services/modelService';
import { ILanguageSelection, IModeService } from 'vs/editor/common/services/modeService';
import { URI } from 'vs/base/common/uri';
import { StandaloneCodeEditorServiceImpl } from 'vs/editor/standalone/browser/standaloneCodeServiceImpl';
import { Mimes } from 'vs/base/common/mime';
/**
* Description of an action contribution
@@ -425,7 +426,7 @@ export class StandaloneEditor extends StandaloneCodeEditor implements IStandalon
let model: ITextModel | null;
if (typeof _model === 'undefined') {
model = createTextModel(modelService, modeService, options.value || '', options.language || 'text/plain', undefined);
model = createTextModel(modelService, modeService, options.value || '', options.language || Mimes.text, undefined);
this._ownsModel = true;
} else {
model = _model;
@@ -4,8 +4,7 @@
*--------------------------------------------------------------------------------------------*/
import 'vs/css!./menuEntryActionViewItem';
import { asCSSUrl, ModifierKeyEmitter } from 'vs/base/browser/dom';
import { domEvent } from 'vs/base/browser/event';
import { addDisposableListener, asCSSUrl, ModifierKeyEmitter } from 'vs/base/browser/dom';
import { IAction, Separator, SubmenuAction } from 'vs/base/common/actions';
import { IDisposable, toDisposable, MutableDisposable, DisposableStore } from 'vs/base/common/lifecycle';
import { localize } from 'vs/nls';
@@ -177,12 +176,12 @@ export class MenuEntryActionViewItem extends ActionViewItem {
}));
}
this._register(domEvent(container, 'mouseleave')(_ => {
this._register(addDisposableListener(container, 'mouseleave', _ => {
mouseOver = false;
updateAltState();
}));
this._register(domEvent(container, 'mouseenter')(e => {
this._register(addDisposableListener(container, 'mouseenter', _ => {
mouseOver = true;
updateAltState();
}));
@@ -14,9 +14,8 @@ import { INotificationService } from 'vs/platform/notification/common/notificati
import { IKeybindingService } from 'vs/platform/keybinding/common/keybinding';
import { IThemeService } from 'vs/platform/theme/common/themeService';
import { IContextMenuDelegate } from 'vs/base/browser/contextmenu';
import { EventType, $, isHTMLElement } from 'vs/base/browser/dom';
import { EventType, $, isHTMLElement, addDisposableListener } from 'vs/base/browser/dom';
import { attachMenuStyler } from 'vs/platform/theme/common/styler';
import { domEvent } from 'vs/base/browser/event';
import { StandardMouseEvent } from 'vs/base/browser/mouseEvent';
import { isPromiseCanceledError } from 'vs/base/common/errors';
@@ -75,7 +74,9 @@ export class ContextMenuHandler {
this.block.style.width = '100%';
this.block.style.height = '100%';
this.block.style.zIndex = '-1';
domEvent(this.block, EventType.MOUSE_DOWN)((e: MouseEvent) => e.stopPropagation());
// TODO@Steven: this is never getting disposed
addDisposableListener(this.block, EventType.MOUSE_DOWN, e => e.stopPropagation());
}
const menuDisposables = new DisposableStore();
@@ -94,8 +95,8 @@ export class ContextMenuHandler {
menu.onDidCancel(() => this.contextViewService.hideContextView(true), null, menuDisposables);
menu.onDidBlur(() => this.contextViewService.hideContextView(true), null, menuDisposables);
domEvent(window, EventType.BLUR)(() => { this.contextViewService.hideContextView(true); }, null, menuDisposables);
domEvent(window, EventType.MOUSE_DOWN)((e: MouseEvent) => {
menuDisposables.add(addDisposableListener(window, EventType.BLUR, () => this.contextViewService.hideContextView(true)));
menuDisposables.add(addDisposableListener(window, EventType.MOUSE_DOWN, (e: MouseEvent) => {
if (e.defaultPrevented) {
return;
}
@@ -117,7 +118,7 @@ export class ContextMenuHandler {
}
this.contextViewService.hideContextView(true);
}, null, menuDisposables);
}));
return combinedDisposable(menuDisposables, menu);
},
@@ -60,6 +60,7 @@ export interface NativeParsedArgs {
'enable-proposed-api'?: string[]; // undefined or array of 1 or more
'open-url'?: boolean;
'skip-release-notes'?: boolean;
'skip-welcome'?: boolean;
'disable-telemetry'?: boolean;
'export-default-configuration'?: string;
'install-source'?: string;
+1
View File
@@ -94,6 +94,7 @@ export const OPTIONS: OptionDescriptions<Required<NativeParsedArgs>> = {
'driver': { type: 'string' },
'logExtensionHostCommunication': { type: 'boolean' },
'skip-release-notes': { type: 'boolean' },
'skip-welcome': { type: 'boolean' },
'disable-telemetry': { type: 'boolean' },
'disable-updates': { type: 'boolean' },
'disable-keytar': { type: 'boolean' },
+3 -2
View File
@@ -6,7 +6,7 @@
import { Event } from 'vs/base/common/event';
import { IOpenerService } from 'vs/platform/opener/common/opener';
import { $, EventHelper, EventLike } from 'vs/base/browser/dom';
import { DomEmitter, domEvent } from 'vs/base/browser/event';
import { DomEmitter } from 'vs/base/browser/event';
import { StandardKeyboardEvent } from 'vs/base/browser/keyboardEvent';
import { KeyCode } from 'vs/base/common/keyCodes';
import { Disposable } from 'vs/base/common/lifecycle';
@@ -67,7 +67,8 @@ export class Link extends Disposable {
}, link.label);
const onClickEmitter = this._register(new DomEmitter(this.el, 'click'));
const onEnterPress = Event.chain(domEvent(this.el, 'keypress'))
const onKeyPress = this._register(new DomEmitter(this.el, 'keypress'));
const onEnterPress = Event.chain(onKeyPress.event)
.map(e => new StandardKeyboardEvent(e))
.filter(e => e.keyCode === KeyCode.Enter)
.event;
@@ -4,7 +4,7 @@
*--------------------------------------------------------------------------------------------*/
import { ISocketFactory, IConnectCallback } from 'vs/platform/remote/common/remoteAgentConnection';
import { ISocket } from 'vs/base/parts/ipc/common/ipc.net';
import { ISocket, SocketCloseEvent, SocketCloseEventType } from 'vs/base/parts/ipc/common/ipc.net';
import { VSBuffer } from 'vs/base/common/buffer';
import { IDisposable, Disposable } from 'vs/base/common/lifecycle';
import { Event, Emitter } from 'vs/base/common/event';
@@ -16,10 +16,29 @@ export interface IWebSocketFactory {
create(url: string): IWebSocket;
}
export interface IWebSocketCloseEvent {
/**
* Returns the WebSocket connection close code provided by the server.
*/
readonly code: number;
/**
* Returns the WebSocket connection close reason provided by the server.
*/
readonly reason: string;
/**
* Returns true if the connection closed cleanly; false otherwise.
*/
readonly wasClean: boolean;
/**
* Underlying event.
*/
readonly event: any | undefined;
}
export interface IWebSocket {
readonly onData: Event<ArrayBuffer>;
readonly onOpen: Event<void>;
readonly onClose: Event<void>;
readonly onClose: Event<IWebSocketCloseEvent | void>;
readonly onError: Event<any>;
send(data: ArrayBuffer | ArrayBufferView): void;
@@ -33,7 +52,7 @@ class BrowserWebSocket extends Disposable implements IWebSocket {
public readonly onOpen: Event<void>;
private readonly _onClose = this._register(new Emitter<void>());
private readonly _onClose = this._register(new Emitter<IWebSocketCloseEvent>());
public readonly onClose = this._onClose.event;
private readonly _onError = this._register(new Emitter<any>());
@@ -135,7 +154,7 @@ class BrowserWebSocket extends Disposable implements IWebSocket {
}
}
this._onClose.fire();
this._onClose.fire({ code: e.code, reason: e.reason, wasClean: e.wasClean, event: e });
}));
this._register(dom.addDisposableListener(this._socket, 'error', sendErrorSoon));
@@ -178,8 +197,21 @@ class BrowserSocket implements ISocket {
return this.socket.onData((data) => listener(VSBuffer.wrap(new Uint8Array(data))));
}
public onClose(listener: () => void): IDisposable {
return this.socket.onClose(listener);
public onClose(listener: (e: SocketCloseEvent) => void): IDisposable {
const adapter = (e: IWebSocketCloseEvent | void) => {
if (typeof e === 'undefined') {
listener(e);
} else {
listener({
type: SocketCloseEventType.WebSocketCloseEvent,
code: e.code,
reason: e.reason,
wasClean: e.wasClean,
event: e.event
});
}
};
return this.socket.onClose(adapter);
}
public onEnd(listener: () => void): IDisposable {
@@ -3,7 +3,7 @@
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import { Client, PersistentProtocol, ISocket, ProtocolConstants } from 'vs/base/parts/ipc/common/ipc.net';
import { Client, PersistentProtocol, ISocket, ProtocolConstants, SocketCloseEventType } from 'vs/base/parts/ipc/common/ipc.net';
import { generateUuid } from 'vs/base/common/uuid';
import { RemoteAgentConnectionContext } from 'vs/platform/remote/common/remoteAgentEnvironment';
import { Disposable, DisposableStore, IDisposable } from 'vs/base/common/lifecycle';
@@ -532,8 +532,28 @@ abstract class PersistentConnection extends Disposable {
this._onDidStateChange.fire(new ConnectionGainEvent(this.reconnectionToken, 0, 0));
this._register(protocol.onSocketClose(() => this._beginReconnecting()));
this._register(protocol.onSocketTimeout(() => this._beginReconnecting()));
this._register(protocol.onSocketClose((e) => {
const logPrefix = commonLogPrefix(this._connectionType, this.reconnectionToken, true);
if (!e) {
this._options.logService.info(`${logPrefix} received socket close event.`);
} else if (e.type === SocketCloseEventType.NodeSocketCloseEvent) {
this._options.logService.info(`${logPrefix} received socket close event (hadError: ${e.hadError}).`);
if (e.error) {
this._options.logService.error(e.error);
}
} else {
this._options.logService.info(`${logPrefix} received socket close event (wasClean: ${e.wasClean}, code: ${e.code}, reason: ${e.reason}).`);
if (e.event) {
this._options.logService.error(e.event);
}
}
this._beginReconnecting();
}));
this._register(protocol.onSocketTimeout(() => {
const logPrefix = commonLogPrefix(this._connectionType, this.reconnectionToken, true);
this._options.logService.trace(`${logPrefix} received socket timeout event.`);
this._beginReconnecting();
}));
PersistentConnection._instances.push(this);
@@ -9,10 +9,13 @@ import ErrorTelemetry from 'vs/platform/telemetry/browser/errorTelemetry';
import { NullAppender, ITelemetryAppender } from 'vs/platform/telemetry/common/telemetryUtils';
import * as Errors from 'vs/base/common/errors';
import * as sinon from 'sinon';
import * as sinonTest from 'sinon-test';
import { ITelemetryData } from 'vs/platform/telemetry/common/telemetry';
import { TestConfigurationService } from 'vs/platform/configuration/test/common/testConfigurationService';
import { IConfigurationService } from 'vs/platform/configuration/common/configuration';
const sinonTestFn = sinonTest(sinon);
class TestTelemetryAppender implements ITelemetryAppender {
public events: any[];
@@ -85,7 +88,7 @@ class ErrorTestingSettings {
suite('TelemetryService', () => {
test('Disposing', sinon.test(function () {
test('Disposing', sinonTestFn(function () {
let testAppender = new TestTelemetryAppender();
let service = new TelemetryService({ appender: testAppender }, undefined!);
@@ -98,7 +101,7 @@ suite('TelemetryService', () => {
}));
// event reporting
test('Simple event', sinon.test(function () {
test('Simple event', sinonTestFn(function () {
let testAppender = new TestTelemetryAppender();
let service = new TelemetryService({ appender: testAppender }, undefined!);
@@ -111,7 +114,7 @@ suite('TelemetryService', () => {
});
}));
test('Event with data', sinon.test(function () {
test('Event with data', sinonTestFn(function () {
let testAppender = new TestTelemetryAppender();
let service = new TelemetryService({ appender: testAppender }, undefined!);
@@ -193,7 +196,7 @@ suite('TelemetryService', () => {
});
});
test('enableTelemetry on by default', sinon.test(function () {
test('enableTelemetry on by default', sinonTestFn(function () {
let testAppender = new TestTelemetryAppender();
let service = new TelemetryService({ appender: testAppender }, undefined!);
@@ -224,7 +227,7 @@ suite('TelemetryService', () => {
}
}
test('Error events', sinon.test(async function (this: any) {
test('Error events', sinonTestFn(async function (this: any) {
let origErrorHandler = Errors.errorHandler.getUnexpectedErrorHandler();
Errors.setUnexpectedErrorHandler(() => { });
@@ -256,7 +259,7 @@ suite('TelemetryService', () => {
}
}));
// test('Unhandled Promise Error events', sinon.test(function() {
// test('Unhandled Promise Error events', sinonTestFn(function() {
//
// let origErrorHandler = Errors.errorHandler.getUnexpectedErrorHandler();
// Errors.setUnexpectedErrorHandler(() => {});
@@ -285,7 +288,7 @@ suite('TelemetryService', () => {
// }
// }));
test('Handle global errors', sinon.test(async function (this: any) {
test('Handle global errors', sinonTestFn(async function (this: any) {
let errorStub = sinon.stub();
window.onerror = errorStub;
@@ -313,7 +316,7 @@ suite('TelemetryService', () => {
service.dispose();
}));
test('Error Telemetry removes PII from filename with spaces', sinon.test(async function (this: any) {
test('Error Telemetry removes PII from filename with spaces', sinonTestFn(async function (this: any) {
let errorStub = sinon.stub();
window.onerror = errorStub;
let settings = new ErrorTestingSettings();
@@ -336,7 +339,7 @@ suite('TelemetryService', () => {
service.dispose();
}));
test('Uncaught Error Telemetry removes PII from filename', sinon.test(function (this: any) {
test('Uncaught Error Telemetry removes PII from filename', sinonTestFn(function (this: any) {
let clock = this.clock;
let errorStub = sinon.stub();
window.onerror = errorStub;
@@ -368,7 +371,7 @@ suite('TelemetryService', () => {
});
}));
test('Unexpected Error Telemetry removes PII', sinon.test(async function (this: any) {
test('Unexpected Error Telemetry removes PII', sinonTestFn(async function (this: any) {
let origErrorHandler = Errors.errorHandler.getUnexpectedErrorHandler();
Errors.setUnexpectedErrorHandler(() => { });
try {
@@ -399,7 +402,7 @@ suite('TelemetryService', () => {
}
}));
test('Uncaught Error Telemetry removes PII', sinon.test(async function (this: any) {
test('Uncaught Error Telemetry removes PII', sinonTestFn(async function (this: any) {
let errorStub = sinon.stub();
window.onerror = errorStub;
let settings = new ErrorTestingSettings();
@@ -426,7 +429,7 @@ suite('TelemetryService', () => {
service.dispose();
}));
test('Unexpected Error Telemetry removes PII but preserves Code file path', sinon.test(async function (this: any) {
test('Unexpected Error Telemetry removes PII but preserves Code file path', sinonTestFn(async function (this: any) {
let origErrorHandler = Errors.errorHandler.getUnexpectedErrorHandler();
Errors.setUnexpectedErrorHandler(() => { });
@@ -462,7 +465,7 @@ suite('TelemetryService', () => {
}
}));
test('Uncaught Error Telemetry removes PII but preserves Code file path', sinon.test(async function (this: any) {
test('Uncaught Error Telemetry removes PII but preserves Code file path', sinonTestFn(async function (this: any) {
let errorStub = sinon.stub();
window.onerror = errorStub;
let settings = new ErrorTestingSettings();
@@ -491,7 +494,7 @@ suite('TelemetryService', () => {
service.dispose();
}));
test('Unexpected Error Telemetry removes PII but preserves Code file path with node modules', sinon.test(async function (this: any) {
test('Unexpected Error Telemetry removes PII but preserves Code file path with node modules', sinonTestFn(async function (this: any) {
let origErrorHandler = Errors.errorHandler.getUnexpectedErrorHandler();
Errors.setUnexpectedErrorHandler(() => { });
@@ -523,7 +526,7 @@ suite('TelemetryService', () => {
}
}));
test('Uncaught Error Telemetry removes PII but preserves Code file path', sinon.test(async function (this: any) {
test('Uncaught Error Telemetry removes PII but preserves Code file path', sinonTestFn(async function (this: any) {
let errorStub = sinon.stub();
window.onerror = errorStub;
let settings = new ErrorTestingSettings();
@@ -549,7 +552,7 @@ suite('TelemetryService', () => {
}));
test('Unexpected Error Telemetry removes PII but preserves Code file path when PIIPath is configured', sinon.test(async function (this: any) {
test('Unexpected Error Telemetry removes PII but preserves Code file path when PIIPath is configured', sinonTestFn(async function (this: any) {
let origErrorHandler = Errors.errorHandler.getUnexpectedErrorHandler();
Errors.setUnexpectedErrorHandler(() => { });
@@ -585,7 +588,7 @@ suite('TelemetryService', () => {
}
}));
test('Uncaught Error Telemetry removes PII but preserves Code file path when PIIPath is configured', sinon.test(async function (this: any) {
test('Uncaught Error Telemetry removes PII but preserves Code file path when PIIPath is configured', sinonTestFn(async function (this: any) {
let errorStub = sinon.stub();
window.onerror = errorStub;
let settings = new ErrorTestingSettings();
@@ -614,7 +617,7 @@ suite('TelemetryService', () => {
service.dispose();
}));
test('Unexpected Error Telemetry removes PII but preserves Missing Model error message', sinon.test(async function (this: any) {
test('Unexpected Error Telemetry removes PII but preserves Missing Model error message', sinonTestFn(async function (this: any) {
let origErrorHandler = Errors.errorHandler.getUnexpectedErrorHandler();
Errors.setUnexpectedErrorHandler(() => { });
@@ -650,7 +653,7 @@ suite('TelemetryService', () => {
}
}));
test('Uncaught Error Telemetry removes PII but preserves Missing Model error message', sinon.test(async function (this: any) {
test('Uncaught Error Telemetry removes PII but preserves Missing Model error message', sinonTestFn(async function (this: any) {
let errorStub = sinon.stub();
window.onerror = errorStub;
let settings = new ErrorTestingSettings();
@@ -680,7 +683,7 @@ suite('TelemetryService', () => {
service.dispose();
}));
test('Unexpected Error Telemetry removes PII but preserves No Such File error message', sinon.test(async function (this: any) {
test('Unexpected Error Telemetry removes PII but preserves No Such File error message', sinonTestFn(async function (this: any) {
let origErrorHandler = Errors.errorHandler.getUnexpectedErrorHandler();
Errors.setUnexpectedErrorHandler(() => { });
@@ -716,7 +719,7 @@ suite('TelemetryService', () => {
}
}));
test('Uncaught Error Telemetry removes PII but preserves No Such File error message', sinon.test(async function (this: any) {
test('Uncaught Error Telemetry removes PII but preserves No Such File error message', sinonTestFn(async function (this: any) {
let origErrorHandler = Errors.errorHandler.getUnexpectedErrorHandler();
Errors.setUnexpectedErrorHandler(() => { });
@@ -754,7 +757,7 @@ suite('TelemetryService', () => {
}
}));
test('Telemetry Service sends events when enableTelemetry is on', sinon.test(function () {
test('Telemetry Service sends events when enableTelemetry is on', sinonTestFn(function () {
let testAppender = new TestTelemetryAppender();
let service = new TelemetryService({ appender: testAppender }, undefined!);
@@ -23,6 +23,7 @@ import { createCancelablePromise, timeout, CancelablePromise } from 'vs/base/com
import { isString, isObject, isArray } from 'vs/base/common/types';
import { URI } from 'vs/base/common/uri';
import { getErrorMessage, isPromiseCanceledError } from 'vs/base/common/errors';
import { Mimes } from 'vs/base/common/mime';
const SYNC_PREVIOUS_STORE = 'sync.previous.store';
const DONOT_MAKE_REQUESTS_UNTIL_KEY = 'sync.donot-make-requests-until';
@@ -304,7 +305,7 @@ export class UserDataSyncStoreClient extends Disposable implements IUserDataSync
const url = joinPath(this.userDataSyncStoreUrl, 'resource', resource).toString();
headers = { ...headers };
headers['Content-Type'] = 'text/plain';
headers['Content-Type'] = Mimes.text;
if (ref) {
headers['If-Match'] = ref;
}
@@ -356,7 +357,7 @@ export class UserDataSyncStoreClient extends Disposable implements IUserDataSync
}
const url = joinPath(this.userDataSyncStoreUrl, 'resource').toString();
const headers: IHeaders = { 'Content-Type': 'text/plain' };
const headers: IHeaders = { 'Content-Type': Mimes.text };
await this.request(url, { type: 'DELETE', headers }, [], CancellationToken.None);
+4 -3
View File
@@ -3,13 +3,13 @@
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import { getMediaMime, MIME_UNKNOWN } from 'vs/base/common/mime';
import { getMediaMime, Mimes } from 'vs/base/common/mime';
import { extname } from 'vs/base/common/path';
import { URI } from 'vs/base/common/uri';
const webviewMimeTypes = new Map([
['.svg', 'image/svg+xml'],
['.txt', 'text/plain'],
['.txt', Mimes.text],
['.css', 'text/css'],
['.js', 'application/javascript'],
['.json', 'application/json'],
@@ -18,9 +18,10 @@ const webviewMimeTypes = new Map([
['.xhtml', 'application/xhtml+xml'],
['.oft', 'font/otf'],
['.xml', 'application/xml'],
['.wasm', 'application/wasm'],
]);
export function getWebviewContentMimeType(resource: URI): string {
const ext = extname(resource.fsPath).toLowerCase();
return webviewMimeTypes.get(ext) || getMediaMime(resource.fsPath) || MIME_UNKNOWN;
return webviewMimeTypes.get(ext) || getMediaMime(resource.fsPath) || Mimes.unknown;
}
+28 -10
View File
@@ -9489,6 +9489,24 @@ declare module 'vscode' {
*/
onDidClose?: Event<void | number>;
/**
* An event that when fired allows changing the name of the terminal.
*
* **Example:** Change the terminal name to "My new terminal".
* ```typescript
* const writeEmitter = new vscode.EventEmitter<string>();
* const changeNameEmitter = new vscode.EventEmitter<string>();
* const pty: vscode.Pseudoterminal = {
* onDidWrite: writeEmitter.event,
* onDidChangeName: changeNameEmitter.event,
* open: () => changeNameEmitter.fire('My new terminal'),
* close: () => {}
* };
* vscode.window.createTerminal({ name: 'My terminal', pty });
* ```
*/
onDidChangeName?: Event<string>;
/**
* Implement to handle when the pty is open and ready to start firing events.
*
@@ -9884,7 +9902,7 @@ declare module 'vscode' {
/**
* An event signaling when the active items have changed.
*/
readonly onDidChangeActive: Event<T[]>;
readonly onDidChangeActive: Event<readonly T[]>;
/**
* Selected items. This can be read and updated by the extension.
@@ -9894,7 +9912,7 @@ declare module 'vscode' {
/**
* An event signaling when the selected items have changed.
*/
readonly onDidChangeSelection: Event<T[]>;
readonly onDidChangeSelection: Event<readonly T[]>;
}
/**
@@ -11409,7 +11427,7 @@ declare module 'vscode' {
readonly outputs: readonly NotebookCellOutput[];
/**
* The most recent {@link NotebookCellExecutionSummary excution summary} for this cell.
* The most recent {@link NotebookCellExecutionSummary execution summary} for this cell.
*/
readonly executionSummary?: NotebookCellExecutionSummary;
}
@@ -11477,7 +11495,7 @@ declare module 'vscode' {
/**
* Get the cells of this notebook. A subset can be retrieved by providing
* a range. The range will be adjuset to the notebook.
* a range. The range will be adjusted to the notebook.
*
* @param range A notebook range.
* @returns The cells contained by the range or all cells.
@@ -11515,7 +11533,7 @@ declare module 'vscode' {
}
/**
* A notebook range represents an ordered pair of two cell indicies.
* A notebook range represents an ordered pair of two cell indices.
* It is guaranteed that start is less than or equal to end.
*/
export class NotebookRange {
@@ -11626,7 +11644,7 @@ declare module 'vscode' {
data: Uint8Array;
/**
* Create a new notbook cell output item.
* Create a new notebook cell output item.
*
* @param data The value of the output item.
* @param mime The mime type of the output item.
@@ -12122,7 +12140,7 @@ declare module 'vscode' {
/**
* Namespace for notebooks.
*
* The notebooks functionality is composed of three loosly coupled components:
* The notebooks functionality is composed of three loosely coupled components:
*
* 1. {@link NotebookSerializer} enable the editor to open, show, and save notebooks
* 2. {@link NotebookController} own the execution of notebooks, e.g they create output from code cells.
@@ -13512,17 +13530,17 @@ declare module 'vscode' {
*/
export interface AuthenticationProviderAuthenticationSessionsChangeEvent {
/**
* The {@link AuthenticationSession}s of the {@link AuthentiationProvider AuthenticationProvider} that have been added.
* The {@link AuthenticationSession}s of the {@link AuthenticationProvider} that have been added.
*/
readonly added?: readonly AuthenticationSession[];
/**
* The {@link AuthenticationSession}s of the {@link AuthentiationProvider AuthenticationProvider} that have been removed.
* The {@link AuthenticationSession}s of the {@link AuthenticationProvider} that have been removed.
*/
readonly removed?: readonly AuthenticationSession[];
/**
* The {@link AuthenticationSession}s of the {@link AuthentiationProvider AuthenticationProvider} that have been changed.
* The {@link AuthenticationSession}s of the {@link AuthenticationProvider} that have been changed.
* A session changes when its data excluding the id are updated. An example of this is a session refresh that results in a new
* access token being set for the session.
*/
-24
View File
@@ -874,30 +874,6 @@ declare module 'vscode' {
//#endregion
//#region Terminal name change event https://github.com/microsoft/vscode/issues/114898
export interface Pseudoterminal {
/**
* An event that when fired allows changing the name of the terminal.
*
* **Example:** Change the terminal name to "My new terminal".
* ```typescript
* const writeEmitter = new vscode.EventEmitter<string>();
* const changeNameEmitter = new vscode.EventEmitter<string>();
* const pty: vscode.Pseudoterminal = {
* onDidWrite: writeEmitter.event,
* onDidChangeName: changeNameEmitter.event,
* open: () => changeNameEmitter.fire('My new terminal'),
* close: () => {}
* };
* vscode.window.createTerminal({ name: 'My terminal', pty });
* ```
*/
onDidChangeName?: Event<string>;
}
//#endregion
//#region Terminal icon https://github.com/microsoft/vscode/issues/120538
export interface TerminalOptions {
@@ -551,7 +551,7 @@ export abstract class AbstractExtHostExtensionService extends Disposable impleme
public async $extensionTestsExecute(): Promise<number> {
await this._eagerExtensionsActivated.wait();
try {
return this._doHandleExtensionTests();
return await this._doHandleExtensionTests();
} catch (error) {
console.error(error); // ensure any error message makes it onto the console
throw error;
+2 -2
View File
@@ -8,7 +8,7 @@ import { illegalArgument } from 'vs/base/common/errors';
import { IRelativePattern } from 'vs/base/common/glob';
import { isMarkdownString, MarkdownString as BaseMarkdownString } from 'vs/base/common/htmlContent';
import { ReadonlyMapView, ResourceMap } from 'vs/base/common/map';
import { normalizeMimeType } from 'vs/base/common/mime';
import { Mimes, normalizeMimeType } from 'vs/base/common/mime';
import { isArray, isStringArray } from 'vs/base/common/types';
import { URI } from 'vs/base/common/uri';
import { generateUuid } from 'vs/base/common/uuid';
@@ -3050,7 +3050,7 @@ export class NotebookCellOutputItem {
static #encoder = new TextEncoder();
static text(value: string, mime: string = 'text/plain'): NotebookCellOutputItem {
static text(value: string, mime: string = Mimes.text): NotebookCellOutputItem {
const bytes = NotebookCellOutputItem.#encoder.encode(String(value));
return new NotebookCellOutputItem(bytes, mime);
}
+2 -2
View File
@@ -13,7 +13,7 @@ import { FileAccess, Schemas } from 'vs/base/common/network';
import { IBaseTextResourceEditorInput } from 'vs/platform/editor/common/editor';
import { DataTransfers, IDragAndDropData } from 'vs/base/browser/dnd';
import { DragMouseEvent } from 'vs/base/browser/mouseEvent';
import { MIME_BINARY } from 'vs/base/common/mime';
import { Mimes } from 'vs/base/common/mime';
import { isWindows } from 'vs/base/common/platform';
import { ServicesAccessor } from 'vs/platform/instantiation/common/instantiation';
import { isCodeEditor } from 'vs/editor/browser/editorBrowser';
@@ -277,7 +277,7 @@ export function fillEditorsDragData(accessor: ServicesAccessor, resourcesOrEdito
// TODO@sandbox this will no longer work when `vscode-file`
// is enabled because we block loading resources that are not
// inside installation dir
event.dataTransfer.setData(DataTransfers.DOWNLOAD_URL, [MIME_BINARY, basename(firstFile.resource), FileAccess.asBrowserUri(firstFile.resource).toString()].join(':'));
event.dataTransfer.setData(DataTransfers.DOWNLOAD_URL, [Mimes.binary, basename(firstFile.resource), FileAccess.asBrowserUri(firstFile.resource).toString()].join(':'));
}
// Resource URLs: allows to drop multiple file resources to a target in VS Code
@@ -22,6 +22,7 @@ import { ViewContainerLocation, IViewDescriptorService } from 'vs/workbench/comm
import { IPaneComposite } from 'vs/workbench/common/panecomposite';
import { IComposite } from 'vs/workbench/common/composite';
import { CompositeDragAndDropData, CompositeDragAndDropObserver, IDraggedCompositeData, ICompositeDragAndDrop, Before2D, toggleDropEffect } from 'vs/workbench/browser/dnd';
import { Gesture, EventType as TouchEventType, GestureEvent } from 'vs/base/browser/touch';
export interface ICompositeBarItem {
id: string;
@@ -233,6 +234,8 @@ export class CompositeBar extends Widget implements ICompositeBar {
// Contextmenu for composites
this._register(addDisposableListener(parent, EventType.CONTEXT_MENU, e => this.showContextMenu(e)));
this._register(Gesture.addTarget(parent));
this._register(addDisposableListener(parent, TouchEventType.Contextmenu, e => this.showContextMenu(e)));
let insertDropBefore: Before2D | undefined = undefined;
// Register a drop target on the whole bar to prevent forbidden feedback
@@ -619,7 +622,7 @@ export class CompositeBar extends Widget implements ICompositeBar {
return this.model.visibleItems.filter(c => overflowingIds.includes(c.id)).map(item => { return { id: item.id, name: this.getAction(item.id)?.label || item.name }; });
}
private showContextMenu(e: MouseEvent): void {
private showContextMenu(e: MouseEvent | GestureEvent): void {
EventHelper.stop(e, true);
const event = new StandardMouseEvent(e);
this.contextMenuService.showContextMenu({
@@ -22,7 +22,6 @@ import { Color } from 'vs/base/common/color';
import { IBaseActionViewItemOptions, BaseActionViewItem } from 'vs/base/browser/ui/actionbar/actionViewItems';
import { Codicon } from 'vs/base/common/codicons';
import { IHoverService } from 'vs/workbench/services/hover/browser/hover';
import { domEvent } from 'vs/base/browser/event';
import { RunOnceScheduler } from 'vs/base/common/async';
import { IConfigurationService } from 'vs/platform/configuration/common/configuration';
import { HoverPosition } from 'vs/base/browser/ui/hover/hoverWidget';
@@ -395,15 +394,15 @@ export class ActivityActionViewItem extends BaseActionViewItem {
this.updateTitle();
if (this.useCustomHover) {
this.hoverDisposables.add(domEvent(this.container, EventType.MOUSE_OVER, true)(() => {
this.hoverDisposables.add(addDisposableListener(this.container, EventType.MOUSE_OVER, () => {
if (!this.showHoverScheduler.isScheduled()) {
this.showHoverScheduler.schedule(this.options.hoverOptions!.delay() || 150);
}
}));
this.hoverDisposables.add(domEvent(this.container, EventType.MOUSE_LEAVE, true)(() => {
}, true));
this.hoverDisposables.add(addDisposableListener(this.container, EventType.MOUSE_LEAVE, () => {
this.hover.value = undefined;
this.showHoverScheduler.cancel();
}));
}, true));
this.hoverDisposables.add(toDisposable(() => {
this.hover.value = undefined;
this.showHoverScheduler.cancel();
@@ -35,6 +35,7 @@ import { CompositeDragAndDropObserver } from 'vs/workbench/browser/dnd';
import { IViewDescriptorService, ViewContainerLocation } from 'vs/workbench/common/views';
import { KeybindingWeight } from 'vs/platform/keybinding/common/keybindingsRegistry';
import { CATEGORIES } from 'vs/workbench/common/actions';
import { Gesture, EventType as GestureEventType } from 'vs/base/browser/touch';
export class SidebarPart extends CompositePart<Viewlet> implements IViewletService {
@@ -171,6 +172,10 @@ export class SidebarPart extends CompositePart<Viewlet> implements IViewletServi
this._register(addDisposableListener(titleArea, EventType.CONTEXT_MENU, e => {
this.onTitleAreaContextMenu(new StandardMouseEvent(e));
}));
this._register(Gesture.addTarget(titleArea));
this._register(addDisposableListener(titleArea, GestureEventType.Contextmenu, e => {
this.onTitleAreaContextMenu(new StandardMouseEvent(e));
}));
this.titleLabelElement!.draggable = true;
@@ -10,6 +10,7 @@ import { dispose, IDisposable, Disposable, toDisposable, MutableDisposable } fro
import { SimpleIconLabel } from 'vs/base/browser/ui/iconLabel/simpleIconLabel';
import { ICommandService } from 'vs/platform/commands/common/commands';
import { Part } from 'vs/workbench/browser/part';
import { EventType as TouchEventType, Gesture, GestureEvent } from 'vs/base/browser/touch';
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry';
import { StatusbarAlignment, IStatusbarService, IStatusbarEntry, IStatusbarEntryAccessor } from 'vs/workbench/services/statusbar/common/statusbar';
@@ -586,6 +587,8 @@ export class StatusbarPart extends Part implements IStatusbarService {
// Context menu support
this._register(addDisposableListener(parent, EventType.CONTEXT_MENU, e => this.showContextMenu(e)));
this._register(Gesture.addTarget(parent));
this._register(addDisposableListener(parent, TouchEventType.Contextmenu, e => this.showContextMenu(e)));
// Initial status bar entries
this.createInitialStatusbarEntries();
@@ -660,7 +663,7 @@ export class StatusbarPart extends Part implements IStatusbarService {
}
}
private showContextMenu(e: MouseEvent): void {
private showContextMenu(e: MouseEvent | GestureEvent): void {
EventHelper.stop(e, true);
const event = new StandardMouseEvent(e);
@@ -38,6 +38,7 @@ import { ViewPane } from 'vs/workbench/browser/parts/views/viewPane';
import { CompositeMenuActions } from 'vs/workbench/browser/actions';
import { createActionViewItem } from 'vs/platform/actions/browser/menuEntryActionViewItem';
import { IActionViewItem } from 'vs/base/browser/ui/actionbar/actionbar';
import { Gesture, EventType as TouchEventType } from 'vs/base/browser/touch';
export const ViewsSubMenu = new MenuId('Views');
MenuRegistry.appendMenuItem(MenuId.ViewContainerTitle, <ISubmenuItem>{
@@ -409,6 +410,8 @@ export class ViewPaneContainer extends Component implements IViewPaneContainer {
this._register(this.paneview.onDidDrop(({ from, to }) => this.movePane(from as ViewPane, to as ViewPane)));
this._register(this.paneview.onDidScroll(_ => this.onDidScrollPane()));
this._register(addDisposableListener(parent, EventType.CONTEXT_MENU, (e: MouseEvent) => this.showContextMenu(new StandardMouseEvent(e))));
this._register(Gesture.addTarget(parent));
this._register(addDisposableListener(parent, TouchEventType.Contextmenu, (e: MouseEvent) => this.showContextMenu(new StandardMouseEvent(e))));
this._menuActions = this._register(this.instantiationService.createInstance(ViewContainerMenuActions, this.paneview.element, this.viewContainer));
this._register(this._menuActions.onDidChange(() => this.updateTitleArea()));
@@ -6,14 +6,14 @@
import { EditorModel } from 'vs/workbench/common/editor/editorModel';
import { URI } from 'vs/base/common/uri';
import { IFileService } from 'vs/platform/files/common/files';
import { MIME_BINARY } from 'vs/base/common/mime';
import { Mimes } from 'vs/base/common/mime';
/**
* An editor model that just represents a resource that can be loaded.
*/
export class BinaryEditorModel extends EditorModel {
private readonly mime = MIME_BINARY;
private readonly mime = Mimes.binary;
private size: number | undefined;
private etag: string | undefined;
@@ -233,9 +233,10 @@ class FormatOnSaveParticipant implements ITextFileSaveParticipant {
const nestedProgress = new Progress<{ displayName?: string, extensionId?: ExtensionIdentifier }>(provider => {
progress.report({
message: localize(
'formatting',
"Running '{0}' Formatter ([configure](command:workbench.action.openSettings?%5B%22editor.formatOnSave%22%5D)).",
provider.displayName || provider.extensionId && provider.extensionId.value || '???'
{ key: 'formatting2', comment: ['[configure]({1}) is a link. Only translate `configure`. Do not change brackets and parentheses or {1}'] },
"Running '{0}' Formatter ([configure]({1})).",
provider.displayName || provider.extensionId && provider.extensionId.value || '???',
'command:workbench.action.openSettings?%5B%22editor.formatOnSave%22%5D'
)
});
});
@@ -336,9 +337,10 @@ class CodeActionOnSaveParticipant implements ITextFileSaveParticipant {
private _report(): void {
progress.report({
message: localize(
'codeaction.get',
"Getting code actions from '{0}' ([configure](command:workbench.action.openSettings?%5B%22editor.codeActionsOnSave%22%5D)).",
[...this._names].map(name => `'${name}'`).join(', ')
{ key: 'codeaction.get2', comment: ['[configure]({1}) is a link. Only translate `configure`. Do not change brackets and parentheses or {1}'] },
"Getting code actions from '{0}' ([configure]({1})).",
[...this._names].map(name => `'${name}'`).join(', '),
'command:workbench.action.openSettings?%5B%22editor.codeActionsOnSave%22%5D'
)
});
}
@@ -110,7 +110,7 @@ class UntitledTextEditorHintContentWidget implements IContentWidget {
this.domNode.style.width = 'max-content';
const language = $('a.language-mode');
language.style.cursor = 'pointer';
language.innerText = localize('selectAlanguage', "Select a language");
language.innerText = localize('selectAlanguage2', "Select a language");
this.domNode.appendChild(language);
const toGetStarted = $('span');
toGetStarted.innerText = localize('toGetStarted', " to get started. Start typing to dismiss, or ",);
@@ -21,6 +21,7 @@ import { IDisposable, dispose } from 'vs/base/common/lifecycle';
import { ADD_CONFIGURATION_ID } from 'vs/workbench/contrib/debug/browser/debugCommands';
import { BaseActionViewItem, SelectActionViewItem } from 'vs/base/browser/ui/actionbar/actionViewItems';
import { debugStart } from 'vs/workbench/contrib/debug/browser/debugIcons';
import { IKeybindingService } from 'vs/platform/keybinding/common/keybinding';
const $ = dom.$;
@@ -45,6 +46,7 @@ export class StartDebugActionViewItem extends BaseActionViewItem {
@ICommandService private readonly commandService: ICommandService,
@IWorkspaceContextService private readonly contextService: IWorkspaceContextService,
@IContextViewService contextViewService: IContextViewService,
@IKeybindingService private readonly keybindingService: IKeybindingService
) {
super(context, action);
this.toDispose = [];
@@ -71,7 +73,9 @@ export class StartDebugActionViewItem extends BaseActionViewItem {
this.container = container;
container.classList.add('start-debug-action-item');
this.start = dom.append(container, $(ThemeIcon.asCSSSelector(debugStart)));
this.start.title = this.action.label;
const keybinding = this.keybindingService.lookupKeybinding(this.action.id)?.getLabel();
let keybindingLabel = keybinding ? ` (${keybinding})` : '';
this.start.title = this.action.label + keybindingLabel;
this.start.setAttribute('role', 'button');
this.toDispose.push(dom.addDisposableListener(this.start, dom.EventType.CLICK, () => {
@@ -37,7 +37,6 @@ import { ITextModel } from 'vs/editor/common/model';
import { dispose, IDisposable } from 'vs/base/common/lifecycle';
import { EditOperation } from 'vs/editor/common/core/editOperation';
import { basename } from 'vs/base/common/path';
import { domEvent } from 'vs/base/browser/event';
import { ModesHoverController } from 'vs/editor/contrib/hover/hover';
import { HoverStartMode } from 'vs/editor/contrib/hover/hoverOperation';
import { IHostService } from 'vs/workbench/services/host/browser/host';
@@ -47,6 +46,8 @@ import { IContextKey, IContextKeyService } from 'vs/platform/contextkey/common/c
import { Expression } from 'vs/workbench/contrib/debug/common/debugModel';
import { themeColorFromId } from 'vs/platform/theme/common/themeService';
import { registerColor } from 'vs/platform/theme/common/colorRegistry';
import { addDisposableListener } from 'vs/base/browser/dom';
import { DomEmitter } from 'vs/base/browser/event';
const LAUNCH_JSON_REGEX = /\.vscode\/launch\.json$/;
const INLINE_VALUE_DECORATION_KEY = 'inlinevaluedecoration';
@@ -284,7 +285,7 @@ export class DebugEditorContribution implements IDebugEditorContribution {
this.altListener.dispose();
}
// When the alt key is pressed show regular editor hover and hide the debug hover #84561
this.altListener = domEvent(document, 'keydown')(keydownEvent => {
this.altListener = addDisposableListener(document, 'keydown', keydownEvent => {
const standardKeyboardEvent = new StandardKeyboardEvent(keydownEvent);
if (standardKeyboardEvent.keyCode === KeyCode.Alt) {
this.altPressed = true;
@@ -297,7 +298,8 @@ export class DebugEditorContribution implements IDebugEditorContribution {
hoverController.showContentHover(this.hoverRange, HoverStartMode.Immediate, false);
}
const listener = Event.any<KeyboardEvent | boolean>(this.hostService.onDidChangeFocus, domEvent(document, 'keyup'))(keyupEvent => {
const onKeyUp = new DomEmitter(document, 'keyup');
const listener = Event.any<KeyboardEvent | boolean>(this.hostService.onDidChangeFocus, onKeyUp.event)(keyupEvent => {
let standardKeyboardEvent = undefined;
if (keyupEvent instanceof KeyboardEvent) {
standardKeyboardEvent = new StandardKeyboardEvent(keyupEvent);
@@ -306,6 +308,7 @@ export class DebugEditorContribution implements IDebugEditorContribution {
this.altPressed = false;
this.editor.updateOptions({ hover: { enabled: false } });
listener.dispose();
onKeyUp.dispose();
}
});
}
@@ -5,7 +5,7 @@
import { URI as uri } from 'vs/base/common/uri';
import { localize } from 'vs/nls';
import { guessMimeTypes, MIME_TEXT } from 'vs/base/common/mime';
import { guessMimeTypes, Mimes } from 'vs/base/common/mime';
import { ITextModel } from 'vs/editor/common/model';
import { IModelService } from 'vs/editor/common/services/modelService';
import { IModeService } from 'vs/editor/common/services/modeService';
@@ -94,7 +94,7 @@ export class DebugContentProvider implements IWorkbenchContribution, ITextModelC
}
const createErrModel = (errMsg?: string) => {
this.debugService.sourceIsNotAvailable(resource);
const languageSelection = this.modeService.create(MIME_TEXT);
const languageSelection = this.modeService.create(Mimes.text);
const message = errMsg
? localize('canNotResolveSourceWithError', "Could not load source '{0}': {1}.", resource.path, errMsg)
: localize('canNotResolveSource', "Could not load source '{0}'.", resource.path);
@@ -41,7 +41,7 @@ export function filterExceptionsFromTelemetry<T extends { [key: string]: unknown
export function isSessionAttach(session: IDebugSession): boolean {
return session.configuration.request === 'attach' && !getExtensionHostDebugSession(session);
return session.configuration.request === 'attach' && !getExtensionHostDebugSession(session) && (!session.parentSession || isSessionAttach(session.parentSession));
}
/**
@@ -14,7 +14,7 @@ import { IThemeService } from 'vs/platform/theme/common/themeService';
import { IExtensionService, IExtensionsStatus, IExtensionHostProfile } from 'vs/workbench/services/extensions/common/extensions';
import { IListVirtualDelegate, IListRenderer } from 'vs/base/browser/ui/list/list';
import { WorkbenchList } from 'vs/platform/list/browser/listService';
import { append, $, reset, Dimension, clearNode } from 'vs/base/browser/dom';
import { append, $, reset, Dimension, clearNode, addDisposableListener } from 'vs/base/browser/dom';
import { ActionBar } from 'vs/base/browser/ui/actionbar/actionbar';
import { dispose, IDisposable } from 'vs/base/common/lifecycle';
import { RunOnceScheduler } from 'vs/base/common/async';
@@ -22,7 +22,6 @@ import { EnablementState } from 'vs/workbench/services/extensionManagement/commo
import { IContextMenuService } from 'vs/platform/contextview/browser/contextView';
import { memoize } from 'vs/base/common/decorators';
import { isNonEmptyArray } from 'vs/base/common/arrays';
import { Event } from 'vs/base/common/event';
import { INotificationService } from 'vs/platform/notification/common/notification';
import { IContextKeyService } from 'vs/platform/contextkey/common/contextkey';
import { IStorageService } from 'vs/platform/storage/common/storage';
@@ -32,7 +31,6 @@ import { ExtensionIdentifier, IExtensionDescription } from 'vs/platform/extensio
import { Schemas } from 'vs/base/common/network';
import { IWorkbenchEnvironmentService } from 'vs/workbench/services/environment/common/environmentService';
import { editorBackground } from 'vs/platform/theme/common/colorRegistry';
import { domEvent } from 'vs/base/browser/event';
import { IListAccessibilityProvider } from 'vs/base/browser/ui/list/listWidget';
import { IEditorService } from 'vs/workbench/services/editor/common/editorService';
import { RuntimeExtensionsInput } from 'vs/workbench/contrib/extensions/common/runtimeExtensionsInput';
@@ -267,8 +265,7 @@ export abstract class AbstractRuntimeExtensionsEditor extends EditorPane {
data.root.classList.toggle('odd', index % 2 === 1);
const onError = Event.once(domEvent(data.icon, 'error'));
onError(() => data.icon.src = element.marketplaceInfo?.iconUrlFallback || DefaultIconPath, null, data.elementDisposables);
data.elementDisposables.push(addDisposableListener(data.icon, 'error', () => data.icon.src = element.marketplaceInfo?.iconUrlFallback || DefaultIconPath, { once: true }));
data.icon.src = element.marketplaceInfo?.iconUrl || DefaultIconPath;
if (!data.icon.complete) {
@@ -13,7 +13,6 @@ import { Cache, CacheResult } from 'vs/base/common/cache';
import { Action, IAction } from 'vs/base/common/actions';
import { isPromiseCanceledError, onUnexpectedError } from 'vs/base/common/errors';
import { dispose, toDisposable, Disposable, DisposableStore, IDisposable } from 'vs/base/common/lifecycle';
import { domEvent } from 'vs/base/browser/event';
import { append, $, finalHandler, join, hide, show, addDisposableListener, EventType, setParentFlowTo } from 'vs/base/browser/dom';
import { EditorPane } from 'vs/workbench/browser/parts/editor/editorPane';
import { IViewletService } from 'vs/workbench/services/viewlet/browser/viewlet';
@@ -349,8 +348,7 @@ export class ExtensionEditor extends EditorPane {
this.extensionManifest = new Cache(() => createCancelablePromise(token => extension.getManifest(token)));
const remoteBadge = this.instantiationService.createInstance(RemoteBadgeWidget, template.iconContainer, true);
const onError = Event.once(domEvent(template.icon, 'error'));
onError(() => template.icon.src = extension.iconUrlFallback, null, this.transientDisposables);
this.transientDisposables.add(addDisposableListener(template.icon, 'error', () => template.icon.src = extension.iconUrlFallback, { once: true }));
template.icon.src = extension.iconUrl;
template.name.textContent = extension.displayName;
@@ -4,7 +4,7 @@
*--------------------------------------------------------------------------------------------*/
import 'vs/css!./media/extension';
import { append, $ } from 'vs/base/browser/dom';
import { append, $, addDisposableListener } from 'vs/base/browser/dom';
import { IDisposable, dispose, combinedDisposable } from 'vs/base/common/lifecycle';
import { IAction } from 'vs/base/common/actions';
import { ActionBar } from 'vs/base/browser/ui/actionbar/actionbar';
@@ -12,7 +12,6 @@ import { IInstantiationService } from 'vs/platform/instantiation/common/instanti
import { IListVirtualDelegate } from 'vs/base/browser/ui/list/list';
import { IPagedRenderer } from 'vs/base/browser/ui/list/listPaging';
import { Event } from 'vs/base/common/event';
import { domEvent } from 'vs/base/browser/event';
import { IExtension, ExtensionContainers, ExtensionState, IExtensionsWorkbenchService } from 'vs/workbench/contrib/extensions/common/extensions';
import { UpdateAction, ManageExtensionAction, ReloadAction, MaliciousStatusLabelAction, StatusLabelAction, RemoteInstallAction, SystemDisabledWarningAction, ExtensionToolTipAction, LocalInstallAction, ActionWithDropDownAction, InstallDropdownAction, InstallingLabelAction, ExtensionActionWithDropdownActionViewItem, ExtensionDropDownAction, WebInstallAction } from 'vs/workbench/contrib/extensions/browser/extensionsActions';
import { areSameExtensions } from 'vs/platform/extensionManagement/common/extensionManagementUtil';
@@ -190,8 +189,7 @@ export class Renderer implements IPagedRenderer<IExtension, ITemplateData> {
updateEnablement();
this.extensionService.onDidChangeExtensions(() => updateEnablement(), this, data.extensionDisposables);
const onError = Event.once(domEvent(data.icon, 'error'));
onError(() => data.icon.src = extension.iconUrlFallback, null, data.extensionDisposables);
data.extensionDisposables.push(addDisposableListener(data.icon, 'error', () => data.icon.src = extension.iconUrlFallback, { once: true }));
data.icon.src = extension.iconUrl;
if (!data.icon.complete) {
@@ -9,7 +9,6 @@ import { IDisposable, dispose, Disposable, DisposableStore, toDisposable } from
import { Action } from 'vs/base/common/actions';
import { IExtensionsWorkbenchService, IExtension } from 'vs/workbench/contrib/extensions/common/extensions';
import { Event } from 'vs/base/common/event';
import { domEvent } from 'vs/base/browser/event';
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
import { IListService, WorkbenchAsyncDataTree } from 'vs/platform/list/browser/listService';
import { IConfigurationService } from 'vs/platform/configuration/common/configuration';
@@ -167,8 +166,7 @@ export class ExtensionRenderer implements IListRenderer<ITreeNode<IExtensionData
public renderElement(node: ITreeNode<IExtensionData>, index: number, data: IExtensionTemplateData): void {
const extension = node.element.extension;
const onError = Event.once(domEvent(data.icon, 'error'));
onError(() => data.icon.src = extension.iconUrlFallback, null, data.extensionDisposables);
data.extensionDisposables.push(dom.addDisposableListener(data.icon, 'error', () => data.icon.src = extension.iconUrlFallback, { once: true }));
data.icon.src = extension.iconUrl;
if (!data.icon.complete) {
@@ -20,7 +20,7 @@ import { Schemas } from 'vs/base/common/network';
import { basename, extname } from 'vs/base/common/resources';
import { match } from 'vs/base/common/glob';
import { URI } from 'vs/base/common/uri';
import { MIME_UNKNOWN, guessMimeTypes } from 'vs/base/common/mime';
import { Mimes, guessMimeTypes } from 'vs/base/common/mime';
import { IExtensionService } from 'vs/workbench/services/extensions/common/extensions';
import { IViewletService } from 'vs/workbench/services/viewlet/browser/viewlet';
import { IModelService } from 'vs/editor/common/services/modelService';
@@ -230,7 +230,7 @@ export class FileBasedRecommendations extends ExtensionRecommendations {
}
const mimeTypes = guessMimeTypes(uri);
if (mimeTypes.length !== 1 || mimeTypes[0] !== MIME_UNKNOWN) {
if (mimeTypes.length !== 1 || mimeTypes[0] !== Mimes.unknown) {
return;
}
@@ -487,12 +487,13 @@ export class ExplorerView extends ViewPane {
}
private setContextKeys(stat: ExplorerItem | null | undefined): void {
const isSingleFolder = this.contextService.getWorkbenchState() === WorkbenchState.FOLDER;
const resource = stat ? stat.resource : isSingleFolder ? this.contextService.getWorkspace().folders[0].uri : null;
const folders = this.contextService.getWorkspace().folders;
const resource = stat ? stat.resource : folders[folders.length - 1].uri;
stat = stat || this.explorerService.findClosest(resource);
this.resourceContext.set(resource);
this.folderContext.set((isSingleFolder && !stat) || !!stat && stat.isDirectory);
this.folderContext.set(!!stat && stat.isDirectory);
this.readonlyContext.set(!!stat && stat.isReadonly);
this.rootContext.set(!stat || (stat && stat.isRoot));
this.rootContext.set(!!stat && stat.isRoot);
if (resource) {
const overrides = resource ? this.editorOverrideService.getEditorIds(resource) : [];
@@ -49,7 +49,6 @@ import { ICompressibleTreeRenderer } from 'vs/base/browser/ui/tree/objectTree';
import { ICompressedTreeNode } from 'vs/base/browser/ui/tree/compressedObjectTreeModel';
import { ILabelService } from 'vs/platform/label/common/label';
import { isNumber } from 'vs/base/common/types';
import { domEvent } from 'vs/base/browser/event';
import { IEditableData } from 'vs/workbench/common/views';
import { IEditorInput } from 'vs/workbench/common/editor';
import { IUriIdentityService } from 'vs/workbench/services/uriIdentity/common/uriIdentity';
@@ -328,13 +327,13 @@ export class FilesRenderer implements ICompressibleTreeRenderer<ExplorerItem, Fu
// accessibility
disposables.add(this._onDidChangeActiveDescendant.add(compressedNavigationController.onDidChange));
domEvent(templateData.container, 'mousedown')(e => {
disposables.add(DOM.addDisposableListener(templateData.container, 'mousedown', e => {
const result = getIconLabelNameFromHTMLElement(e.target);
if (result) {
compressedNavigationController.setIndex(result.index);
}
}, undefined, disposables);
}));
disposables.add(toDisposable(() => this.compressedNavigationControllers.delete(stat)));
@@ -48,13 +48,13 @@ import { textLinkForeground } from 'vs/platform/theme/common/colorRegistry';
import { IConfigurationService } from 'vs/platform/configuration/common/configuration';
import { OS, OperatingSystem } from 'vs/base/common/platform';
import { IFileService } from 'vs/platform/files/common/files';
import { domEvent } from 'vs/base/browser/event';
import { StandardKeyboardEvent } from 'vs/base/browser/keyboardEvent';
import { KeyCode } from 'vs/base/common/keyCodes';
import { Progress } from 'vs/platform/progress/common/progress';
import { ActionViewItem } from 'vs/base/browser/ui/actionbar/actionViewItems';
import { Codicon } from 'vs/base/common/codicons';
import { registerIcon } from 'vs/platform/theme/common/iconRegistry';
import { DomEmitter } from 'vs/base/browser/event';
interface IResourceMarkersTemplateData {
resourceLabel: IResourceLabel;
@@ -417,10 +417,10 @@ class MarkerWidget extends Disposable {
this._codeLink.setAttribute('href', codeLink);
this._codeLink.tabIndex = 0;
const onClick = Event.chain(domEvent(this._codeLink, 'click'))
const onClick = Event.chain(this._register(new DomEmitter(this._codeLink, 'click')).event)
.filter(e => ((this._clickModifierKey === 'meta' && e.metaKey) || (this._clickModifierKey === 'ctrl' && e.ctrlKey) || (this._clickModifierKey === 'alt' && e.altKey)))
.event;
const onEnterPress = Event.chain(domEvent(this._codeLink, 'keydown'))
const onEnterPress = Event.chain(this._register(new DomEmitter(this._codeLink, 'keydown')).event)
.map(e => new StandardKeyboardEvent(e))
.filter(e => e.keyCode === KeyCode.Enter)
.event;
@@ -36,7 +36,6 @@ import { ActionBar, IActionViewItem } from 'vs/base/browser/ui/actionbar/actionb
import { IMenuService, MenuId } from 'vs/platform/actions/common/actions';
import { IKeybindingService } from 'vs/platform/keybinding/common/keybinding';
import { StandardKeyboardEvent, IKeyboardEvent } from 'vs/base/browser/keyboardEvent';
import { domEvent } from 'vs/base/browser/event';
import { ResourceLabels } from 'vs/workbench/browser/labels';
import { IMarker, IMarkerService, MarkerSeverity } from 'vs/platform/markers/common/markers';
import { withUndefinedAsNull } from 'vs/base/common/types';
@@ -443,7 +442,7 @@ export class MarkersView extends ViewPane implements IMarkersView {
}));
// move focus to input, whenever a key is pressed in the panel container
this._register(domEvent(parent, 'keydown')(e => {
this._register(dom.addDisposableListener(parent, 'keydown', e => {
if (this.keybindingService.mightProducePrintableCharacter(new StandardKeyboardEvent(e))) {
this.focusFilter();
}
@@ -263,6 +263,7 @@ export interface ICellViewModel extends IGenericCellViewModel {
handle: number;
uri: URI;
language: string;
readonly mime: string;
cellKind: CellKind;
lineNumbers: 'on' | 'off' | 'inherit';
focusMode: CellFocusMode;
@@ -72,6 +72,7 @@ import { NotebookOptions } from 'vs/workbench/contrib/notebook/common/notebookOp
import { ViewContext } from 'vs/workbench/contrib/notebook/browser/viewModel/viewContext';
import { NotebookEditorToolbar } from 'vs/workbench/contrib/notebook/browser/notebookEditorToolbar';
import { INotebookRendererMessagingService } from 'vs/workbench/contrib/notebook/common/notebookRendererMessagingService';
import { IMarkupCellInitialization } from 'vs/workbench/contrib/notebook/browser/view/renderers/webviewMessages';
const $ = DOM.$;
@@ -1385,18 +1386,13 @@ export class NotebookEditorWidget extends Disposable implements INotebookEditor
}
}
await this._webview!.initializeMarkup(requests.map(request => ({
mime: 'text/markdown',
cellId: request[0].id,
cellHandle: request[0].handle,
content: request[0].getText(),
offset: request[1],
visible: false,
})));
await this._webview!.initializeMarkup(requests.map(([model, offset]) => this.createMarkupCellInitialization(model, offset)));
} else {
const initRequests = viewModel.viewCells.filter(cell => cell.cellKind === CellKind.Markup).slice(0, 5).map(cell => ({
cellId: cell.id, cellHandle: cell.handle, content: cell.getText(), offset: -10000, visible: false, mime: 'text/markdown',
}));
const initRequests = viewModel.viewCells
.filter(cell => cell.cellKind === CellKind.Markup)
.slice(0, 5)
.map(cell => this.createMarkupCellInitialization(cell, -10000));
await this._webview!.initializeMarkup(initRequests);
// no cached view state so we are rendering the first viewport
@@ -1420,6 +1416,17 @@ export class NotebookEditorWidget extends Disposable implements INotebookEditor
}
}
private createMarkupCellInitialization(model: ICellViewModel, offset: number): IMarkupCellInitialization {
return ({
mime: model.mime,
cellId: model.id,
cellHandle: model.handle,
content: model.getText(),
offset: offset,
visible: false,
});
}
restoreListViewState(viewState: INotebookEditorViewState | undefined): void {
if (viewState?.scrollPosition !== undefined) {
this._list.scrollTop = viewState!.scrollPosition.top;
@@ -2264,7 +2271,7 @@ export class NotebookEditorWidget extends Disposable implements INotebookEditor
const cellTop = this._list.getAbsoluteTopOfElement(cell);
await this._webview.showMarkdownPreview({
mime: 'text/markdown',
mime: cell.mime,
cellHandle: cell.handle,
cellId: cell.id,
content: cell.getText(),
@@ -5,6 +5,7 @@
import * as DOM from 'vs/base/browser/dom';
import { Disposable, DisposableStore, toDisposable } from 'vs/base/common/lifecycle';
import { Mimes } from 'vs/base/common/mime';
import { dirname } from 'vs/base/common/resources';
import { URI } from 'vs/base/common/uri';
import { MarkdownRenderer } from 'vs/editor/browser/core/markdownRenderer';
@@ -215,7 +216,7 @@ class PlainTextRendererContrib extends Disposable implements IOutputRendererCont
}
getMimetypes() {
return ['text/plain'];
return [Mimes.text];
}
constructor(
@@ -270,7 +271,7 @@ class MdRendererContrib extends Disposable implements IOutputRendererContributio
}
getMimetypes() {
return ['text/markdown'];
return [Mimes.markdown];
}
constructor(
@@ -525,17 +525,12 @@ var requirejs = (function() {
}
case 'focus-editor':
{
const resolvedResult = this.resolveOutputId(data.id);
if (resolvedResult) {
const latestCell = this.notebookEditor.getCellByInfo(resolvedResult.cellInfo);
if (!latestCell) {
return;
}
const cell = this.notebookEditor.getCellById(data.cellId);
if (cell) {
if (data.focusNext) {
this.notebookEditor.focusNextNotebookCell(latestCell, 'editor');
this.notebookEditor.focusNextNotebookCell(cell, 'editor');
} else {
this.notebookEditor.focusNotebookCell(latestCell, 'editor');
this.notebookEditor.focusNotebookCell(cell, 'editor');
}
}
break;
@@ -812,6 +807,7 @@ var requirejs = (function() {
this.hiddenInsetMapping.delete(request.output);
return {
cellId: request.cell.id,
outputId: id,
cellTop: request.cellTop,
outputOffset: request.outputOffset,
@@ -826,7 +822,7 @@ var requirejs = (function() {
this._sendMessageToWebview({
type: 'view-scroll',
widgets: widgets,
markdownPreviews,
markupCells: markdownPreviews,
});
}
@@ -3,9 +3,7 @@
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import * as DOM from 'vs/base/browser/dom';
import { domEvent } from 'vs/base/browser/event';
import { Delayer } from 'vs/base/common/async';
import { Disposable } from 'vs/base/common/lifecycle';
import * as platform from 'vs/base/common/platform';
@@ -49,8 +47,8 @@ export class CellDragAndDropController extends Disposable {
this.listInsertionIndicator = DOM.append(insertionIndicatorContainer, $('.cell-list-insertion-indicator'));
this._register(domEvent(document.body, DOM.EventType.DRAG_START, true)(this.onGlobalDragStart.bind(this)));
this._register(domEvent(document.body, DOM.EventType.DRAG_END, true)(this.onGlobalDragEnd.bind(this)));
this._register(DOM.addDisposableListener(document.body, DOM.EventType.DRAG_START, this.onGlobalDragStart.bind(this), true));
this._register(DOM.addDisposableListener(document.body, DOM.EventType.DRAG_END, this.onGlobalDragEnd.bind(this), true));
const addCellDragListener = (eventType: string, handler: (e: CellDragEvent) => void) => {
this._register(DOM.addDisposableListener(
@@ -300,7 +298,7 @@ export class CellDragAndDropController extends Disposable {
const container = templateData.container;
dragHandle.setAttribute('draggable', 'true');
templateData.disposables.add(domEvent(dragHandle, DOM.EventType.DRAG_END)(() => {
templateData.disposables.add(DOM.addDisposableListener(dragHandle, DOM.EventType.DRAG_END, () => {
if (!this.notebookEditor.notebookOptions.getLayoutConfiguration().dragAndDropEnabled) {
return;
}
@@ -310,7 +308,7 @@ export class CellDragAndDropController extends Disposable {
this.dragCleanup();
}));
templateData.disposables.add(domEvent(dragHandle, DOM.EventType.DRAG_START)(event => {
templateData.disposables.add(DOM.addDisposableListener(dragHandle, DOM.EventType.DRAG_START, event => {
if (!event.dataTransfer) {
return;
}
@@ -5,7 +5,6 @@
import { getPixelRatio, getZoomLevel } from 'vs/base/browser/browser';
import * as DOM from 'vs/base/browser/dom';
import { domEvent } from 'vs/base/browser/event';
import * as aria from 'vs/base/browser/ui/aria/aria';
import { renderIcon } from 'vs/base/browser/ui/iconLabel/iconLabels';
import { IListRenderer, IListVirtualDelegate } from 'vs/base/browser/ui/list/list';
@@ -261,7 +260,7 @@ abstract class AbstractCellRenderer {
}
protected addExpandListener(templateData: BaseCellRenderTemplate): void {
templateData.disposables.add(domEvent(templateData.expandButton, DOM.EventType.CLICK)(() => {
templateData.disposables.add(DOM.addDisposableListener(templateData.expandButton, DOM.EventType.CLICK, () => {
if (!templateData.currentRenderedCell) {
return;
}
@@ -59,7 +59,7 @@ export interface IScrollAckMessage extends BaseToWebviewMessage {
export interface IBlurOutputMessage extends BaseToWebviewMessage {
readonly type: 'focus-editor';
readonly id: string;
readonly cellId: string;
readonly focusNext?: boolean;
}
@@ -174,6 +174,7 @@ export interface ICreationRequestMessage {
}
export interface IContentWidgetTopRequest {
readonly cellId: string;
readonly outputId: string;
readonly cellTop: number;
readonly outputOffset: number;
@@ -183,7 +184,7 @@ export interface IContentWidgetTopRequest {
export interface IViewScrollTopRequestMessage {
readonly type: 'view-scroll';
readonly widgets: IContentWidgetTopRequest[];
readonly markdownPreviews: { id: string; top: number; }[];
readonly markupCells: { id: string; top: number; }[];
}
export interface IScrollRequestMessage {
@@ -320,12 +320,12 @@ async function webviewPreloads(style: PreloadStyles, options: PreloadOptions, re
}
}
function createFocusSink(cellId: string, outputId: string, focusNext?: boolean) {
function createFocusSink(cellId: string, focusNext?: boolean) {
const element = document.createElement('div');
element.tabIndex = 0;
element.addEventListener('focus', () => {
postNotebookMessage<webviewMessages.IBlurOutputMessage>('focus-editor', {
id: outputId,
cellId: cellId,
focusNext
});
});
@@ -357,7 +357,7 @@ async function webviewPreloads(style: PreloadStyles, options: PreloadOptions, re
return false;
}
class FocusTracker {
class OutputFocusTracker {
private _outputId: string;
private _hasFocus: boolean = false;
private _loosingFocus: boolean = false;
@@ -405,14 +405,14 @@ async function webviewPreloads(style: PreloadStyles, options: PreloadOptions, re
}
}
const focusTrackers = new Map<string, FocusTracker>();
const outputFocusTrackers = new Map<string, OutputFocusTracker>();
function addFocusTracker(element: HTMLElement, outputId: string): void {
if (focusTrackers.has(outputId)) {
focusTrackers.get(outputId)?.dispose();
function addOutputFocusTracker(element: HTMLElement, outputId: string): void {
if (outputFocusTrackers.has(outputId)) {
outputFocusTrackers.get(outputId)?.dispose();
}
focusTrackers.set(outputId, new FocusTracker(element, outputId));
outputFocusTrackers.set(outputId, new OutputFocusTracker(element, outputId));
}
function createEmitter<T>(listenerChange: (listeners: Set<Listener<T>>) => void = () => undefined): EmitterLike<T> {
@@ -510,44 +510,46 @@ async function webviewPreloads(style: PreloadStyles, options: PreloadOptions, re
switch (event.data.type) {
case 'initializeMarkup':
await notebookDocument.ensureMarkupCells(event.data.cells);
await viewModel.ensureMarkupCells(event.data.cells);
dimensionUpdater.updateImmediately();
postNotebookMessage('initializedMarkup', {});
break;
case 'createMarkupCell':
notebookDocument.ensureMarkupCells([event.data.cell]);
viewModel.ensureMarkupCells([event.data.cell]);
break;
case 'showMarkupCell':
notebookDocument.showMarkupCell(event.data.id, event.data.top, event.data.content);
viewModel.showMarkupCell(event.data.id, event.data.top, event.data.content);
break;
case 'hideMarkupCells':
for (const id of event.data.ids) {
notebookDocument.hideMarkupCell(id);
viewModel.hideMarkupCell(id);
}
break;
case 'unhideMarkupCells':
for (const id of event.data.ids) {
notebookDocument.unhideMarkupCell(id);
viewModel.unhideMarkupCell(id);
}
break;
case 'deleteMarkupCell':
for (const id of event.data.ids) {
notebookDocument.deleteMarkupCell(id);
viewModel.deleteMarkupCell(id);
}
break;
case 'updateSelectedMarkupCells':
notebookDocument.updateSelectedCells(event.data.selectedCellIds);
viewModel.updateSelectedCells(event.data.selectedCellIds);
break;
case 'html': {
const data = event.data;
outputs.enqueue(event.data.outputId, async (state) => {
const outputId = data.outputId;
outputRunner.enqueue(event.data.outputId, async (state) => {
const preloadsAndErrors = await Promise.all<unknown>([
data.rendererId ? renderers.load(data.rendererId) : undefined,
...data.requiredPreloads.map(p => kernelPreloads.waitFor(p.uri)),
@@ -557,48 +559,9 @@ async function webviewPreloads(style: PreloadStyles, options: PreloadOptions, re
return;
}
let cellOutputContainer = document.getElementById(data.cellId);
const outputId = data.outputId;
if (!cellOutputContainer) {
const container = document.getElementById('container')!;
const cellOutput = viewModel.ensureOutputCell(data.cellId, data.cellTop);
const outputNode = cellOutput.createOutputNode(outputId, data.outputOffset, data.left);
const upperWrapperElement = createFocusSink(data.cellId, outputId);
container.appendChild(upperWrapperElement);
const newElement = document.createElement('div');
newElement.id = data.cellId;
newElement.classList.add('cell_container');
container.appendChild(newElement);
cellOutputContainer = newElement;
const lowerWrapperElement = createFocusSink(data.cellId, outputId, true);
container.appendChild(lowerWrapperElement);
}
cellOutputContainer.style.position = 'absolute';
cellOutputContainer.style.top = data.cellTop + 'px';
const outputContainer = document.createElement('div');
outputContainer.classList.add('output_container');
outputContainer.style.position = 'absolute';
outputContainer.style.overflow = 'hidden';
outputContainer.style.maxHeight = '0px';
outputContainer.style.top = `${data.outputOffset}px`;
const outputNode = document.createElement('div');
outputNode.classList.add('output');
outputNode.style.position = 'absolute';
outputNode.style.top = `0px`;
outputNode.style.left = data.left + 'px';
// outputNode.style.width = 'calc(100% - ' + data.left + 'px)';
// outputNode.style.minHeight = '32px';
outputNode.style.padding = '0px';
outputNode.id = outputId;
addMouseoverListeners(outputNode, outputId);
addFocusTracker(outputNode, outputId);
const content = data.content;
if (content.type === RenderOutputType.Html) {
const trustedHtml = ttPolicy?.createHTML(content.htmlContent) ?? content.htmlContent;
@@ -634,8 +597,6 @@ async function webviewPreloads(style: PreloadStyles, options: PreloadOptions, re
}
}
cellOutputContainer.appendChild(outputContainer);
outputContainer.appendChild(outputNode);
resizeObserver.observe(outputNode, outputId, true);
if (content.type === RenderOutputType.Html) {
@@ -661,7 +622,7 @@ async function webviewPreloads(style: PreloadStyles, options: PreloadOptions, re
}
// don't hide until after this step so that the height is right
cellOutputContainer.style.visibility = data.initiallyHidden ? 'hidden' : 'visible';
cellOutput.element.style.visibility = data.initiallyHidden ? 'hidden' : 'visible';
});
break;
}
@@ -670,84 +631,46 @@ async function webviewPreloads(style: PreloadStyles, options: PreloadOptions, re
// const date = new Date();
// console.log('----- will scroll ---- ', date.getMinutes() + ':' + date.getSeconds() + ':' + date.getMilliseconds());
for (const request of event.data.widgets) {
const widget = document.getElementById(request.outputId);
if (widget) {
widget.parentElement!.parentElement!.style.top = `${request.cellTop}px`;
widget.parentElement!.style.top = `${request.outputOffset}px`;
if (request.forceDisplay) {
widget.parentElement!.parentElement!.style.visibility = 'visible';
}
}
}
for (const cell of event.data.markdownPreviews) {
const container = document.getElementById(cell.id);
if (container) {
container.style.top = `${cell.top}px`;
}
}
viewModel.updateOutputsScroll(event.data.widgets);
viewModel.updateMarkupScrolls(event.data.markupCells);
break;
}
case 'clear':
renderers.clearAll();
viewModel.clearAll();
document.getElementById('container')!.innerText = '';
focusTrackers.forEach(ft => {
outputFocusTrackers.forEach(ft => {
ft.dispose();
});
focusTrackers.clear();
outputFocusTrackers.clear();
break;
case 'clearOutput': {
const output = document.getElementById(event.data.outputId);
const { rendererId, outputId } = event.data;
outputs.cancelOutput(outputId);
if (output && output.parentNode) {
if (rendererId) {
renderers.clearOutput(rendererId, outputId);
}
output.parentNode.removeChild(output);
}
const { cellId, rendererId, outputId } = event.data;
outputRunner.cancelOutput(outputId);
viewModel.clearOutput(cellId, outputId, rendererId);
break;
}
case 'hideOutput': {
const { outputId } = event.data;
outputs.enqueue(event.data.outputId, () => {
const container = document.getElementById(outputId)?.parentElement?.parentElement;
if (container) {
container.style.visibility = 'hidden';
}
const { cellId, outputId } = event.data;
outputRunner.enqueue(outputId, () => {
viewModel.hideOutput(cellId);
});
break;
}
case 'showOutput': {
const { outputId, cellTop: top } = event.data;
outputs.enqueue(event.data.outputId, () => {
const output = document.getElementById(outputId);
if (output) {
output.parentElement!.parentElement!.style.visibility = 'visible';
output.parentElement!.parentElement!.style.top = top + 'px';
dimensionUpdater.update(outputId, output.clientHeight, {
isOutput: true,
});
}
const { outputId, cellTop, cellId } = event.data;
outputRunner.enqueue(outputId, () => {
viewModel.showOutput(cellId, outputId, cellTop);
});
break;
}
case 'ack-dimension':
{
const { outputId, height } = event.data;
const output = document.getElementById(outputId);
if (output) {
output.parentElement!.style.maxHeight = `${height}px`;
output.parentElement!.style.height = `${height}px`;
}
break;
}
case 'ack-dimension': {
const { cellId, outputId, height } = event.data;
viewModel.updateOutputHeight(cellId, outputId, height);
break;
}
case 'preload':
const resources = event.data.resources;
for (const { uri, originalUri } of resources) {
@@ -790,12 +713,7 @@ async function webviewPreloads(style: PreloadStyles, options: PreloadOptions, re
break;
case 'notebookOptions':
currentOptions = event.data.options;
// Update markdown previews
for (const markdownContainer of document.querySelectorAll('.preview')) {
setMarkupContainerDraggable(markdownContainer, currentOptions.dragAndDropEnabled);
}
viewModel.toggleDragDropEnabled(currentOptions.dragAndDropEnabled);
break;
}
});
@@ -905,8 +823,9 @@ async function webviewPreloads(style: PreloadStyles, options: PreloadOptions, re
}
};
const outputs = new class {
private outputs = new Map<string, { cancelled: boolean; queue: Promise<unknown> }>();
const outputRunner = new class {
private readonly outputs = new Map<string, { cancelled: boolean; queue: Promise<unknown> }>();
/**
* Pushes the action onto the list of actions for the given output ID,
* ensuring that it's run in-order.
@@ -973,14 +892,14 @@ async function webviewPreloads(style: PreloadStyles, options: PreloadOptions, re
public clearAll() {
outputs.cancelAll();
outputRunner.cancelAll();
for (const renderer of this._renderers.values()) {
renderer.api?.disposeOutputItem?.();
}
}
public clearOutput(rendererId: string, outputId: string) {
outputs.cancelOutput(outputId);
outputRunner.cancelOutput(outputId);
this._renderers.get(rendererId)?.api?.disposeOutputItem?.(outputId);
}
@@ -1001,9 +920,10 @@ async function webviewPreloads(style: PreloadStyles, options: PreloadOptions, re
let hasPostedRenderedMathTelemetry = false;
const unsupportedKatexTermsRegex = /(\\(?:abovewithdelims|array|Arrowvert|arrowvert|atopwithdelims|bbox|bracevert|buildrel|cancelto|cases|class|cssId|ddddot|dddot|DeclareMathOperator|definecolor|displaylines|enclose|eqalign|eqalignno|eqref|hfil|hfill|idotsint|iiiint|label|leftarrowtail|leftroot|leqalignno|lower|mathtip|matrix|mbox|mit|mmlToken|moveleft|moveright|mspace|newenvironment|Newextarrow|notag|oldstyle|overparen|overwithdelims|pmatrix|raise|ref|renewenvironment|require|root|Rule|scr|shoveleft|shoveright|sideset|skew|Space|strut|style|texttip|Tiny|toggle|underparen|unicode|uproot)\b)/gi;
const notebookDocument = new class {
const viewModel = new class ViewModel {
private readonly _markupCells = new Map<string, MarkupCell>();
private readonly _outputCells = new Map<string, OutputCell>();
private async createMarkupCell(init: webviewMessages.IMarkupCellInitialization, top: number): Promise<MarkupCell> {
const existing = this._markupCells.get(init.cellId);
@@ -1012,11 +932,11 @@ async function webviewPreloads(style: PreloadStyles, options: PreloadOptions, re
return existing;
}
const markdownCell = new MarkupCell(init.cellId, init.mime, init.content, top);
this._markupCells.set(init.cellId, markdownCell);
const cell = new MarkupCell(init.cellId, init.mime, init.content, top);
this._markupCells.set(init.cellId, cell);
await markdownCell.ready;
return markdownCell;
await cell.ready;
return cell;
}
public async ensureMarkupCells(update: readonly webviewMessages.IMarkupCellInitialization[]): Promise<void> {
@@ -1074,13 +994,71 @@ async function webviewPreloads(style: PreloadStyles, options: PreloadOptions, re
cell.setSelected(selectedCellSet.has(cell.id));
}
}
public toggleDragDropEnabled(dragAndDropEnabled: boolean) {
for (const cell of this._markupCells.values()) {
cell.toggleDragDropEnabled(dragAndDropEnabled);
}
}
public updateMarkupScrolls(markupCells: { id: string; top: number; }[]) {
for (const { id, top } of markupCells) {
const cell = this._markupCells.get(id);
if (cell) {
cell.element.style.top = `${top}px`;
}
}
}
public clearAll() {
this._markupCells.clear();
this._outputCells.clear();
}
public ensureOutputCell(cellId: string, cellTop: number): OutputCell {
let cell = this._outputCells.get(cellId);
if (!cell) {
cell = new OutputCell(cellId);
this._outputCells.set(cellId, cell);
}
cell.element.style.top = cellTop + 'px';
return cell;
}
public clearOutput(cellId: string, outputId: string, rendererId: string | undefined) {
const cell = this._outputCells.get(cellId);
cell?.clearOutput(outputId, rendererId);
}
public showOutput(cellId: string, outputId: string, top: number) {
const cell = this._outputCells.get(cellId);
cell?.show(outputId, top);
}
public hideOutput(cellId: string) {
const cell = this._outputCells.get(cellId);
cell?.hide();
}
public updateOutputHeight(cellId: string, outputId: string, height: number) {
const cell = this._outputCells.get(cellId);
cell?.updateOutputHeight(outputId, height);
}
public updateOutputsScroll(updates: webviewMessages.IContentWidgetTopRequest[]) {
for (const request of updates) {
const cell = this._outputCells.get(request.cellId);
cell?.updateScroll(request);
}
}
}();
class MarkupCell implements IOutputItem {
public readonly ready: Promise<void>;
/// Internal field that holds markdown text
/// Internal field that holds text content
private _content: string;
constructor(id: string, mime: string, content: string, top: number) {
@@ -1098,6 +1076,7 @@ async function webviewPreloads(style: PreloadStyles, options: PreloadOptions, re
this.element.classList.add('preview');
this.element.style.position = 'absolute';
this.element.style.top = top + 'px';
this.toggleDragDropEnabled(currentOptions.dragAndDropEnabled);
root.appendChild(this.element);
this.addEventListeners();
@@ -1155,18 +1134,16 @@ async function webviewPreloads(style: PreloadStyles, options: PreloadOptions, re
postNotebookMessage<webviewMessages.IMouseLeaveMarkupCellMessage>('mouseLeaveMarkupCell', { cellId: this.id });
});
setMarkupContainerDraggable(this.element, currentOptions.dragAndDropEnabled);
this.element.addEventListener('dragstart', e => {
markdownPreviewDragManager.startDrag(e, this.id);
markupCellDragManager.startDrag(e, this.id);
});
this.element.addEventListener('drag', e => {
markdownPreviewDragManager.updateDrag(e, this.id);
markupCellDragManager.updateDrag(e, this.id);
});
this.element.addEventListener('dragend', e => {
markdownPreviewDragManager.endDrag(e, this.id);
markupCellDragManager.endDrag(e, this.id);
});
}
@@ -1223,6 +1200,125 @@ async function webviewPreloads(style: PreloadStyles, options: PreloadOptions, re
public setSelected(selected: boolean) {
this.element.classList.toggle('selected', selected);
}
public toggleDragDropEnabled(enabled: boolean) {
if (enabled) {
this.element.classList.add('draggable');
this.element.setAttribute('draggable', 'true');
} else {
this.element.classList.remove('draggable');
this.element.removeAttribute('draggable');
}
}
}
class OutputCell {
public readonly element: HTMLElement;
public readonly outputElements = new Map</*outputId*/ string, HTMLElement>();
constructor(cellId: string) {
const container = document.getElementById('container')!;
const upperWrapperElement = createFocusSink(cellId);
container.appendChild(upperWrapperElement);
this.element = document.createElement('div');
this.element.style.position = 'absolute';
this.element.id = cellId;
this.element.classList.add('cell_container');
container.appendChild(this.element);
this.element = this.element;
const lowerWrapperElement = createFocusSink(cellId, true);
container.appendChild(lowerWrapperElement);
}
public createOutputNode(outputId: string, outputOffset: number, left: number): HTMLElement {
let outputContainer = this.outputElements.get(outputId);
if (!outputContainer) {
outputContainer = document.createElement('div');
outputContainer.classList.add('output_container');
outputContainer.style.position = 'absolute';
outputContainer.style.overflow = 'hidden';
this.element.appendChild(outputContainer);
this.outputElements.set(outputId, outputContainer);
}
outputContainer.innerText = '';
outputContainer.style.maxHeight = '0px';
outputContainer.style.top = `${outputOffset}px`;
const outputNode = document.createElement('div');
outputNode.id = outputId;
outputNode.classList.add('output');
outputNode.style.position = 'absolute';
outputNode.style.top = `0px`;
outputNode.style.left = left + 'px';
outputNode.style.padding = '0px';
outputContainer.appendChild(outputNode);
addMouseoverListeners(outputNode, outputId);
addOutputFocusTracker(outputNode, outputId);
return outputNode;
}
public clearOutput(outputId: string, rendererId: string | undefined) {
const outputContainer = this.outputElements.get(outputId);
if (!outputContainer) {
return;
}
if (rendererId) {
renderers.clearOutput(rendererId, outputId);
}
outputContainer.remove();
this.outputElements.delete(outputId);
}
public show(outputId: string, top: number) {
const outputContainer = this.outputElements.get(outputId);
if (!outputContainer) {
return;
}
this.element.style.visibility = 'visible';
this.element.style.top = `${top}px`;
dimensionUpdater.update(outputId, outputContainer.clientHeight, {
isOutput: true,
});
}
public hide() {
this.element.style.visibility = 'hidden';
}
public updateOutputHeight(outputId: string, height: number) {
const outputContainer = this.outputElements.get(outputId);
if (!outputContainer) {
return;
}
outputContainer.style.maxHeight = `${height}px`;
outputContainer.style.height = `${height}px`;
}
public updateScroll(request: webviewMessages.IContentWidgetTopRequest) {
this.element.style.top = `${request.cellTop}px`;
const outputContainer = this.outputElements.get(request.outputId);
if (outputContainer) {
outputContainer.style.top = `${request.outputOffset}px`;
}
if (request.forceDisplay) {
this.element.style.visibility = 'visible';
}
}
}
vscode.postMessage({
@@ -1230,16 +1326,6 @@ async function webviewPreloads(style: PreloadStyles, options: PreloadOptions, re
type: 'initialized'
});
function setMarkupContainerDraggable(element: Element, isDraggable: boolean) {
if (isDraggable) {
element.classList.add('draggable');
element.setAttribute('draggable', 'true');
} else {
element.classList.remove('draggable');
element.removeAttribute('draggable');
}
}
function postNotebookMessage<T extends webviewMessages.FromWebviewMessage>(
type: T['type'],
properties: Omit<T, '__vscode_notebook_message' | 'type'>
@@ -1251,13 +1337,13 @@ async function webviewPreloads(style: PreloadStyles, options: PreloadOptions, re
});
}
const markdownPreviewDragManager = new class MarkdownPreviewDragManager {
const markupCellDragManager = new class MarkupCellDragManager {
private currentDrag: { cellId: string, clientY: number } | undefined;
constructor() {
document.addEventListener('dragover', e => {
// Allow dropping dragged markdown cells
// Allow dropping dragged markup cells
e.preventDefault();
});
@@ -18,6 +18,7 @@ import { NotebookCellTextModel } from 'vs/workbench/contrib/notebook/common/mode
import { IConfigurationService } from 'vs/platform/configuration/common/configuration';
import { IResolvedTextEditorModel, ITextModelService } from 'vs/editor/common/services/resolverService';
import { ViewContext } from 'vs/workbench/contrib/notebook/browser/viewModel/viewContext';
import { Mimes } from 'vs/base/common/mime';
export abstract class BaseCellViewModel extends Disposable {
@@ -46,6 +47,16 @@ export abstract class BaseCellViewModel extends Disposable {
return this.model.language;
}
get mime(): string {
switch (this.language) {
case 'markdown':
return Mimes.markdown;
default:
return Mimes.text;
}
}
abstract cellKind: CellKind;
private _editState: CellEditState = CellEditState.Preview;
@@ -7,6 +7,7 @@ import { CancellationToken } from 'vs/base/common/cancellation';
import { IDiffResult, ISequence } from 'vs/base/common/diff/diff';
import { Event } from 'vs/base/common/event';
import * as glob from 'vs/base/common/glob';
import { Mimes } from 'vs/base/common/mime';
import { Schemas } from 'vs/base/common/network';
import { basename } from 'vs/base/common/path';
import { isWindows } from 'vs/base/common/platform';
@@ -34,16 +35,16 @@ export const NOTEBOOK_DISPLAY_ORDER = [
'application/javascript',
'text/html',
'image/svg+xml',
'text/markdown',
Mimes.markdown,
'image/png',
'image/jpeg',
'text/plain'
Mimes.text
];
export const ACCESSIBLE_NOTEBOOK_DISPLAY_ORDER = [
'text/markdown',
Mimes.markdown,
'application/json',
'text/plain',
Mimes.text,
'text/html',
'image/svg+xml',
'image/png',
@@ -586,8 +587,8 @@ const _mimeTypeInfo = new Map<string, MimeTypeInfo>([
['image/git', { alwaysSecure: true, supportedByCore: true }],
['image/svg+xml', { supportedByCore: true }],
['application/json', { alwaysSecure: true, supportedByCore: true }],
['text/markdown', { alwaysSecure: true, supportedByCore: true }],
['text/plain', { alwaysSecure: true, supportedByCore: true }],
[Mimes.markdown, { alwaysSecure: true, supportedByCore: true }],
[Mimes.text, { alwaysSecure: true, supportedByCore: true }],
['text/html', { supportedByCore: true }],
['text/x-javascript', { alwaysSecure: true, supportedByCore: true }], // secure because rendered as text, not executed
['application/vnd.code.notebook.error', { alwaysSecure: true, supportedByCore: true }],
@@ -4,11 +4,12 @@
*--------------------------------------------------------------------------------------------*/
import * as assert from 'assert';
import { NOTEBOOK_DISPLAY_ORDER, sortMimeTypes, CellKind, diff, CellUri, NotebookWorkingCopyTypeIdentifier } from 'vs/workbench/contrib/notebook/common/notebookCommon';
import { cellRangesToIndexes, cellIndexesToRanges } from 'vs/workbench/contrib/notebook/common/notebookRange';
import { TestCell, setupInstantiationService } from 'vs/workbench/contrib/notebook/test/testNotebookEditor';
import { Mimes } from 'vs/base/common/mime';
import { URI } from 'vs/base/common/uri';
import { IModeService } from 'vs/editor/common/services/modeService';
import { CellKind, CellUri, diff, NotebookWorkingCopyTypeIdentifier, NOTEBOOK_DISPLAY_ORDER, sortMimeTypes } from 'vs/workbench/contrib/notebook/common/notebookCommon';
import { cellIndexesToRanges, cellRangesToIndexes } from 'vs/workbench/contrib/notebook/common/notebookRange';
import { setupInstantiationService, TestCell } from 'vs/workbench/contrib/notebook/test/testNotebookEditor';
suite('NotebookCommon', () => {
const instantiationService = setupInstantiationService();
@@ -23,30 +24,30 @@ suite('NotebookCommon', () => {
'application/javascript',
'text/html',
'image/svg+xml',
'text/markdown',
Mimes.markdown,
'image/png',
'image/jpeg',
'text/plain'
Mimes.text
], [], defaultDisplayOrder),
[
'application/json',
'application/javascript',
'text/html',
'image/svg+xml',
'text/markdown',
Mimes.markdown,
'image/png',
'image/jpeg',
'text/plain'
Mimes.text
]
);
assert.deepStrictEqual(sortMimeTypes(
[
'application/json',
'text/markdown',
Mimes.markdown,
'application/javascript',
'text/html',
'text/plain',
Mimes.text,
'image/png',
'image/jpeg',
'image/svg+xml'
@@ -56,18 +57,18 @@ suite('NotebookCommon', () => {
'application/javascript',
'text/html',
'image/svg+xml',
'text/markdown',
Mimes.markdown,
'image/png',
'image/jpeg',
'text/plain'
Mimes.text
]
);
assert.deepStrictEqual(sortMimeTypes(
[
'text/markdown',
Mimes.markdown,
'application/json',
'text/plain',
Mimes.text,
'image/jpeg',
'application/javascript',
'text/html',
@@ -79,10 +80,10 @@ suite('NotebookCommon', () => {
'application/javascript',
'text/html',
'image/svg+xml',
'text/markdown',
Mimes.markdown,
'image/png',
'image/jpeg',
'text/plain'
Mimes.text
]
);
});
@@ -97,22 +98,22 @@ suite('NotebookCommon', () => {
'application/javascript',
'text/html',
'image/svg+xml',
'text/markdown',
Mimes.markdown,
'image/png',
'image/jpeg',
'text/plain'
Mimes.text
],
[
'image/png',
'text/plain',
'text/markdown',
Mimes.text,
Mimes.markdown,
'text/html',
'application/json'
], defaultDisplayOrder),
[
'image/png',
'text/plain',
'text/markdown',
Mimes.text,
Mimes.markdown,
'text/html',
'application/json',
'application/javascript',
@@ -123,9 +124,9 @@ suite('NotebookCommon', () => {
assert.deepStrictEqual(sortMimeTypes(
[
'text/markdown',
Mimes.markdown,
'application/json',
'text/plain',
Mimes.text,
'application/javascript',
'text/html',
'image/svg+xml',
@@ -136,18 +137,18 @@ suite('NotebookCommon', () => {
'application/json',
'text/html',
'text/html',
'text/markdown',
Mimes.markdown,
'application/json'
], defaultDisplayOrder),
[
'application/json',
'text/html',
'text/markdown',
Mimes.markdown,
'application/javascript',
'image/svg+xml',
'image/png',
'image/jpeg',
'text/plain'
Mimes.text
]
);
});
@@ -165,7 +166,7 @@ suite('NotebookCommon', () => {
'text/html'
],
[
'text/markdown',
Mimes.markdown,
'text/html',
'application/json'
], defaultDisplayOrder),
@@ -189,7 +190,7 @@ suite('NotebookCommon', () => {
],
[
'application/vnd-vega*',
'text/markdown',
Mimes.markdown,
'text/html',
'application/json'
], defaultDisplayOrder),
@@ -5,6 +5,7 @@
import * as assert from 'assert';
import { LcsDiff } from 'vs/base/common/diff/diff';
import { Mimes } from 'vs/base/common/mime';
import { NotebookDiffEditorEventDispatcher } from 'vs/workbench/contrib/notebook/browser/diff/eventDispatcher';
import { NotebookTextDiffEditor } from 'vs/workbench/contrib/notebook/browser/diff/notebookTextDiffEditor';
import { CellKind, CellSequence } from 'vs/workbench/contrib/notebook/common/notebookCommon';
@@ -14,9 +15,9 @@ suite('NotebookCommon', () => {
test('diff different source', async () => {
await withTestNotebookDiffModel([
['x', 'javascript', CellKind.Code, [{ outputId: 'someOtherId', outputs: [{ mime: 'text/plain', data: new Uint8Array([3]) }] }], { custom: { metadata: { collapsed: false } }, executionOrder: 3 }],
['x', 'javascript', CellKind.Code, [{ outputId: 'someOtherId', outputs: [{ mime: Mimes.text, data: new Uint8Array([3]) }] }], { custom: { metadata: { collapsed: false } }, executionOrder: 3 }],
], [
['y', 'javascript', CellKind.Code, [{ outputId: 'someOtherId', outputs: [{ mime: 'text/plain', data: new Uint8Array([3]) }] }], { custom: { metadata: { collapsed: false } }, executionOrder: 3 }],
['y', 'javascript', CellKind.Code, [{ outputId: 'someOtherId', outputs: [{ mime: Mimes.text, data: new Uint8Array([3]) }] }], { custom: { metadata: { collapsed: false } }, executionOrder: 3 }],
], (model, accessor) => {
const diff = new LcsDiff(new CellSequence(model.original.notebook), new CellSequence(model.modified.notebook));
const diffResult = diff.ComputeDiff(false);
@@ -44,10 +45,10 @@ suite('NotebookCommon', () => {
test('diff different output', async () => {
await withTestNotebookDiffModel([
['x', 'javascript', CellKind.Code, [{ outputId: 'someId', outputs: [{ mime: 'text/plain', data: new Uint8Array([5]) }] }], { custom: { metadata: { collapsed: false } }, executionOrder: 5 }],
['x', 'javascript', CellKind.Code, [{ outputId: 'someId', outputs: [{ mime: Mimes.text, data: new Uint8Array([5]) }] }], { custom: { metadata: { collapsed: false } }, executionOrder: 5 }],
['', 'javascript', CellKind.Code, [], {}]
], [
['x', 'javascript', CellKind.Code, [{ outputId: 'someOtherId', outputs: [{ mime: 'text/plain', data: new Uint8Array([3]) }] }], { custom: { metadata: { collapsed: false } }, executionOrder: 3 }],
['x', 'javascript', CellKind.Code, [{ outputId: 'someOtherId', outputs: [{ mime: Mimes.text, data: new Uint8Array([3]) }] }], { custom: { metadata: { collapsed: false } }, executionOrder: 3 }],
['', 'javascript', CellKind.Code, [], {}]
], (model, accessor) => {
const diff = new LcsDiff(new CellSequence(model.original.notebook), new CellSequence(model.modified.notebook));
@@ -145,12 +146,12 @@ suite('NotebookCommon', () => {
test('diff foo/foe', async () => {
await withTestNotebookDiffModel([
[['def foe(x, y):\n', ' return x + y\n', 'foe(3, 2)'].join(''), 'javascript', CellKind.Code, [{ outputId: 'someId', outputs: [{ mime: 'text/plain', data: new Uint8Array([6]) }] }], { custom: { metadata: { collapsed: false } }, executionOrder: 5 }],
[['def foo(x, y):\n', ' return x * y\n', 'foo(1, 2)'].join(''), 'javascript', CellKind.Code, [{ outputId: 'someId', outputs: [{ mime: 'text/plain', data: new Uint8Array([2]) }] }], { custom: { metadata: { collapsed: false } }, executionOrder: 6 }],
[['def foe(x, y):\n', ' return x + y\n', 'foe(3, 2)'].join(''), 'javascript', CellKind.Code, [{ outputId: 'someId', outputs: [{ mime: Mimes.text, data: new Uint8Array([6]) }] }], { custom: { metadata: { collapsed: false } }, executionOrder: 5 }],
[['def foo(x, y):\n', ' return x * y\n', 'foo(1, 2)'].join(''), 'javascript', CellKind.Code, [{ outputId: 'someId', outputs: [{ mime: Mimes.text, data: new Uint8Array([2]) }] }], { custom: { metadata: { collapsed: false } }, executionOrder: 6 }],
['', 'javascript', CellKind.Code, [], {}]
], [
[['def foo(x, y):\n', ' return x * y\n', 'foo(1, 2)'].join(''), 'javascript', CellKind.Code, [{ outputId: 'someId', outputs: [{ mime: 'text/plain', data: new Uint8Array([6]) }] }], { custom: { metadata: { collapsed: false } }, executionOrder: 5 }],
[['def foe(x, y):\n', ' return x + y\n', 'foe(3, 2)'].join(''), 'javascript', CellKind.Code, [{ outputId: 'someId', outputs: [{ mime: 'text/plain', data: new Uint8Array([2]) }] }], { custom: { metadata: { collapsed: false } }, executionOrder: 6 }],
[['def foo(x, y):\n', ' return x * y\n', 'foo(1, 2)'].join(''), 'javascript', CellKind.Code, [{ outputId: 'someId', outputs: [{ mime: Mimes.text, data: new Uint8Array([6]) }] }], { custom: { metadata: { collapsed: false } }, executionOrder: 5 }],
[['def foe(x, y):\n', ' return x + y\n', 'foe(3, 2)'].join(''), 'javascript', CellKind.Code, [{ outputId: 'someId', outputs: [{ mime: Mimes.text, data: new Uint8Array([2]) }] }], { custom: { metadata: { collapsed: false } }, executionOrder: 6 }],
['', 'javascript', CellKind.Code, [], {}]
], (model, accessor) => {
const diff = new LcsDiff(new CellSequence(model.original.notebook), new CellSequence(model.modified.notebook));
@@ -272,13 +273,13 @@ suite('NotebookCommon', () => {
await withTestNotebookDiffModel([
['# Description', 'markdown', CellKind.Markup, [], { custom: { metadata: {} } }],
['x = 3', 'javascript', CellKind.Code, [], { custom: { metadata: { collapsed: true } }, executionOrder: 1 }],
['x', 'javascript', CellKind.Code, [{ outputId: 'someId', outputs: [{ mime: 'text/plain', data: new Uint8Array([3]) }] }], { custom: { metadata: { collapsed: false } }, executionOrder: 1 }],
['x', 'javascript', CellKind.Code, [{ outputId: 'someId', outputs: [{ mime: Mimes.text, data: new Uint8Array([3]) }] }], { custom: { metadata: { collapsed: false } }, executionOrder: 1 }],
['x', 'javascript', CellKind.Code, [], { custom: { metadata: { collapsed: false } } }]
], [
['# Description', 'markdown', CellKind.Markup, [], { custom: { metadata: {} } }],
['x = 3', 'javascript', CellKind.Code, [], { custom: { metadata: { collapsed: true } }, executionOrder: 1 }],
['x', 'javascript', CellKind.Code, [], { custom: { metadata: { collapsed: false } } }],
['x', 'javascript', CellKind.Code, [{ outputId: 'someId', outputs: [{ mime: 'text/plain', data: new Uint8Array([3]) }] }], { custom: { metadata: { collapsed: false } }, executionOrder: 1 }]
['x', 'javascript', CellKind.Code, [{ outputId: 'someId', outputs: [{ mime: Mimes.text, data: new Uint8Array([3]) }] }], { custom: { metadata: { collapsed: false } }, executionOrder: 1 }]
], async (model) => {
const diff = new LcsDiff(new CellSequence(model.original.notebook), new CellSequence(model.modified.notebook));
const diffResult = diff.ComputeDiff(false);
@@ -305,18 +306,18 @@ suite('NotebookCommon', () => {
await withTestNotebookDiffModel([
['# Description', 'markdown', CellKind.Markup, [], { custom: { metadata: {} } }],
['x = 3', 'javascript', CellKind.Code, [], { custom: { metadata: { collapsed: true } }, executionOrder: 1 }],
['x', 'javascript', CellKind.Code, [{ outputId: 'someId', outputs: [{ mime: 'text/plain', data: new Uint8Array([3]) }] }], { custom: { metadata: { collapsed: false } }, executionOrder: 1 }],
['x', 'javascript', CellKind.Code, [{ outputId: 'someId', outputs: [{ mime: Mimes.text, data: new Uint8Array([3]) }] }], { custom: { metadata: { collapsed: false } }, executionOrder: 1 }],
['x', 'javascript', CellKind.Code, [], { custom: { metadata: { collapsed: false } } }],
['x = 5', 'javascript', CellKind.Code, [], {}],
['x', 'javascript', CellKind.Code, [], {}],
['x', 'javascript', CellKind.Code, [{ outputId: 'someId', outputs: [{ mime: 'text/plain', data: new Uint8Array([5]) }] }], {}],
['x', 'javascript', CellKind.Code, [{ outputId: 'someId', outputs: [{ mime: Mimes.text, data: new Uint8Array([5]) }] }], {}],
], [
['# Description', 'markdown', CellKind.Markup, [], { custom: { metadata: {} } }],
['x = 3', 'javascript', CellKind.Code, [], { custom: { metadata: { collapsed: true } }, executionOrder: 1 }],
['x', 'javascript', CellKind.Code, [], { custom: { metadata: { collapsed: false } } }],
['x', 'javascript', CellKind.Code, [{ outputId: 'someId', outputs: [{ mime: 'text/plain', data: new Uint8Array([3]) }] }], { custom: { metadata: { collapsed: false } }, executionOrder: 1 }],
['x', 'javascript', CellKind.Code, [{ outputId: 'someId', outputs: [{ mime: Mimes.text, data: new Uint8Array([3]) }] }], { custom: { metadata: { collapsed: false } }, executionOrder: 1 }],
['x = 5', 'javascript', CellKind.Code, [], {}],
['x', 'javascript', CellKind.Code, [{ outputId: 'someId', outputs: [{ mime: 'text/plain', data: new Uint8Array([5]) }] }], {}],
['x', 'javascript', CellKind.Code, [{ outputId: 'someId', outputs: [{ mime: Mimes.text, data: new Uint8Array([5]) }] }], {}],
['x', 'javascript', CellKind.Code, [], {}],
], async (model) => {
const diff = new LcsDiff(new CellSequence(model.original.notebook), new CellSequence(model.modified.notebook));
@@ -20,6 +20,7 @@ import { INotebookService } from 'vs/workbench/contrib/notebook/common/notebookS
import { mock } from 'vs/base/test/common/mock';
import { TestInstantiationService } from 'vs/platform/instantiation/test/common/instantiationServiceMock';
import { DisposableStore } from 'vs/base/common/lifecycle';
import { Mimes } from 'vs/base/common/mime';
suite('NotebookEditorKernelManager', () => {
@@ -151,6 +152,6 @@ class TestNotebookKernel implements INotebookKernel {
}
constructor(opts?: { languages: string[] }) {
this.supportedLanguages = opts?.languages ?? ['text/plain'];
this.supportedLanguages = opts?.languages ?? [Mimes.text];
}
}
@@ -25,6 +25,7 @@ import { CellKind, NotebookData, TransientOptions } from 'vs/workbench/contrib/n
import { setupInstantiationService } from 'vs/workbench/contrib/notebook/test/testNotebookEditor';
import { VSBuffer } from 'vs/base/common/buffer';
import { CancellationToken } from 'vs/base/common/cancellation';
import { Mimes } from 'vs/base/common/mime';
suite('NotebookFileWorkingCopyModel', function () {
@@ -35,7 +36,7 @@ suite('NotebookFileWorkingCopyModel', function () {
const notebook = instantiationService.createInstance(NotebookTextModel,
'notebook',
URI.file('test'),
[{ cellKind: CellKind.Code, language: 'foo', source: 'foo', outputs: [{ outputId: 'id', outputs: [{ mime: 'text/plain', value: 'Hello Out' }] }] }],
[{ cellKind: CellKind.Code, language: 'foo', source: 'foo', outputs: [{ outputId: 'id', outputs: [{ mime: Mimes.text, value: 'Hello Out' }] }] }],
{},
{ transientCellMetadata: {}, transientDocumentMetadata: {}, transientOutputs: false }
);
@@ -16,6 +16,7 @@ import { mock } from 'vs/base/test/common/mock';
import { TestInstantiationService } from 'vs/platform/instantiation/test/common/instantiationServiceMock';
import { DisposableStore } from 'vs/base/common/lifecycle';
import { NotebookTextModel } from 'vs/workbench/contrib/notebook/common/model/notebookTextModel';
import { Mimes } from 'vs/base/common/mime';
suite('NotebookKernelService', () => {
@@ -176,7 +177,7 @@ class TestNotebookKernel implements INotebookKernel {
}
constructor(opts?: { languages?: string[], label?: string, viewType?: string }) {
this.supportedLanguages = opts?.languages ?? ['text/plain'];
this.supportedLanguages = opts?.languages ?? [Mimes.text];
this.label = opts?.label ?? this.label;
this.viewType = opts?.viewType ?? this.viewType;
}
@@ -4,10 +4,11 @@
*--------------------------------------------------------------------------------------------*/
import * as assert from 'assert';
import { CellKind, CellEditType, NotebookTextModelChangedEvent, SelectionStateType, ICellEditOperation } from 'vs/workbench/contrib/notebook/common/notebookCommon';
import { withTestNotebook, TestCell, setupInstantiationService } from 'vs/workbench/contrib/notebook/test/testNotebookEditor';
import { IUndoRedoService } from 'vs/platform/undoRedo/common/undoRedo';
import { Mimes } from 'vs/base/common/mime';
import { IModeService } from 'vs/editor/common/services/modeService';
import { IUndoRedoService } from 'vs/platform/undoRedo/common/undoRedo';
import { CellEditType, CellKind, ICellEditOperation, NotebookTextModelChangedEvent, SelectionStateType } from 'vs/workbench/contrib/notebook/common/notebookCommon';
import { setupInstantiationService, TestCell, withTestNotebook } from 'vs/workbench/contrib/notebook/test/testNotebookEditor';
suite('NotebookTextModel', () => {
@@ -189,7 +190,7 @@ suite('NotebookTextModel', () => {
editType: CellEditType.Output,
outputs: [{
outputId: 'someId',
outputs: [{ mime: 'text/markdown', data: valueBytesFromString('_Hello_') }]
outputs: [{ mime: Mimes.markdown, data: valueBytesFromString('_Hello_') }]
}]
}], true, undefined, () => undefined, undefined);
@@ -203,7 +204,7 @@ suite('NotebookTextModel', () => {
append: true,
outputs: [{
outputId: 'someId2',
outputs: [{ mime: 'text/markdown', data: valueBytesFromString('_Hello2_') }]
outputs: [{ mime: Mimes.markdown, data: valueBytesFromString('_Hello2_') }]
}]
}], true, undefined, () => undefined, undefined);
@@ -219,7 +220,7 @@ suite('NotebookTextModel', () => {
editType: CellEditType.Output,
outputs: [{
outputId: 'someId3',
outputs: [{ mime: 'text/plain', data: valueBytesFromString('Last, replaced output') }]
outputs: [{ mime: Mimes.text, data: valueBytesFromString('Last, replaced output') }]
}]
}], true, undefined, () => undefined, undefined);
@@ -247,7 +248,7 @@ suite('NotebookTextModel', () => {
append: true,
outputs: [{
outputId: 'append1',
outputs: [{ mime: 'text/markdown', data: valueBytesFromString('append 1') }]
outputs: [{ mime: Mimes.markdown, data: valueBytesFromString('append 1') }]
}]
},
{
@@ -256,7 +257,7 @@ suite('NotebookTextModel', () => {
append: true,
outputs: [{
outputId: 'append2',
outputs: [{ mime: 'text/markdown', data: valueBytesFromString('append 2') }]
outputs: [{ mime: Mimes.markdown, data: valueBytesFromString('append 2') }]
}]
}
], true, undefined, () => undefined, undefined);
@@ -584,7 +585,7 @@ suite('NotebookTextModel', () => {
{
editType: CellEditType.Output, handle: 0, append: true, outputs: [{
outputId: 'newOutput',
outputs: [{ mime: 'text/plain', data: valueBytesFromString('cba') }, { mime: 'application/foo', data: valueBytesFromString('cba') }]
outputs: [{ mime: Mimes.text, data: valueBytesFromString('cba') }, { mime: 'application/foo', data: valueBytesFromString('cba') }]
}]
}
];
@@ -614,7 +615,7 @@ suite('NotebookTextModel', () => {
{
editType: CellEditType.Output, index: 2, append: true, outputs: [{
outputId: 'newOutput',
outputs: [{ mime: 'text/plain', data: valueBytesFromString('cba') }, { mime: 'application/foo', data: valueBytesFromString('cba') }]
outputs: [{ mime: Mimes.text, data: valueBytesFromString('cba') }, { mime: 'application/foo', data: valueBytesFromString('cba') }]
}]
}
];
@@ -641,7 +642,7 @@ suite('NotebookTextModel', () => {
{
editType: CellEditType.Output, index: 1, append: true, outputs: [{
outputId: 'newOutput',
outputs: [{ mime: 'text/plain', data: valueBytesFromString('cba') }, { mime: 'application/foo', data: valueBytesFromString('cba') }]
outputs: [{ mime: Mimes.text, data: valueBytesFromString('cba') }, { mime: 'application/foo', data: valueBytesFromString('cba') }]
}]
},
{
@@ -650,7 +651,7 @@ suite('NotebookTextModel', () => {
{
editType: CellEditType.Output, index: 1, append: true, outputs: [{
outputId: 'newOutput2',
outputs: [{ mime: 'text/plain', data: valueBytesFromString('cba') }, { mime: 'application/foo', data: valueBytesFromString('cba') }]
outputs: [{ mime: Mimes.text, data: valueBytesFromString('cba') }, { mime: 'application/foo', data: valueBytesFromString('cba') }]
}]
}
];
@@ -314,7 +314,9 @@ class OnAutoForwardedAction extends Disposable {
}
private linkMessage() {
return nls.localize('remote.tunnelsView.notificationLink', "[See all forwarded ports](command:{0}.focus)", TunnelPanel.ID);
return nls.localize(
{ key: 'remote.tunnelsView.notificationLink2', comment: ['[See all forwarded ports]({0}) is a link. Only translate `See all forwarded ports`. Do not change brackets and parentheses or {0}'] },
"[See all forwarded ports]({0})", `command:${TunnelPanel.ID}.focus`);
}
private async showNotification(tunnel: RemoteTunnel) {
@@ -301,7 +301,11 @@ export class RemoteStatusIndicator extends Disposable implements IWorkbenchContr
const workspaceLabel = this.getWorkspaceLabel();
if (workspaceLabel) {
const toolTip: IMarkdownString = {
value: nls.localize('workspace.tooltip', "Virtual workspace on {0}\n\n[Some features](command:{1}) are not available for resources located on a virtual file system.", workspaceLabel, LIST_WORKSPACE_UNSUPPORTED_EXTENSIONS_COMMAND_ID),
value: nls.localize(
{ key: 'workspace.tooltip2', comment: ['{0} is a remote location name, e.g. GitHub', '[Some features]({1}) is a link. Only translate `Some features`. Do not change brackets and parentheses or {1}'] },
"Virtual workspace on {0}\n\n[Some features]({1}) are not available for resources located on a virtual file system.",
workspaceLabel, `command:${LIST_WORKSPACE_UNSUPPORTED_EXTENSIONS_COMMAND_ID}`
),
isTrusted: true
};
this.renderRemoteStatusIndicator(`$(remote) ${truncate(workspaceLabel, RemoteStatusIndicator.REMOTE_STATUS_LABEL_MAX_LENGTH)}`, toolTip);
@@ -327,7 +327,7 @@ suite('SearchModel', () => {
}
function stub(arg1: any, arg2: any, arg3: any): sinon.SinonStub {
const stub = sinon.stub(arg1, arg2, arg3);
const stub = sinon.stub(arg1, arg2).callsFake(arg3);
restoreStubs.push(stub);
return stub;
}
@@ -16,7 +16,8 @@
.monaco-workbench .pane-body.integrated-terminal .terminal-outer-container,
.monaco-workbench .pane-body.integrated-terminal .terminal-groups-container,
.monaco-workbench .pane-body.integrated-terminal .terminal-group {
.monaco-workbench .pane-body.integrated-terminal .terminal-group,
.monaco-workbench .pane-body.integrated-terminal .terminal-split-pane {
height: 100%;
}
@@ -314,14 +315,21 @@
position: absolute;
left: 0;
right: 0;
height: 100%;
top: 0;
bottom: 0;
pointer-events: none;
opacity: 0; /* hidden initially */
transition: left 70ms ease-out, right 70ms ease-out, opacity 150ms ease-out;
transition: left 70ms ease-out, right 70ms ease-out, top 70ms ease-out, bottom 70ms ease-out, opacity 150ms ease-out;
}
.monaco-workbench .pane-body.integrated-terminal .terminal-drop-overlay.drop-left {
.monaco-workbench .pane-body.integrated-terminal .terminal-group > .monaco-split-view2.horizontal .terminal-drop-overlay.drop-before {
right: 50%;
}
.monaco-workbench .pane-body.integrated-terminal .terminal-drop-overlay.drop-right {
.monaco-workbench .pane-body.integrated-terminal .terminal-group > .monaco-split-view2.horizontal .terminal-drop-overlay.drop-after {
left: 50%
}
.monaco-workbench .pane-body.integrated-terminal .terminal-group > .monaco-split-view2.vertical .terminal-drop-overlay.drop-before {
bottom: 50%;
}
.monaco-workbench .pane-body.integrated-terminal .terminal-group > .monaco-split-view2.vertical .terminal-drop-overlay.drop-after {
top: 50%;
}
@@ -162,7 +162,7 @@ export interface ITerminalService {
* Moves a terminal instance's group to the target instance group's position.
*/
moveGroup(source: ITerminalInstance, target: ITerminalInstance): void;
moveInstance(source: ITerminalInstance, target: ITerminalInstance, side: 'left' | 'right'): void;
moveInstance(source: ITerminalInstance, target: ITerminalInstance, side: 'before' | 'after'): void;
/**
* Perform an action with the active terminal instance, if the terminal does
@@ -631,7 +631,7 @@ export interface ITerminalInstance {
export interface IRequestAddInstanceToGroupEvent {
uri: URI;
side: 'left' | 'right'
side: 'before' | 'after'
}
export const enum LinuxDistro {
@@ -15,10 +15,10 @@ import { ICodeEditorService } from 'vs/editor/browser/services/codeEditorService
import { EndOfLinePreference } from 'vs/editor/common/model';
import { localize } from 'vs/nls';
import { CONTEXT_ACCESSIBILITY_MODE_ENABLED } from 'vs/platform/accessibility/common/accessibility';
import { Action2, ICommandActionTitle, ILocalizedString, MenuId, registerAction2 } from 'vs/platform/actions/common/actions';
import { Action2, ICommandActionTitle, ILocalizedString, registerAction2 } from 'vs/platform/actions/common/actions';
import { ICommandService } from 'vs/platform/commands/common/commands';
import { IConfigurationService } from 'vs/platform/configuration/common/configuration';
import { ContextKeyAndExpr, ContextKeyEqualsExpr, ContextKeyExpr } from 'vs/platform/contextkey/common/contextkey';
import { ContextKeyExpr } from 'vs/platform/contextkey/common/contextkey';
import { ServicesAccessor } from 'vs/platform/instantiation/common/instantiation';
import { KeybindingWeight } from 'vs/platform/keybinding/common/keybindingsRegistry';
import { ILabelService } from 'vs/platform/label/common/label';
@@ -32,8 +32,9 @@ import { PICK_WORKSPACE_FOLDER_COMMAND_ID } from 'vs/workbench/browser/actions/w
import { FindInFilesCommand, IFindInFilesArgs } from 'vs/workbench/contrib/search/browser/searchActions';
import { Direction, IRemoteTerminalService, ITerminalInstance, ITerminalInstanceService, ITerminalService } from 'vs/workbench/contrib/terminal/browser/terminal';
import { TerminalQuickAccessProvider } from 'vs/workbench/contrib/terminal/browser/terminalQuickAccess';
import { IRemoteTerminalAttachTarget, ITerminalConfigHelper, KEYBINDING_CONTEXT_TERMINAL_A11Y_TREE_FOCUS, KEYBINDING_CONTEXT_TERMINAL_ALT_BUFFER_ACTIVE, KEYBINDING_CONTEXT_TERMINAL_FIND_FOCUSED, KEYBINDING_CONTEXT_TERMINAL_FIND_NOT_VISIBLE, KEYBINDING_CONTEXT_TERMINAL_FIND_VISIBLE, KEYBINDING_CONTEXT_TERMINAL_FOCUS, KEYBINDING_CONTEXT_TERMINAL_IS_OPEN, KEYBINDING_CONTEXT_TERMINAL_PROCESS_SUPPORTED, KEYBINDING_CONTEXT_TERMINAL_TABS_FOCUS, KEYBINDING_CONTEXT_TERMINAL_TABS_SINGULAR_SELECTION, KEYBINDING_CONTEXT_TERMINAL_TEXT_SELECTED, TERMINAL_ACTION_CATEGORY, TerminalCommandId, TERMINAL_VIEW_ID } from 'vs/workbench/contrib/terminal/common/terminal';
import { IRemoteTerminalAttachTarget, ITerminalConfigHelper, KEYBINDING_CONTEXT_TERMINAL_A11Y_TREE_FOCUS, KEYBINDING_CONTEXT_TERMINAL_ALT_BUFFER_ACTIVE, KEYBINDING_CONTEXT_TERMINAL_FIND_FOCUSED, KEYBINDING_CONTEXT_TERMINAL_FIND_NOT_VISIBLE, KEYBINDING_CONTEXT_TERMINAL_FIND_VISIBLE, KEYBINDING_CONTEXT_TERMINAL_FOCUS, KEYBINDING_CONTEXT_TERMINAL_IS_OPEN, KEYBINDING_CONTEXT_TERMINAL_PROCESS_SUPPORTED, KEYBINDING_CONTEXT_TERMINAL_TABS_FOCUS, KEYBINDING_CONTEXT_TERMINAL_TABS_SINGULAR_SELECTION, KEYBINDING_CONTEXT_TERMINAL_TEXT_SELECTED, TERMINAL_ACTION_CATEGORY, TerminalCommandId } from 'vs/workbench/contrib/terminal/common/terminal';
import { ITerminalContributionService } from 'vs/workbench/contrib/terminal/common/terminalExtensionPoints';
import { terminalStrings } from 'vs/workbench/contrib/terminal/common/terminalStrings';
import { IConfigurationResolverService } from 'vs/workbench/services/configurationResolver/common/configurationResolver';
import { IHistoryService } from 'vs/workbench/services/history/common/history';
import { IPreferencesService } from 'vs/workbench/services/preferences/common/preferences';
@@ -342,38 +343,10 @@ export function registerTerminalActions() {
constructor() {
super({
id: TerminalCommandId.Focus,
title: { value: localize('workbench.action.terminal.focus', "Focus Terminal"), original: 'Focus Terminal' },
title: terminalStrings.focus,
f1: true,
category,
precondition: KEYBINDING_CONTEXT_TERMINAL_PROCESS_SUPPORTED,
// This command is used to show instead of tabs when there is only a single terminal
menu: {
id: MenuId.ViewTitle,
group: 'navigation',
order: 0,
when: ContextKeyAndExpr.create([
ContextKeyEqualsExpr.create('view', TERMINAL_VIEW_ID),
ContextKeyExpr.has(`config.${TerminalSettingId.TabsEnabled}`),
ContextKeyExpr.or(
ContextKeyExpr.and(
ContextKeyExpr.equals(`config.${TerminalSettingId.TabsShowActiveTerminal}`, 'singleTerminal'),
ContextKeyExpr.equals('terminalCount', 1)
),
ContextKeyExpr.and(
ContextKeyExpr.equals(`config.${TerminalSettingId.TabsShowActiveTerminal}`, 'singleTerminalOrNarrow'),
ContextKeyExpr.or(
ContextKeyExpr.equals('terminalCount', 1),
ContextKeyExpr.has('isTerminalTabsNarrow')
)
),
ContextKeyExpr.and(
ContextKeyExpr.equals(`config.${TerminalSettingId.TabsShowActiveTerminal}`, 'singleGroup'),
ContextKeyExpr.equals('terminalGroupCount', 1)
),
ContextKeyExpr.equals(`config.${TerminalSettingId.TabsShowActiveTerminal}`, 'always')
)
]),
}
precondition: KEYBINDING_CONTEXT_TERMINAL_PROCESS_SUPPORTED
});
}
async run(accessor: ServicesAccessor) {
@@ -1339,7 +1312,7 @@ export function registerTerminalActions() {
constructor() {
super({
id: TerminalCommandId.Split,
title: { value: localize('workbench.action.terminal.split', "Split Terminal"), original: 'Split Terminal' },
title: terminalStrings.split,
f1: true,
category,
precondition: KEYBINDING_CONTEXT_TERMINAL_PROCESS_SUPPORTED,
@@ -1361,15 +1334,6 @@ export function registerTerminalActions() {
type: 'object'
}
}]
},
menu: {
id: MenuId.ViewTitle,
group: 'navigation',
order: 2,
when: ContextKeyAndExpr.create([
ContextKeyEqualsExpr.create('view', TERMINAL_VIEW_ID),
ContextKeyExpr.not(`config.${TerminalSettingId.TabsEnabled}`)
])
}
});
}
@@ -1389,7 +1353,7 @@ export function registerTerminalActions() {
constructor() {
super({
id: TerminalCommandId.SplitInstance,
title: { value: localize('workbench.action.terminal.splitInstance', "Split Terminal"), original: 'Split Terminal' },
title: terminalStrings.split,
f1: false,
category,
precondition: KEYBINDING_CONTEXT_TERMINAL_PROCESS_SUPPORTED,
@@ -1423,7 +1387,7 @@ export function registerTerminalActions() {
constructor() {
super({
id: TerminalCommandId.Unsplit,
title: { value: localize('workbench.action.terminal.unsplit', "Unsplit Terminal"), original: 'Unsplit Terminal' },
title: terminalStrings.unsplit,
f1: true,
category,
precondition: KEYBINDING_CONTEXT_TERMINAL_PROCESS_SUPPORTED
@@ -1438,7 +1402,7 @@ export function registerTerminalActions() {
constructor() {
super({
id: TerminalCommandId.UnsplitInstance,
title: { value: localize('workbench.action.terminal.unsplit', "Unsplit Terminal"), original: 'Unsplit Terminal' },
title: terminalStrings.unsplit,
f1: true,
category,
precondition: KEYBINDING_CONTEXT_TERMINAL_PROCESS_SUPPORTED
@@ -1578,16 +1542,7 @@ export function registerTerminalActions() {
f1: true,
category,
precondition: ContextKeyExpr.or(KEYBINDING_CONTEXT_TERMINAL_PROCESS_SUPPORTED, KEYBINDING_CONTEXT_TERMINAL_IS_OPEN),
icon: Codicon.trash,
menu: {
id: MenuId.ViewTitle,
group: 'navigation',
order: 3,
when: ContextKeyAndExpr.create([
ContextKeyEqualsExpr.create('view', TERMINAL_VIEW_ID),
ContextKeyExpr.not(`config.${TerminalSettingId.TabsEnabled}`)
])
}
icon: Codicon.trash
});
}
async run(accessor: ServicesAccessor) {
@@ -1605,9 +1560,7 @@ export function registerTerminalActions() {
constructor() {
super({
id: TerminalCommandId.KillInstance,
title: {
value: localize('workbench.action.terminal.kill.short', "Kill Terminal"), original: 'Kill Terminal'
},
title: terminalStrings.kill,
f1: false,
category,
precondition: ContextKeyExpr.or(KEYBINDING_CONTEXT_TERMINAL_PROCESS_SUPPORTED, KEYBINDING_CONTEXT_TERMINAL_IS_OPEN),
@@ -1656,10 +1609,7 @@ export function registerTerminalActions() {
});
}
run(accessor: ServicesAccessor) {
accessor.get(ITerminalService).doWithActiveInstance(t => {
t.clear();
t.focus();
});
accessor.get(ITerminalService).doWithActiveInstance(t => t.clear());
}
});
registerAction2(class extends Action2 {
@@ -1684,15 +1634,7 @@ export function registerTerminalActions() {
title: TerminalCommandId.CreateWithProfileButton,
f1: false,
category,
precondition: KEYBINDING_CONTEXT_TERMINAL_PROCESS_SUPPORTED,
menu: [{
id: MenuId.ViewTitle,
group: 'navigation',
order: 0,
when: ContextKeyAndExpr.create([
ContextKeyEqualsExpr.create('view', TERMINAL_VIEW_ID)
]),
}]
precondition: KEYBINDING_CONTEXT_TERMINAL_PROCESS_SUPPORTED
});
}
async run(accessor: ServicesAccessor) {
@@ -58,8 +58,10 @@ import { isMacintosh, isWindows, OperatingSystem, OS } from 'vs/base/common/plat
import { URI } from 'vs/base/common/uri';
import { Schemas } from 'vs/base/common/network';
import { DataTransfers } from 'vs/base/browser/dnd';
import { DragAndDropObserver, IDragAndDropObserverCallbacks } from 'vs/workbench/browser/dnd';
import { containsDragType, DragAndDropObserver, IDragAndDropObserverCallbacks } from 'vs/workbench/browser/dnd';
import { getColorClass } from 'vs/workbench/contrib/terminal/browser/terminalIcon';
import { IWorkbenchLayoutService, Position } from 'vs/workbench/services/layout/browser/layoutService';
import { Orientation } from 'vs/base/browser/ui/sash/sash';
// How long in milliseconds should an average frame take to render for a notification to appear
// which suggests the fallback DOM-based renderer
@@ -832,14 +834,14 @@ export class TerminalInstance extends Disposable implements ITerminalInstance {
private _initDragAndDrop(container: HTMLElement) {
this._dndObserver?.dispose();
const dndController = new TerminalInstanceDragAndDropController(container);
const dndController = this._instantiationService.createInstance(TerminalInstanceDragAndDropController, container);
dndController.onDropTerminal(e => this._onRequestAddInstanceToGroup.fire(e));
dndController.onDropFile(async path => {
const preparedPath = await this._terminalInstanceService.preparePathForTerminalAsync(path, this.shellLaunchConfig.executable, this.title, this.shellType, this.isRemote);
this.sendText(preparedPath, false);
this.focus();
});
this._dndObserver = new DragAndDropObserver(container.parentElement!, dndController);
this._dndObserver = new DragAndDropObserver(container, dndController);
}
private async _measureRenderTime(): Promise<void> {
@@ -1936,7 +1938,9 @@ class TerminalInstanceDragAndDropController extends Disposable implements IDragA
get onDropTerminal(): Event<IRequestAddInstanceToGroupEvent> { return this._onDropTerminal.event; }
constructor(
private readonly _container: HTMLElement
private readonly _container: HTMLElement,
@IWorkbenchLayoutService private readonly _layoutService: IWorkbenchLayoutService,
@IViewDescriptorService private readonly _viewDescriptorService: IViewDescriptorService,
) {
super();
this._register(toDisposable(() => this._clearDropOverlay()));
@@ -1950,6 +1954,10 @@ class TerminalInstanceDragAndDropController extends Disposable implements IDragA
}
onDragEnter(e: DragEvent) {
if (!containsDragType(e, DataTransfers.FILES, DataTransfers.RESOURCES, 'terminals')) {
return;
}
if (!this._dropOverlay) {
this._dropOverlay = document.createElement('div');
this._dropOverlay.classList.add('terminal-drop-overlay');
@@ -1960,8 +1968,8 @@ class TerminalInstanceDragAndDropController extends Disposable implements IDragA
// Dragging terminals
if (types.includes('terminals')) {
const side = this._getDropSide(e);
this._dropOverlay.classList.toggle('drop-left', side === 'left');
this._dropOverlay.classList.toggle('drop-right', side === 'right');
this._dropOverlay.classList.toggle('drop-before', side === 'before');
this._dropOverlay.classList.toggle('drop-after', side === 'after');
}
if (!this._dropOverlay.parentElement) {
@@ -1986,8 +1994,8 @@ class TerminalInstanceDragAndDropController extends Disposable implements IDragA
// Dragging terminals
if (types.includes('terminals')) {
const side = this._getDropSide(e);
this._dropOverlay.classList.toggle('drop-left', side === 'left');
this._dropOverlay.classList.toggle('drop-right', side === 'right');
this._dropOverlay.classList.toggle('drop-before', side === 'before');
this._dropOverlay.classList.toggle('drop-after', side === 'after');
}
this._dropOverlay.style.opacity = '1';
@@ -2026,13 +2034,24 @@ class TerminalInstanceDragAndDropController extends Disposable implements IDragA
this._onDropFile.fire(path);
}
private _getDropSide(e: DragEvent): 'left' | 'right' {
private _getDropSide(e: DragEvent): 'before' | 'after' {
const target = this._container;
if (!target) {
return 'right';
return 'after';
}
const rect = target.getBoundingClientRect();
return e.clientX - rect.left < rect.width / 2 ? 'left' : 'right';
return this._getViewOrientation() === Orientation.HORIZONTAL
? (e.clientX - rect.left < rect.width / 2 ? 'before' : 'after')
: (e.clientY - rect.top < rect.height / 2 ? 'before' : 'after');
}
private _getViewOrientation(): Orientation {
const panelPosition = this._layoutService.getPanelPosition();
const terminalLocation = this._viewDescriptorService.getViewLocationById(TERMINAL_VIEW_ID);
return terminalLocation === ViewContainerLocation.Panel && panelPosition === Position.BOTTOM
? Orientation.HORIZONTAL
: Orientation.VERTICAL;
}
}
@@ -3,11 +3,13 @@
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import { Codicon } from 'vs/base/common/codicons';
import { localize } from 'vs/nls';
import { MenuRegistry, MenuId } from 'vs/platform/actions/common/actions';
import { ContextKeyAndExpr, ContextKeyEqualsExpr, ContextKeyExpr } from 'vs/platform/contextkey/common/contextkey';
import { TerminalSettingId } from 'vs/platform/terminal/common/terminal';
import { IS_SPLIT_TERMINAL_CONTEXT_KEY, KEYBINDING_CONTEXT_TERMINAL_PROCESS_SUPPORTED, KEYBINDING_CONTEXT_TERMINAL_TABS_SINGULAR_SELECTION, TerminalCommandId, TERMINAL_VIEW_ID } from 'vs/workbench/contrib/terminal/common/terminal';
import { terminalStrings } from 'vs/workbench/contrib/terminal/common/terminalStrings';
const enum ContextMenuGroup {
Create = '1_create',
@@ -34,7 +36,8 @@ export function setupTerminalMenus(): void {
MenuRegistry.appendMenuItems(
[
{
id: MenuId.MenubarTerminalMenu, item: {
id: MenuId.MenubarTerminalMenu,
item: {
group: TerminalMenuBarGroup.Create,
command: {
id: TerminalCommandId.New,
@@ -44,7 +47,8 @@ export function setupTerminalMenus(): void {
}
},
{
id: MenuId.MenubarTerminalMenu, item: {
id: MenuId.MenubarTerminalMenu,
item: {
group: TerminalMenuBarGroup.Create,
command: {
id: TerminalCommandId.Split,
@@ -56,7 +60,8 @@ export function setupTerminalMenus(): void {
}
},
{
id: MenuId.MenubarTerminalMenu, item: {
id: MenuId.MenubarTerminalMenu,
item: {
group: TerminalMenuBarGroup.Run,
command: {
id: TerminalCommandId.RunActiveFile,
@@ -67,7 +72,8 @@ export function setupTerminalMenus(): void {
}
},
{
id: MenuId.MenubarTerminalMenu, item: {
id: MenuId.MenubarTerminalMenu,
item: {
group: TerminalMenuBarGroup.Run,
command: {
id: TerminalCommandId.RunSelectedText,
@@ -83,16 +89,18 @@ export function setupTerminalMenus(): void {
MenuRegistry.appendMenuItems(
[
{
id: MenuId.TerminalInstanceContext, item: {
id: MenuId.TerminalInstanceContext,
item: {
group: ContextMenuGroup.Create,
command: {
id: TerminalCommandId.Split,
title: localize('workbench.action.terminal.split', "Split Terminal")
title: terminalStrings.split.value
}
}
},
{
id: MenuId.TerminalInstanceContext, item: {
id: MenuId.TerminalInstanceContext,
item: {
command: {
id: TerminalCommandId.New,
title: localize('workbench.action.terminal.new.short', "New Terminal")
@@ -101,16 +109,18 @@ export function setupTerminalMenus(): void {
}
},
{
id: MenuId.TerminalInstanceContext, item: {
id: MenuId.TerminalInstanceContext,
item: {
command: {
id: TerminalCommandId.Kill,
title: localize('workbench.action.terminal.kill.short', "Kill Terminal")
title: terminalStrings.kill.value
},
group: ContextMenuGroup.Kill
}
},
{
id: MenuId.TerminalInstanceContext, item: {
id: MenuId.TerminalInstanceContext,
item: {
command: {
id: TerminalCommandId.CopySelection,
title: localize('workbench.action.terminal.copySelection.short', "Copy")
@@ -120,7 +130,8 @@ export function setupTerminalMenus(): void {
}
},
{
id: MenuId.TerminalInstanceContext, item: {
id: MenuId.TerminalInstanceContext,
item: {
command: {
id: TerminalCommandId.Paste,
title: localize('workbench.action.terminal.paste.short', "Paste")
@@ -130,7 +141,8 @@ export function setupTerminalMenus(): void {
}
},
{
id: MenuId.TerminalInstanceContext, item: {
id: MenuId.TerminalInstanceContext,
item: {
command: {
id: TerminalCommandId.Clear,
title: localize('workbench.action.terminal.clear', "Clear")
@@ -139,7 +151,8 @@ export function setupTerminalMenus(): void {
}
},
{
id: MenuId.TerminalInstanceContext, item: {
id: MenuId.TerminalInstanceContext,
item: {
command: {
id: TerminalCommandId.ShowTabs,
title: localize('workbench.action.terminal.showsTabs', "Show Tabs")
@@ -149,7 +162,8 @@ export function setupTerminalMenus(): void {
}
},
{
id: MenuId.TerminalInstanceContext, item: {
id: MenuId.TerminalInstanceContext,
item: {
command: {
id: TerminalCommandId.SelectAll,
title: localize('workbench.action.terminal.selectAll', "Select All"),
@@ -164,7 +178,8 @@ export function setupTerminalMenus(): void {
MenuRegistry.appendMenuItems(
[
{
id: MenuId.TerminalTabEmptyAreaContext, item: {
id: MenuId.TerminalTabEmptyAreaContext,
item: {
command: {
id: TerminalCommandId.NewWithProfile,
title: localize('workbench.action.terminal.newWithProfile.short', "New Terminal With Profile")
@@ -173,7 +188,8 @@ export function setupTerminalMenus(): void {
}
},
{
id: MenuId.TerminalTabEmptyAreaContext, item: {
id: MenuId.TerminalTabEmptyAreaContext,
item: {
command: {
id: TerminalCommandId.New,
title: localize('workbench.action.terminal.new.short', "New Terminal")
@@ -187,7 +203,8 @@ export function setupTerminalMenus(): void {
MenuRegistry.appendMenuItems(
[
{
id: MenuId.TerminalNewDropdownContext, item: {
id: MenuId.TerminalNewDropdownContext,
item: {
command: {
id: TerminalCommandId.SelectDefaultProfile,
title: { value: localize('workbench.action.terminal.selectDefaultProfile', "Select Default Profile"), original: 'Select Default Profile' }
@@ -196,7 +213,8 @@ export function setupTerminalMenus(): void {
}
},
{
id: MenuId.TerminalNewDropdownContext, item: {
id: MenuId.TerminalNewDropdownContext,
item: {
command: {
id: TerminalCommandId.ConfigureTerminalSettings,
title: localize('workbench.action.terminal.openSettings', "Configure Terminal Settings")
@@ -210,7 +228,8 @@ export function setupTerminalMenus(): void {
MenuRegistry.appendMenuItems(
[
{
id: MenuId.ViewTitle, item: {
id: MenuId.ViewTitle,
item: {
command: {
id: TerminalCommandId.SwitchTerminal,
title: { value: localize('workbench.action.terminal.switchTerminal', "Switch Terminal"), original: 'Switch Terminal' }
@@ -222,6 +241,86 @@ export function setupTerminalMenus(): void {
ContextKeyExpr.not(`config.${TerminalSettingId.TabsEnabled}`)
]),
}
},
{
// This is used to show instead of tabs when there is only a single terminal
id: MenuId.ViewTitle,
item: {
command: {
id: TerminalCommandId.Focus,
title: terminalStrings.focus
},
group: 'navigation',
order: 0,
when: ContextKeyAndExpr.create([
ContextKeyEqualsExpr.create('view', TERMINAL_VIEW_ID),
ContextKeyExpr.has(`config.${TerminalSettingId.TabsEnabled}`),
ContextKeyExpr.or(
ContextKeyExpr.and(
ContextKeyExpr.equals(`config.${TerminalSettingId.TabsShowActiveTerminal}`, 'singleTerminal'),
ContextKeyExpr.equals('terminalCount', 1)
),
ContextKeyExpr.and(
ContextKeyExpr.equals(`config.${TerminalSettingId.TabsShowActiveTerminal}`, 'singleTerminalOrNarrow'),
ContextKeyExpr.or(
ContextKeyExpr.equals('terminalCount', 1),
ContextKeyExpr.has('isTerminalTabsNarrow')
)
),
ContextKeyExpr.and(
ContextKeyExpr.equals(`config.${TerminalSettingId.TabsShowActiveTerminal}`, 'singleGroup'),
ContextKeyExpr.equals('terminalGroupCount', 1)
),
ContextKeyExpr.equals(`config.${TerminalSettingId.TabsShowActiveTerminal}`, 'always')
)
]),
}
},
{
id: MenuId.ViewTitle,
item: {
command: {
id: TerminalCommandId.Split,
title: terminalStrings.split,
icon: Codicon.splitHorizontal
},
group: 'navigation',
order: 2,
when: ContextKeyAndExpr.create([
ContextKeyEqualsExpr.create('view', TERMINAL_VIEW_ID),
ContextKeyExpr.not(`config.${TerminalSettingId.TabsEnabled}`)
])
}
},
{
id: MenuId.ViewTitle,
item: {
command: {
id: TerminalCommandId.Kill,
title: terminalStrings.kill,
icon: Codicon.trash
},
group: 'navigation',
order: 3,
when: ContextKeyAndExpr.create([
ContextKeyEqualsExpr.create('view', TERMINAL_VIEW_ID),
ContextKeyExpr.not(`config.${TerminalSettingId.TabsEnabled}`)
])
}
},
{
id: MenuId.ViewTitle,
item: {
command: {
id: TerminalCommandId.CreateWithProfileButton,
title: TerminalCommandId.CreateWithProfileButton
},
group: 'navigation',
order: 0,
when: ContextKeyAndExpr.create([
ContextKeyEqualsExpr.create('view', TERMINAL_VIEW_ID)
])
}
}
]
);
@@ -229,16 +328,18 @@ export function setupTerminalMenus(): void {
MenuRegistry.appendMenuItems(
[
{
id: MenuId.TerminalInlineTabContext, item: {
id: MenuId.TerminalInlineTabContext,
item: {
group: ContextMenuGroup.Create,
command: {
id: TerminalCommandId.Split,
title: localize('workbench.action.terminal.split', "Split Terminal")
title: terminalStrings.split.value
}
}
},
{
id: MenuId.TerminalInlineTabContext, item: {
id: MenuId.TerminalInlineTabContext,
item: {
command: {
id: TerminalCommandId.ChangeIcon,
title: localize('workbench.action.terminal.changeIcon', "Change Icon...")
@@ -248,7 +349,8 @@ export function setupTerminalMenus(): void {
}
},
{
id: MenuId.TerminalInlineTabContext, item: {
id: MenuId.TerminalInlineTabContext,
item: {
command: {
id: TerminalCommandId.ChangeColor,
title: localize('workbench.action.terminal.changeColor', "Change Color...")
@@ -258,7 +360,8 @@ export function setupTerminalMenus(): void {
}
},
{
id: MenuId.TerminalInlineTabContext, item: {
id: MenuId.TerminalInlineTabContext,
item: {
command: {
id: TerminalCommandId.Rename,
title: localize('workbench.action.terminal.rename', "Rename...")
@@ -267,10 +370,11 @@ export function setupTerminalMenus(): void {
}
},
{
id: MenuId.TerminalInlineTabContext, item: {
id: MenuId.TerminalInlineTabContext,
item: {
command: {
id: TerminalCommandId.Kill,
title: localize('workbench.action.terminal.kill.short', "Kill Terminal")
title: terminalStrings.kill.value
},
group: ContextMenuGroup.Kill
}
@@ -281,16 +385,18 @@ export function setupTerminalMenus(): void {
MenuRegistry.appendMenuItems(
[
{
id: MenuId.TerminalTabContext, item: {
id: MenuId.TerminalTabContext,
item: {
command: {
id: TerminalCommandId.SplitInstance,
title: localize('workbench.action.terminal.splitInstance', "Split Terminal"),
title: terminalStrings.split.value,
},
group: ContextMenuGroup.Create
}
},
{
id: MenuId.TerminalTabContext, item: {
id: MenuId.TerminalTabContext,
item: {
command: {
id: TerminalCommandId.RenameInstance,
title: localize('workbench.action.terminal.renameInstance', "Rename...")
@@ -299,7 +405,8 @@ export function setupTerminalMenus(): void {
}
},
{
id: MenuId.TerminalTabContext, item: {
id: MenuId.TerminalTabContext,
item: {
command: {
id: TerminalCommandId.ChangeIconInstance,
title: localize('workbench.action.terminal.changeIcon', "Change Icon...")
@@ -308,7 +415,8 @@ export function setupTerminalMenus(): void {
}
},
{
id: MenuId.TerminalTabContext, item: {
id: MenuId.TerminalTabContext,
item: {
command: {
id: TerminalCommandId.ChangeColorInstance,
title: localize('workbench.action.terminal.changeColor', "Change Color...")
@@ -317,7 +425,8 @@ export function setupTerminalMenus(): void {
}
},
{
id: MenuId.TerminalTabContext, item: {
id: MenuId.TerminalTabContext,
item: {
group: ContextMenuGroup.Config,
command: {
id: TerminalCommandId.JoinInstance,
@@ -327,20 +436,22 @@ export function setupTerminalMenus(): void {
}
},
{
id: MenuId.TerminalTabContext, item: {
id: MenuId.TerminalTabContext,
item: {
group: ContextMenuGroup.Config,
command: {
id: TerminalCommandId.UnsplitInstance,
title: localize('workbench.action.terminal.unsplitInstance', "Unsplit Terminal")
title: terminalStrings.unsplit.value
},
when: ContextKeyExpr.and(KEYBINDING_CONTEXT_TERMINAL_TABS_SINGULAR_SELECTION, IS_SPLIT_TERMINAL_CONTEXT_KEY)
}
},
{
id: MenuId.TerminalTabContext, item: {
id: MenuId.TerminalTabContext,
item: {
command: {
id: TerminalCommandId.KillInstance,
title: localize('workbench.action.terminal.killInstance', "Kill Terminal")
title: terminalStrings.kill.value
},
group: ContextMenuGroup.Kill,
}
@@ -13,6 +13,7 @@ import { TerminalCommandId } from 'vs/workbench/contrib/terminal/common/terminal
import { IThemeService, ThemeIcon } from 'vs/platform/theme/common/themeService';
import { killTerminalIcon, renameTerminalIcon } from 'vs/workbench/contrib/terminal/browser/terminalIcons';
import { getColorClass, getIconId, getUriClasses } from 'vs/workbench/contrib/terminal/browser/terminalIcon';
import { terminalStrings } from 'vs/workbench/contrib/terminal/common/terminalStrings';
export class TerminalQuickAccessProvider extends PickerQuickAccessProvider<IPickerQuickAccessItem> {
@@ -57,7 +58,7 @@ export class TerminalQuickAccessProvider extends PickerQuickAccessProvider<IPick
},
{
iconClass: ThemeIcon.asClassName(killTerminalIcon),
tooltip: localize('killTerminal', "Kill Terminal Instance")
tooltip: terminalStrings.kill.value
}
],
iconClasses,
@@ -63,7 +63,7 @@ export class TerminalService implements ITerminalService {
private _linkProviderDisposables: Map<ITerminalExternalLinkProvider, IDisposable[]> = new Map();
private _processSupportContextKey: IContextKey<boolean>;
private readonly _localTerminalService?: ILocalTerminalService;
private readonly _offProcessTerminalService?: IOffProcessTerminalService;
private readonly _primaryOffProcessTerminalService?: IOffProcessTerminalService;
private _profilesReadyBarrier: AutoOpenBarrier;
private _availableProfiles: ITerminalProfile[] | undefined;
private _configHelper: TerminalConfigHelper;
@@ -210,7 +210,7 @@ export class TerminalService implements ITerminalService {
: enableTerminalReconnection
? this._localTerminalsInitPromise = this._reconnectToLocalTerminals()
: Promise.resolve();
this._offProcessTerminalService = !!this._environmentService.remoteAuthority ? this._remoteTerminalService : this._localTerminalService;
this._primaryOffProcessTerminalService = !!this._environmentService.remoteAuthority ? this._remoteTerminalService : this._localTerminalService;
initPromise.then(() => this._setConnected());
// Wait up to 5 seconds for profiles to be ready so it's assured that we know the actual
@@ -376,12 +376,11 @@ export class TerminalService implements ITerminalService {
}
private async _detectProfiles(includeDetectedProfiles?: boolean): Promise<ITerminalProfile[]> {
const offProcService = this._offProcessTerminalService;
if (!offProcService) {
if (!this._primaryOffProcessTerminalService) {
return this._availableProfiles || [];
}
const platform = await this._getPlatformKey();
return offProcService?.getProfiles(this._configurationService.getValue(`${TerminalSettingPrefix.Profiles}${platform}`), this._configurationService.getValue(`${TerminalSettingPrefix.DefaultProfile}${platform}`), includeDetectedProfiles);
return this._primaryOffProcessTerminalService?.getProfiles(this._configurationService.getValue(`${TerminalSettingPrefix.Profiles}${platform}`), this._configurationService.getValue(`${TerminalSettingPrefix.DefaultProfile}${platform}`), includeDetectedProfiles);
}
private _onBeforeShutdown(reason: ShutdownReason): boolean | Promise<boolean> {
@@ -441,7 +440,7 @@ export class TerminalService implements ITerminalService {
const state: ITerminalsLayoutInfoById = {
tabs: this.terminalGroups.map(g => g.getLayoutInfo(g === this.getActiveGroup()))
};
this._offProcessTerminalService?.setTerminalLayoutInfo(state);
this._primaryOffProcessTerminalService?.setTerminalLayoutInfo(state);
}
@debounce(500)
@@ -449,7 +448,7 @@ export class TerminalService implements ITerminalService {
if (!this.configHelper.config.enablePersistentSessions || !instance || !instance.persistentProcessId || !instance.title) {
return;
}
this._offProcessTerminalService?.updateTitle(instance.persistentProcessId, instance.title, instance.titleSource);
this._primaryOffProcessTerminalService?.updateTitle(instance.persistentProcessId, instance.title, instance.titleSource);
}
@debounce(500)
@@ -457,7 +456,7 @@ export class TerminalService implements ITerminalService {
if (!this.configHelper.config.enablePersistentSessions || !instance || !instance.persistentProcessId || !instance.icon) {
return;
}
this._offProcessTerminalService?.updateIcon(instance.persistentProcessId, instance.icon, instance.color);
this._primaryOffProcessTerminalService?.updateIcon(instance.persistentProcessId, instance.icon, instance.color);
}
private _removeGroup(group: ITerminalGroup): void {
@@ -743,7 +742,7 @@ export class TerminalService implements ITerminalService {
this._onInstancesChanged.fire();
}
moveInstance(source: ITerminalInstance, target: ITerminalInstance, side: 'left' | 'right'): void {
moveInstance(source: ITerminalInstance, target: ITerminalInstance, side: 'before' | 'after'): void {
const sourceGroup = this.getGroupForInstance(source);
const targetGroup = this.getGroupForInstance(target);
if (!sourceGroup || !targetGroup) {
@@ -758,7 +757,7 @@ export class TerminalService implements ITerminalService {
}
// Rearrange within the target group
const index = targetGroup.terminalInstances.indexOf(target) + (side === 'right' ? 1 : 0);
const index = targetGroup.terminalInstances.indexOf(target) + (side === 'after' ? 1 : 0);
targetGroup.moveInstance(source, index);
}
@@ -30,7 +30,7 @@ import { Disposable, DisposableStore, dispose, IDisposable, toDisposable } from
import { IListDragAndDrop, IListDragOverReaction, IListRenderer, ListDragOverEffect } from 'vs/base/browser/ui/list/list';
import { DataTransfers, IDragAndDropData } from 'vs/base/browser/dnd';
import { disposableTimeout } from 'vs/base/common/async';
import { ElementsDragAndDropData } from 'vs/base/browser/ui/list/listView';
import { ElementsDragAndDropData, NativeDragAndDropData } from 'vs/base/browser/ui/list/listView';
import { URI } from 'vs/base/common/uri';
import { getColorClass, getIconId, getUriClasses } from 'vs/workbench/contrib/terminal/browser/terminalIcon';
import { Schemas } from 'vs/base/common/network';
@@ -41,6 +41,8 @@ import { once } from 'vs/base/common/functional';
import { attachInputBoxStyler } from 'vs/platform/theme/common/styler';
import { IKeyboardEvent } from 'vs/base/browser/keyboardEvent';
import { KeyCode } from 'vs/base/common/keyCodes';
import { containsDragType } from 'vs/workbench/browser/dnd';
import { terminalStrings } from 'vs/workbench/contrib/terminal/common/terminalStrings';
const $ = DOM.$;
@@ -436,10 +438,10 @@ class TerminalTabsRenderer implements IListRenderer<ITerminalInstance, ITerminal
fillActionBar(instance: ITerminalInstance, template: ITerminalTabEntryTemplate): void {
// If the instance is within the selection, split all selected
const actions = [
new Action(TerminalCommandId.SplitInstance, localize('terminal.split', "Split"), ThemeIcon.asClassName(Codicon.splitHorizontal), true, async () => {
new Action(TerminalCommandId.SplitInstance, terminalStrings.split.short, ThemeIcon.asClassName(Codicon.splitHorizontal), true, async () => {
this._runForSelectionOrInstance(instance, e => this._terminalService.splitInstance(e));
}),
new Action(TerminalCommandId.KillInstance, localize('terminal.kill', "Kill"), ThemeIcon.asClassName(Codicon.trashcan), true, async () => {
new Action(TerminalCommandId.KillInstance, terminalStrings.kill.short, ThemeIcon.asClassName(Codicon.trashcan), true, async () => {
this._runForSelectionOrInstance(instance, e => e.dispose());
})
];
@@ -547,7 +549,11 @@ class TerminalTabsDragAndDrop implements IListDragAndDrop<ITerminalInstance> {
}
onDragOver(data: IDragAndDropData, targetInstance: ITerminalInstance | undefined, targetIndex: number | undefined, originalEvent: DragEvent): boolean | IListDragOverReaction {
let result = true;
if (data instanceof NativeDragAndDropData) {
if (!containsDragType(originalEvent, DataTransfers.FILES, DataTransfers.RESOURCES)) {
return false;
}
}
const didChangeAutoFocusInstance = this._autoFocusInstance !== targetInstance;
if (didChangeAutoFocusInstance) {
@@ -556,7 +562,7 @@ class TerminalTabsDragAndDrop implements IListDragAndDrop<ITerminalInstance> {
}
if (!targetInstance) {
return result;
return data instanceof ElementsDragAndDropData;
}
if (didChangeAutoFocusInstance) {
@@ -42,6 +42,7 @@ import { dispose, IDisposable, toDisposable } from 'vs/base/common/lifecycle';
import { URI } from 'vs/base/common/uri';
import { ColorScheme } from 'vs/platform/theme/common/theme';
import { getColorClass, getUriClasses } from 'vs/workbench/contrib/terminal/browser/terminalIcon';
import { terminalStrings } from 'vs/workbench/contrib/terminal/common/terminalStrings';
export class TerminalViewPane extends ViewPane {
private _actions: IAction[] | undefined;
@@ -257,7 +258,7 @@ export class TerminalViewPane extends ViewPane {
},
{
id: TerminalCommandId.Split,
title: nls.localize('terminal.split', "Split Terminal"),
title: terminalStrings.split.value,
icon: Codicon.splitHorizontal
},
undefined);
@@ -385,7 +386,7 @@ class SingleTerminalTabActionViewItem extends MenuEntryActionViewItem {
},
{
id: TerminalCommandId.Split,
title: nls.localize('workbench.action.terminal.split', "Split Terminal"),
title: terminalStrings.split.value,
icon: Codicon.splitHorizontal
},
undefined,

Some files were not shown because too many files have changed in this diff Show More