mirror of
https://github.com/Microsoft/vscode
synced 2024-09-13 21:55:38 +00:00
Merge branch 'main' into dev/t-andreamah/markdown-static-preview-scroll-state
This commit is contained in:
commit
44d135e94f
10
.github/classifier.json
vendored
10
.github/classifier.json
vendored
|
@ -20,8 +20,7 @@
|
|||
"context-keys": {"assign": []},
|
||||
"css-less-scss": {"assign": ["aeschli"]},
|
||||
"custom-editors": {"assign": ["mjbvz"]},
|
||||
"debug": {"assign": ["isidorn"]},
|
||||
"debug-console": {"assign": ["isidorn"]},
|
||||
"debug": {"assign": ["weinand"]},
|
||||
"dialogs": {"assign": ["sbatten"]},
|
||||
"diff-editor": {"assign": []},
|
||||
"dropdown": {"assign": []},
|
||||
|
@ -81,9 +80,10 @@
|
|||
"icon-brand": {"assign": []},
|
||||
"icons-product": {"assign": ["misolori"]},
|
||||
"install-update": {"assign": []},
|
||||
"integrated-terminal": {"assign": ["meganrogge"]},
|
||||
"integrated-terminal-conpty": {"assign": ["meganrogge"]},
|
||||
"integrated-terminal-links": {"assign": ["meganrogge"]},
|
||||
"terminal": {"assign": ["meganrogge"]},
|
||||
"terminal-conpty": {"assign": ["meganrogge"]},
|
||||
"terminal-links": {"assign": ["meganrogge"]},
|
||||
"terminal-external": {"assign": ["meganrogge"]},
|
||||
"integration-test": {"assign": []},
|
||||
"intellisense-config": {"assign": []},
|
||||
"ipc": {"assign": ["joaomoreno"]},
|
||||
|
|
2
.yarnrc
2
.yarnrc
|
@ -1,3 +1,3 @@
|
|||
disturl "https://electronjs.org/headers"
|
||||
target "12.0.4"
|
||||
target "12.0.7"
|
||||
runtime "electron"
|
||||
|
|
|
@ -10,7 +10,7 @@ This repository ("`Code - OSS`") is where we (Microsoft) develop the [Visual Stu
|
|||
## Visual Studio Code
|
||||
|
||||
<p align="center">
|
||||
<img alt="VS Code in action" src="https://user-images.githubusercontent.com/1487073/58344409-70473b80-7e0a-11e9-8570-b2efc6f8fa44.png">
|
||||
<img alt="VS Code in action" src="https://user-images.githubusercontent.com/35271042/118224532-3842c400-b438-11eb-923d-a5f66fa6785a.png">
|
||||
</p>
|
||||
|
||||
[Visual Studio Code](https://code.visualstudio.com) is a distribution of the `Code - OSS` repository with Microsoft specific customizations released under a traditional [Microsoft product license](https://code.visualstudio.com/License/).
|
||||
|
|
|
@ -228,7 +228,14 @@ function packageTask(platform, arch, sourceFolderName, destinationFolderName, op
|
|||
.pipe(jsFilter)
|
||||
.pipe(util.rewriteSourceMappingURL(sourceMappingURLBase))
|
||||
.pipe(jsFilter.restore)
|
||||
.pipe(createAsar(path.join(process.cwd(), 'node_modules'), ['**/*.node', '**/vscode-ripgrep/bin/*', '**/node-pty/build/Release/*', '**/*.wasm'], 'node_modules.asar'));
|
||||
.pipe(createAsar(path.join(process.cwd(), 'node_modules'), [
|
||||
'**/*.node',
|
||||
'**/vscode-ripgrep/bin/*',
|
||||
'**/node-pty/build/Release/*',
|
||||
'**/node-pty/lib/worker/conoutSocketWorker.js',
|
||||
'**/node-pty/lib/shared/conout.js',
|
||||
'**/*.wasm'
|
||||
], 'node_modules.asar'));
|
||||
|
||||
let all = es.merge(
|
||||
packageJsonStream,
|
||||
|
|
|
@ -6,7 +6,7 @@
|
|||
"git": {
|
||||
"name": "chromium",
|
||||
"repositoryUrl": "https://chromium.googlesource.com/chromium/src",
|
||||
"commitHash": "5342041f85833c038dcbc5632d62fc10f7592323"
|
||||
"commitHash": "cd7a46bf02a768a1aabf9443f6ee469bc6e28e7c"
|
||||
}
|
||||
},
|
||||
"licenseDetail": [
|
||||
|
@ -40,7 +40,7 @@
|
|||
"SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
|
||||
],
|
||||
"isOnlyProductionDependency": true,
|
||||
"version": "89.0.4389.114"
|
||||
"version": "89.0.4389.128"
|
||||
},
|
||||
{
|
||||
"component": {
|
||||
|
@ -60,12 +60,12 @@
|
|||
"git": {
|
||||
"name": "electron",
|
||||
"repositoryUrl": "https://github.com/electron/electron",
|
||||
"commitHash": "9ce7c512475aa6aa91417a3b08e19f85a8587a30"
|
||||
"commitHash": "8d55658bfa8b5983e1a90ad079c2e2ac91ee7af0"
|
||||
}
|
||||
},
|
||||
"isOnlyProductionDependency": true,
|
||||
"license": "MIT",
|
||||
"version": "12.0.4"
|
||||
"version": "12.0.7"
|
||||
},
|
||||
{
|
||||
"component": {
|
||||
|
|
|
@ -54,6 +54,19 @@
|
|||
"type": "string",
|
||||
"description": "Label that will be shown in the UI for this port.",
|
||||
"default": "Application"
|
||||
},
|
||||
"requireLocalPort": {
|
||||
"type": "boolean",
|
||||
"markdownDescription": "When true, a modal dialog will show if the chosen local port isn't used for forwarding.",
|
||||
"default": false
|
||||
},
|
||||
"protocol": {
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"http",
|
||||
"https"
|
||||
],
|
||||
"description": "The protocol to use when forwarding this port."
|
||||
}
|
||||
},
|
||||
"default": {
|
||||
|
@ -80,7 +93,13 @@
|
|||
"properties": {
|
||||
"onAutoForward": {
|
||||
"type": "string",
|
||||
"enum": ["notify", "openBrowser", "openPreview", "silent", "ignore"],
|
||||
"enum": [
|
||||
"notify",
|
||||
"openBrowser",
|
||||
"openPreview",
|
||||
"silent",
|
||||
"ignore"
|
||||
],
|
||||
"enumDescriptions": [
|
||||
"Shows a notification when a port is automatically forwarded.",
|
||||
"Opens the browser when the port is automatically forwarded. Depending on your settings, this could open an embedded browser.",
|
||||
|
@ -100,9 +119,28 @@
|
|||
"type": "string",
|
||||
"description": "Label that will be shown in the UI for this port.",
|
||||
"default": "Application"
|
||||
},
|
||||
"requireLocalPort": {
|
||||
"type": "boolean",
|
||||
"markdownDescription": "When true, a modal dialog will show if the chosen local port isn't used for forwarding.",
|
||||
"default": false
|
||||
},
|
||||
"protocol": {
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"http",
|
||||
"https"
|
||||
],
|
||||
"description": "The protocol to use when forwarding this port."
|
||||
}
|
||||
},
|
||||
"defaultSnippets": [{ "body": { "onAutoForward": "ignore" } }],
|
||||
"defaultSnippets": [
|
||||
{
|
||||
"body": {
|
||||
"onAutoForward": "ignore"
|
||||
}
|
||||
}
|
||||
],
|
||||
"markdownDescription": "Set default properties that are applied to all ports that don't get properties from the setting `remote.portsAttributes`. For example:\n\n```\n{\n \"onAutoForward\": \"ignore\"\n}\n```",
|
||||
"additionalProperties": false
|
||||
},
|
||||
|
|
|
@ -162,6 +162,19 @@
|
|||
"type": "string",
|
||||
"description": "Label that will be shown in the UI for this port.",
|
||||
"default": "Application"
|
||||
},
|
||||
"requireLocalPort": {
|
||||
"type": "boolean",
|
||||
"markdownDescription": "When true, a modal dialog will show if the chosen local port isn't used for forwarding.",
|
||||
"default": false
|
||||
},
|
||||
"protocol": {
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"http",
|
||||
"https"
|
||||
],
|
||||
"description": "The protocol to use when forwarding this port."
|
||||
}
|
||||
},
|
||||
"default": {
|
||||
|
@ -215,6 +228,19 @@
|
|||
"type": "string",
|
||||
"description": "Label that will be shown in the UI for this port.",
|
||||
"default": "Application"
|
||||
},
|
||||
"requireLocalPort": {
|
||||
"type": "boolean",
|
||||
"markdownDescription": "When true, a modal dialog will show if the chosen local port isn't used for forwarding.",
|
||||
"default": false
|
||||
},
|
||||
"protocol": {
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"http",
|
||||
"https"
|
||||
],
|
||||
"description": "The protocol to use when forwarding this port."
|
||||
}
|
||||
},
|
||||
"defaultSnippets": [
|
||||
|
@ -461,6 +487,19 @@
|
|||
"type": "string",
|
||||
"description": "Label that will be shown in the UI for this port.",
|
||||
"default": "Application"
|
||||
},
|
||||
"requireLocalPort": {
|
||||
"type": "boolean",
|
||||
"markdownDescription": "When true, a modal dialog will show if the chosen local port isn't used for forwarding.",
|
||||
"default": false
|
||||
},
|
||||
"protocol": {
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"http",
|
||||
"https"
|
||||
],
|
||||
"description": "The protocol to use when forwarding this port."
|
||||
}
|
||||
},
|
||||
"default": {
|
||||
|
@ -514,6 +553,19 @@
|
|||
"type": "string",
|
||||
"description": "Label that will be shown in the UI for this port.",
|
||||
"default": "Application"
|
||||
},
|
||||
"requireLocalPort": {
|
||||
"type": "boolean",
|
||||
"markdownDescription": "When true, a modal dialog will show if the chosen local port isn't used for forwarding.",
|
||||
"default": false
|
||||
},
|
||||
"protocol": {
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"http",
|
||||
"https"
|
||||
],
|
||||
"description": "The protocol to use when forwarding this port."
|
||||
}
|
||||
},
|
||||
"defaultSnippets": [
|
||||
|
@ -736,6 +788,19 @@
|
|||
"type": "string",
|
||||
"description": "Label that will be shown in the UI for this port.",
|
||||
"default": "Application"
|
||||
},
|
||||
"requireLocalPort": {
|
||||
"type": "boolean",
|
||||
"markdownDescription": "When true, a modal dialog will show if the chosen local port isn't used for forwarding.",
|
||||
"default": false
|
||||
},
|
||||
"protocol": {
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"http",
|
||||
"https"
|
||||
],
|
||||
"description": "The protocol to use when forwarding this port."
|
||||
}
|
||||
},
|
||||
"default": {
|
||||
|
@ -789,6 +854,19 @@
|
|||
"type": "string",
|
||||
"description": "Label that will be shown in the UI for this port.",
|
||||
"default": "Application"
|
||||
},
|
||||
"requireLocalPort": {
|
||||
"type": "boolean",
|
||||
"markdownDescription": "When true, a modal dialog will show if the chosen local port isn't used for forwarding.",
|
||||
"default": false
|
||||
},
|
||||
"protocol": {
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"http",
|
||||
"https"
|
||||
],
|
||||
"description": "The protocol to use when forwarding this port."
|
||||
}
|
||||
},
|
||||
"defaultSnippets": [
|
||||
|
@ -977,6 +1055,19 @@
|
|||
"type": "string",
|
||||
"description": "Label that will be shown in the UI for this port.",
|
||||
"default": "Application"
|
||||
},
|
||||
"requireLocalPort": {
|
||||
"type": "boolean",
|
||||
"markdownDescription": "When true, a modal dialog will show if the chosen local port isn't used for forwarding.",
|
||||
"default": false
|
||||
},
|
||||
"protocol": {
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"http",
|
||||
"https"
|
||||
],
|
||||
"description": "The protocol to use when forwarding this port."
|
||||
}
|
||||
},
|
||||
"default": {
|
||||
|
@ -1030,6 +1121,19 @@
|
|||
"type": "string",
|
||||
"description": "Label that will be shown in the UI for this port.",
|
||||
"default": "Application"
|
||||
},
|
||||
"requireLocalPort": {
|
||||
"type": "boolean",
|
||||
"markdownDescription": "When true, a modal dialog will show if the chosen local port isn't used for forwarding.",
|
||||
"default": false
|
||||
},
|
||||
"protocol": {
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"http",
|
||||
"https"
|
||||
],
|
||||
"description": "The protocol to use when forwarding this port."
|
||||
}
|
||||
},
|
||||
"defaultSnippets": [
|
||||
|
@ -1187,6 +1291,19 @@
|
|||
"type": "string",
|
||||
"description": "Label that will be shown in the UI for this port.",
|
||||
"default": "Application"
|
||||
},
|
||||
"requireLocalPort": {
|
||||
"type": "boolean",
|
||||
"markdownDescription": "When true, a modal dialog will show if the chosen local port isn't used for forwarding.",
|
||||
"default": false
|
||||
},
|
||||
"protocol": {
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"http",
|
||||
"https"
|
||||
],
|
||||
"description": "The protocol to use when forwarding this port."
|
||||
}
|
||||
},
|
||||
"default": {
|
||||
|
@ -1240,6 +1357,19 @@
|
|||
"type": "string",
|
||||
"description": "Label that will be shown in the UI for this port.",
|
||||
"default": "Application"
|
||||
},
|
||||
"requireLocalPort": {
|
||||
"type": "boolean",
|
||||
"markdownDescription": "When true, a modal dialog will show if the chosen local port isn't used for forwarding.",
|
||||
"default": false
|
||||
},
|
||||
"protocol": {
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"http",
|
||||
"https"
|
||||
],
|
||||
"description": "The protocol to use when forwarding this port."
|
||||
}
|
||||
},
|
||||
"defaultSnippets": [
|
||||
|
|
|
@ -68,6 +68,16 @@
|
|||
"type": "string",
|
||||
"description": "Label that will be shown in the UI for this port.",
|
||||
"default": "Application"
|
||||
},
|
||||
"requireLocalPort": {
|
||||
"type": "boolean",
|
||||
"markdownDescription": "When true, a modal dialog will show if the chosen local port isn't used for forwarding.",
|
||||
"default": false
|
||||
},
|
||||
"protocol": {
|
||||
"type": "string",
|
||||
"enum": ["http", "https"],
|
||||
"description": "The protocol to use when forwarding this port."
|
||||
}
|
||||
},
|
||||
"default": {
|
||||
|
@ -120,6 +130,16 @@
|
|||
"type": "string",
|
||||
"description": "Label that will be shown in the UI for this port.",
|
||||
"default": "Application"
|
||||
},
|
||||
"requireLocalPort": {
|
||||
"type": "boolean",
|
||||
"markdownDescription": "When true, a modal dialog will show if the chosen local port isn't used for forwarding.",
|
||||
"default": false
|
||||
},
|
||||
"protocol": {
|
||||
"type": "string",
|
||||
"enum": ["http", "https"],
|
||||
"description": "The protocol to use when forwarding this port."
|
||||
}
|
||||
},
|
||||
"defaultSnippets": [
|
||||
|
|
|
@ -315,12 +315,10 @@ function updateStatusBar(context: vscode.ExtensionContext, state: State, busy =
|
|||
}
|
||||
|
||||
if (!statusItem) {
|
||||
statusItem = vscode.window.createStatusBarItem(vscode.StatusBarAlignment.Left);
|
||||
statusItem = vscode.window.createStatusBarItem('status.debug.autoAttach', vscode.StatusBarAlignment.Left);
|
||||
statusItem.name = localize('status.name.auto.attach', "Debug Auto Attach");
|
||||
statusItem.command = TOGGLE_COMMAND;
|
||||
statusItem.tooltip = localize(
|
||||
'status.tooltip.auto.attach',
|
||||
'Automatically attach to node.js processes in debug mode',
|
||||
);
|
||||
statusItem.tooltip = localize('status.tooltip.auto.attach', "Automatically attach to node.js processes in debug mode");
|
||||
context.subscriptions.push(statusItem);
|
||||
}
|
||||
|
||||
|
|
|
@ -179,7 +179,8 @@ export class GitHubServer {
|
|||
|
||||
private updateStatusBarItem(isStart?: boolean) {
|
||||
if (isStart && !this._statusBarItem) {
|
||||
this._statusBarItem = vscode.window.createStatusBarItem(vscode.StatusBarAlignment.Left);
|
||||
this._statusBarItem = vscode.window.createStatusBarItem('status.git.signIn', vscode.StatusBarAlignment.Left);
|
||||
this._statusBarItem.name = localize('status.git.signIn.name', "GitHub Sign-in");
|
||||
this._statusBarItem.text = this.type === AuthProviderType.github
|
||||
? localize('signingIn', "$(mark-github) Signing in to github.com...")
|
||||
: localize('signingInEnterprise', "$(mark-github) Signing in to {0}...", this.getServerUri().authority);
|
||||
|
|
|
@ -39,12 +39,7 @@ class BinarySize {
|
|||
export class BinarySizeStatusBarEntry extends PreviewStatusBarEntry {
|
||||
|
||||
constructor() {
|
||||
super({
|
||||
id: 'imagePreview.binarySize',
|
||||
name: localize('sizeStatusBar.name', "Image Binary Size"),
|
||||
alignment: vscode.StatusBarAlignment.Right,
|
||||
priority: 100,
|
||||
});
|
||||
super('status.imagePreview.binarySize', localize('sizeStatusBar.name', "Image Binary Size"), vscode.StatusBarAlignment.Right, 100);
|
||||
}
|
||||
|
||||
public show(owner: string, size: number | undefined) {
|
||||
|
|
|
@ -11,9 +11,10 @@ export abstract class PreviewStatusBarEntry extends Disposable {
|
|||
|
||||
protected readonly entry: vscode.StatusBarItem;
|
||||
|
||||
constructor(options: vscode.StatusBarItemOptions) {
|
||||
constructor(id: string, name: string, alignment: vscode.StatusBarAlignment, priority: number) {
|
||||
super();
|
||||
this.entry = this._register(vscode.window.createStatusBarItem(options));
|
||||
this.entry = this._register(vscode.window.createStatusBarItem(id, alignment, priority));
|
||||
this.entry.name = name;
|
||||
}
|
||||
|
||||
protected showItem(owner: string, text: string) {
|
||||
|
|
|
@ -12,12 +12,7 @@ const localize = nls.loadMessageBundle();
|
|||
export class SizeStatusBarEntry extends PreviewStatusBarEntry {
|
||||
|
||||
constructor() {
|
||||
super({
|
||||
id: 'imagePreview.size',
|
||||
name: localize('sizeStatusBar.name', "Image Size"),
|
||||
alignment: vscode.StatusBarAlignment.Right,
|
||||
priority: 101 /* to the left of editor status (100) */,
|
||||
});
|
||||
super('status.imagePreview.size', localize('sizeStatusBar.name', "Image Size"), vscode.StatusBarAlignment.Right, 101 /* to the left of editor status (100) */);
|
||||
}
|
||||
|
||||
public show(owner: string, text: string) {
|
||||
|
|
|
@ -19,12 +19,7 @@ export class ZoomStatusBarEntry extends OwnedStatusBarEntry {
|
|||
public readonly onDidChangeScale = this._onDidChangeScale.event;
|
||||
|
||||
constructor() {
|
||||
super({
|
||||
id: 'imagePreview.zoom',
|
||||
name: localize('zoomStatusBar.name', "Image Zoom"),
|
||||
alignment: vscode.StatusBarAlignment.Right,
|
||||
priority: 102 /* to the left of editor size entry (101) */,
|
||||
});
|
||||
super('status.imagePreview.zoom', localize('zoomStatusBar.name', "Image Zoom"), vscode.StatusBarAlignment.Right, 102 /* to the left of editor size entry (101) */);
|
||||
|
||||
this._register(vscode.commands.registerCommand(selectZoomLevelCommandId, async () => {
|
||||
type MyPickItem = vscode.QuickPickItem & { scale: Scale };
|
||||
|
|
|
@ -101,12 +101,8 @@ export function startClient(context: ExtensionContext, newLanguageClient: Langua
|
|||
|
||||
const documentSelector = ['json', 'jsonc'];
|
||||
|
||||
const schemaResolutionErrorStatusBarItem = window.createStatusBarItem({
|
||||
id: 'status.json.resolveError',
|
||||
name: localize('json.resolveError', "JSON: Schema Resolution Error"),
|
||||
alignment: StatusBarAlignment.Right,
|
||||
priority: 0,
|
||||
});
|
||||
const schemaResolutionErrorStatusBarItem = window.createStatusBarItem('status.json.resolveError', StatusBarAlignment.Right, 0);
|
||||
schemaResolutionErrorStatusBarItem.name = localize('json.resolveError', "JSON: Schema Resolution Error");
|
||||
schemaResolutionErrorStatusBarItem.text = '$(alert)';
|
||||
toDispose.push(schemaResolutionErrorStatusBarItem);
|
||||
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
{
|
||||
"description": "Extension to add task support for npm scripts.",
|
||||
"displayName": "NPM support for VS Code",
|
||||
"workspaceTrust": "This extension calls the `tasks.executeTask()` API, which requires trust to run.",
|
||||
"workspaceTrust": "This extension executes tasks, which require trust to run.",
|
||||
"config.npm.autoDetect": "Controls whether npm scripts should be automatically detected.",
|
||||
"config.npm.runSilent": "Run npm commands with the `--silent` option.",
|
||||
"config.npm.packageManager": "The package manager used to run scripts.",
|
||||
|
|
|
@ -25,7 +25,7 @@
|
|||
"notebook.cellBorderColor": "#E8E8E8",
|
||||
"notebook.selectedCellBackground": "#c8ddf150",
|
||||
"statusBarItem.errorBackground": "#c72e0f",
|
||||
"list.focusHighlightForeground": "#33B6FF"
|
||||
"list.focusHighlightForeground": "#9DDDFF"
|
||||
},
|
||||
"tokenColors": [
|
||||
{
|
||||
|
|
|
@ -135,12 +135,8 @@ export default class VersionStatus extends Disposable {
|
|||
) {
|
||||
super();
|
||||
|
||||
this._statusBarEntry = this._register(vscode.window.createStatusBarItem({
|
||||
id: 'status.typescript',
|
||||
name: localize('projectInfo.name', "TypeScript: Project Info"),
|
||||
alignment: vscode.StatusBarAlignment.Right,
|
||||
priority: 99 /* to the right of editor status (100) */
|
||||
}));
|
||||
this._statusBarEntry = this._register(vscode.window.createStatusBarItem('status.typescript', vscode.StatusBarAlignment.Right, 99 /* to the right of editor status (100) */));
|
||||
this._statusBarEntry.name = localize('projectInfo.name', "TypeScript: Project Info");
|
||||
|
||||
const command = new ProjectStatusCommand(this._client, () => this._state);
|
||||
commandManager.register(command);
|
||||
|
|
|
@ -23,12 +23,8 @@ class ExcludeHintItem {
|
|||
constructor(
|
||||
private readonly telemetryReporter: TelemetryReporter
|
||||
) {
|
||||
this._item = vscode.window.createStatusBarItem({
|
||||
id: 'status.typescript.exclude',
|
||||
name: localize('statusExclude', "TypeScript: Configure Excludes"),
|
||||
alignment: vscode.StatusBarAlignment.Right,
|
||||
priority: 98 /* to the right of typescript version status (99) */
|
||||
});
|
||||
this._item = vscode.window.createStatusBarItem('status.typescript.exclude', vscode.StatusBarAlignment.Right, 98 /* to the right of typescript version status (99) */);
|
||||
this._item.name = localize('statusExclude', "TypeScript: Configure Excludes");
|
||||
this._item.command = 'js.projectStatus.command';
|
||||
}
|
||||
|
||||
|
|
|
@ -91,16 +91,27 @@ suite('Notebook Document', function () {
|
|||
test('notebook open/close, notebook ready when cell-document open event is fired', async function () {
|
||||
const uri = await utils.createRandomFile(undefined, undefined, '.nbdtest');
|
||||
let didHappen = false;
|
||||
const p = utils.asPromise(vscode.workspace.onDidOpenTextDocument).then(doc => {
|
||||
if (doc.uri.scheme !== 'vscode-notebook-cell') {
|
||||
return;
|
||||
}
|
||||
const notebook = vscode.notebook.notebookDocuments.find(notebook => {
|
||||
const cell = notebook.getCells().find(cell => cell.document === doc);
|
||||
return Boolean(cell);
|
||||
|
||||
const p = new Promise<void>((resolve, reject) => {
|
||||
const sub = vscode.workspace.onDidOpenTextDocument(doc => {
|
||||
if (doc.uri.scheme !== 'vscode-notebook-cell') {
|
||||
// ignore other open events
|
||||
return;
|
||||
}
|
||||
const notebook = vscode.notebook.notebookDocuments.find(notebook => {
|
||||
const cell = notebook.getCells().find(cell => cell.document === doc);
|
||||
return Boolean(cell);
|
||||
});
|
||||
assert.ok(notebook, `notebook for cell ${doc.uri} NOT found`);
|
||||
didHappen = true;
|
||||
sub.dispose();
|
||||
resolve();
|
||||
});
|
||||
assert.ok(notebook, `notebook for cell ${doc.uri} NOT found`);
|
||||
didHappen = true;
|
||||
|
||||
setTimeout(() => {
|
||||
sub.dispose();
|
||||
reject(new Error('TIMEOUT'));
|
||||
}, 15000);
|
||||
});
|
||||
|
||||
await vscode.notebook.openNotebookDocument(uri);
|
||||
|
|
|
@ -440,12 +440,12 @@ suite('Notebook API tests', function () {
|
|||
await cellsChangeEvent;
|
||||
await cellMetadataChangeEvent;
|
||||
assert.strictEqual(vscode.window.activeNotebookEditor!.document.cellCount, 3);
|
||||
assert.strictEqual(vscode.window.activeNotebookEditor!.document.cellAt(0)?.metadata?.inputCollapsed, false);
|
||||
assert.strictEqual(vscode.window.activeNotebookEditor!.document.cellAt(0)?.metadata.inputCollapsed, false);
|
||||
assert.strictEqual(version + 1, vscode.window.activeNotebookEditor!.document.version);
|
||||
|
||||
await vscode.commands.executeCommand('undo');
|
||||
assert.strictEqual(version + 2, vscode.window.activeNotebookEditor!.document.version);
|
||||
assert.strictEqual(vscode.window.activeNotebookEditor!.document.cellAt(0)?.metadata?.inputCollapsed, undefined);
|
||||
assert.strictEqual(vscode.window.activeNotebookEditor!.document.cellAt(0)?.metadata.inputCollapsed, undefined);
|
||||
assert.strictEqual(vscode.window.activeNotebookEditor!.document.cellCount, 2);
|
||||
});
|
||||
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import * as assert from 'assert';
|
||||
import { workspace, window, commands, ViewColumn, TextEditorViewColumnChangeEvent, Uri, Selection, Position, CancellationTokenSource, TextEditorSelectionChangeKind, QuickPickItem, TextEditor } from 'vscode';
|
||||
import { workspace, window, commands, ViewColumn, TextEditorViewColumnChangeEvent, Uri, Selection, Position, CancellationTokenSource, TextEditorSelectionChangeKind, QuickPickItem, TextEditor, StatusBarAlignment } from 'vscode';
|
||||
import { join } from 'path';
|
||||
import { closeAllEditors, pathEquals, createRandomFile, assertNoRpc } from '../utils';
|
||||
|
||||
|
@ -638,4 +638,22 @@ suite('vscode API - window', () => {
|
|||
|
||||
});
|
||||
});
|
||||
|
||||
test('createStatusBar', async function () {
|
||||
const statusBarEntryWithoutId = window.createStatusBarItem(StatusBarAlignment.Left, 100);
|
||||
assert.strictEqual(statusBarEntryWithoutId.id, 'vscode.vscode-api-tests');
|
||||
assert.strictEqual(statusBarEntryWithoutId.alignment, StatusBarAlignment.Left);
|
||||
assert.strictEqual(statusBarEntryWithoutId.priority, 100);
|
||||
assert.strictEqual(statusBarEntryWithoutId.name, undefined);
|
||||
statusBarEntryWithoutId.name = 'Test Name';
|
||||
assert.strictEqual(statusBarEntryWithoutId.name, 'Test Name');
|
||||
|
||||
const statusBarEntryWithId = window.createStatusBarItem('testId', StatusBarAlignment.Right, 200);
|
||||
assert.strictEqual(statusBarEntryWithId.alignment, StatusBarAlignment.Right);
|
||||
assert.strictEqual(statusBarEntryWithId.priority, 200);
|
||||
assert.strictEqual(statusBarEntryWithId.id, 'testId');
|
||||
assert.strictEqual(statusBarEntryWithId.name, undefined);
|
||||
statusBarEntryWithId.name = 'Test Name';
|
||||
assert.strictEqual(statusBarEntryWithId.name, 'Test Name');
|
||||
});
|
||||
});
|
||||
|
|
|
@ -137,3 +137,9 @@ export async function asPromise<T>(event: vscode.Event<T>, timeout = vscode.env.
|
|||
});
|
||||
});
|
||||
}
|
||||
|
||||
export function testRepeat(n: number, description: string, callback: (this: any) => any): void {
|
||||
for (let i = 0; i < n; i++) {
|
||||
test(`${description} (iteration ${i})`, callback);
|
||||
}
|
||||
}
|
||||
|
|
10
package.json
10
package.json
|
@ -1,7 +1,7 @@
|
|||
{
|
||||
"name": "code-oss-dev",
|
||||
"version": "1.57.0",
|
||||
"distro": "0a045304c3e628e1aaf00003d2c9063264bd9bb5",
|
||||
"distro": "ecdb89a80900940251ce4a8083f6b2e4b032b583",
|
||||
"author": {
|
||||
"name": "Microsoft Corporation"
|
||||
},
|
||||
|
@ -69,7 +69,7 @@
|
|||
"native-is-elevated": "0.4.3",
|
||||
"native-keymap": "2.2.1",
|
||||
"native-watchdog": "1.3.0",
|
||||
"node-pty": "0.10.1",
|
||||
"node-pty": "0.11.0-beta7",
|
||||
"nsfw": "2.1.2",
|
||||
"spdlog": "^0.13.0",
|
||||
"sudo-prompt": "9.2.1",
|
||||
|
@ -81,10 +81,10 @@
|
|||
"vscode-ripgrep": "^1.11.3",
|
||||
"vscode-sqlite3": "4.0.11",
|
||||
"vscode-textmate": "5.4.0",
|
||||
"xterm": "4.12.0-beta.26",
|
||||
"xterm": "4.13.0-beta.1",
|
||||
"xterm-addon-search": "0.9.0-beta.2",
|
||||
"xterm-addon-unicode11": "0.3.0-beta.5",
|
||||
"xterm-addon-webgl": "0.11.0-beta.8",
|
||||
"xterm-addon-webgl": "0.11.1",
|
||||
"yauzl": "^2.9.2",
|
||||
"yazl": "^2.4.3"
|
||||
},
|
||||
|
@ -125,7 +125,7 @@
|
|||
"cssnano": "^4.1.11",
|
||||
"debounce": "^1.0.0",
|
||||
"deemon": "^1.4.0",
|
||||
"electron": "12.0.4",
|
||||
"electron": "12.0.7",
|
||||
"eslint": "6.8.0",
|
||||
"eslint-plugin-jsdoc": "^19.1.0",
|
||||
"event-stream": "3.3.4",
|
||||
|
|
|
@ -48,7 +48,7 @@
|
|||
},
|
||||
{
|
||||
"name": "ms-vscode.node-debug2",
|
||||
"version": "1.42.6",
|
||||
"version": "1.42.7",
|
||||
"repo": "https://github.com/microsoft/vscode-node-debug2",
|
||||
"metadata": {
|
||||
"id": "36d19e17-7569-4841-a001-947eb18602b2",
|
||||
|
|
|
@ -13,7 +13,7 @@
|
|||
"jschardet": "3.0.0",
|
||||
"minimist": "^1.2.5",
|
||||
"native-watchdog": "1.3.0",
|
||||
"node-pty": "0.10.1",
|
||||
"node-pty": "0.11.0-beta7",
|
||||
"nsfw": "2.1.2",
|
||||
"spdlog": "^0.13.0",
|
||||
"tas-client-umd": "0.1.4",
|
||||
|
@ -22,10 +22,10 @@
|
|||
"vscode-regexpp": "^3.1.0",
|
||||
"vscode-ripgrep": "^1.11.3",
|
||||
"vscode-textmate": "5.4.0",
|
||||
"xterm": "4.12.0-beta.26",
|
||||
"xterm": "4.13.0-beta.1",
|
||||
"xterm-addon-search": "0.9.0-beta.2",
|
||||
"xterm-addon-unicode11": "0.3.0-beta.5",
|
||||
"xterm-addon-webgl": "0.11.0-beta.8",
|
||||
"xterm-addon-webgl": "0.11.1",
|
||||
"yauzl": "^2.9.2",
|
||||
"yazl": "^2.4.3"
|
||||
},
|
||||
|
|
|
@ -8,9 +8,9 @@
|
|||
"tas-client-umd": "0.1.4",
|
||||
"vscode-oniguruma": "1.5.1",
|
||||
"vscode-textmate": "5.4.0",
|
||||
"xterm": "4.12.0-beta.26",
|
||||
"xterm": "4.13.0-beta.1",
|
||||
"xterm-addon-search": "0.9.0-beta.2",
|
||||
"xterm-addon-unicode11": "0.3.0-beta.5",
|
||||
"xterm-addon-webgl": "0.11.0-beta.8"
|
||||
"xterm-addon-webgl": "0.11.1"
|
||||
}
|
||||
}
|
||||
|
|
|
@ -37,12 +37,12 @@ xterm-addon-unicode11@0.3.0-beta.5:
|
|||
resolved "https://registry.yarnpkg.com/xterm-addon-unicode11/-/xterm-addon-unicode11-0.3.0-beta.5.tgz#7e490799d530d3b301125c7a4e92317c161761c4"
|
||||
integrity sha512-SgDDL3PoMH1G48JO6T45whKAex4NPxi80UzUVitnrqyd8dFQP+oF6cxqUutULgm9HSGk62qy3mrZvIMGO5VXog==
|
||||
|
||||
xterm-addon-webgl@0.11.0-beta.8:
|
||||
version "0.11.0-beta.8"
|
||||
resolved "https://registry.yarnpkg.com/xterm-addon-webgl/-/xterm-addon-webgl-0.11.0-beta.8.tgz#8cb4925d67c31beb8144275daf46358f42eff9fe"
|
||||
integrity sha512-udRmQ/jgH8cL8VQOZweytkToIROevVeiA7WY0tIe878Wt2zKY+AYHZV8js3c1W9wHDu5G90BhmzTidJ5UwZK3Q==
|
||||
xterm-addon-webgl@0.11.1:
|
||||
version "0.11.1"
|
||||
resolved "https://registry.yarnpkg.com/xterm-addon-webgl/-/xterm-addon-webgl-0.11.1.tgz#33dd250ab52e9f51d2ff52396447962e6f53e24c"
|
||||
integrity sha512-xF6DnEoV+rPtzetMBXBZVe1kLKtus7AKdEcyfq2eMHQzhaRvC+pfnU+XiCXC85kueguqu2UkBHXZs5mihK9jOQ==
|
||||
|
||||
xterm@4.12.0-beta.26:
|
||||
version "4.12.0-beta.26"
|
||||
resolved "https://registry.yarnpkg.com/xterm/-/xterm-4.12.0-beta.26.tgz#57c75b732808795398a66bc1a3e06d09eaff2ada"
|
||||
integrity sha512-yZB1kMBXQu2G0G1ch7TUi6f893iTZC+tmfjw/PQNZTmN46b4oX1l7rplc3sFcdrICHtmQ0Q5n1u0d6WUAdq1Kw==
|
||||
xterm@4.13.0-beta.1:
|
||||
version "4.13.0-beta.1"
|
||||
resolved "https://registry.yarnpkg.com/xterm/-/xterm-4.13.0-beta.1.tgz#ad2ad321c69a4add6e878c890f278a1da74fd7d0"
|
||||
integrity sha512-gAMGqBglESTxQWph1uKVyd1jO/6eKsbicNG+Mr/YAsj06TjFVcLw839Iqu6P+DVFEV7lLLspcOb8fwX6qMBH/Q==
|
||||
|
|
|
@ -353,10 +353,10 @@ node-addon-api@*, node-addon-api@^3.0.2:
|
|||
resolved "https://registry.yarnpkg.com/node-addon-api/-/node-addon-api-3.1.0.tgz#98b21931557466c6729e51cb77cd39c965f42239"
|
||||
integrity sha512-flmrDNB06LIl5lywUz7YlNGZH/5p0M7W28k8hzd9Lshtdh1wshD2Y+U4h9LD6KObOy1f+fEVdgprPrEymjM5uw==
|
||||
|
||||
node-pty@0.10.1:
|
||||
version "0.10.1"
|
||||
resolved "https://registry.yarnpkg.com/node-pty/-/node-pty-0.10.1.tgz#cd05d03a2710315ec40221232ec04186f6ac2c6d"
|
||||
integrity sha512-JTdtUS0Im/yRsWJSx7yiW9rtpfmxqxolrtnyKwPLI+6XqTAPW/O2MjS8FYL4I5TsMbH2lVgDb2VMjp+9LoQGNg==
|
||||
node-pty@0.11.0-beta7:
|
||||
version "0.11.0-beta7"
|
||||
resolved "https://registry.yarnpkg.com/node-pty/-/node-pty-0.11.0-beta7.tgz#aed0888b5032d96c54d8473455e6adfae3bbebbe"
|
||||
integrity sha512-uApPGLglZRiHQcUMWakbZOrBo8HVWvhzIqNnrWvBGJOvc6m/S5lCdbbg93BURyJqHFmBS0GV+4hwiMNDuGRbSA==
|
||||
dependencies:
|
||||
nan "^2.14.0"
|
||||
|
||||
|
@ -539,15 +539,15 @@ xterm-addon-unicode11@0.3.0-beta.5:
|
|||
resolved "https://registry.yarnpkg.com/xterm-addon-unicode11/-/xterm-addon-unicode11-0.3.0-beta.5.tgz#7e490799d530d3b301125c7a4e92317c161761c4"
|
||||
integrity sha512-SgDDL3PoMH1G48JO6T45whKAex4NPxi80UzUVitnrqyd8dFQP+oF6cxqUutULgm9HSGk62qy3mrZvIMGO5VXog==
|
||||
|
||||
xterm-addon-webgl@0.11.0-beta.8:
|
||||
version "0.11.0-beta.8"
|
||||
resolved "https://registry.yarnpkg.com/xterm-addon-webgl/-/xterm-addon-webgl-0.11.0-beta.8.tgz#8cb4925d67c31beb8144275daf46358f42eff9fe"
|
||||
integrity sha512-udRmQ/jgH8cL8VQOZweytkToIROevVeiA7WY0tIe878Wt2zKY+AYHZV8js3c1W9wHDu5G90BhmzTidJ5UwZK3Q==
|
||||
xterm-addon-webgl@0.11.1:
|
||||
version "0.11.1"
|
||||
resolved "https://registry.yarnpkg.com/xterm-addon-webgl/-/xterm-addon-webgl-0.11.1.tgz#33dd250ab52e9f51d2ff52396447962e6f53e24c"
|
||||
integrity sha512-xF6DnEoV+rPtzetMBXBZVe1kLKtus7AKdEcyfq2eMHQzhaRvC+pfnU+XiCXC85kueguqu2UkBHXZs5mihK9jOQ==
|
||||
|
||||
xterm@4.12.0-beta.26:
|
||||
version "4.12.0-beta.26"
|
||||
resolved "https://registry.yarnpkg.com/xterm/-/xterm-4.12.0-beta.26.tgz#57c75b732808795398a66bc1a3e06d09eaff2ada"
|
||||
integrity sha512-yZB1kMBXQu2G0G1ch7TUi6f893iTZC+tmfjw/PQNZTmN46b4oX1l7rplc3sFcdrICHtmQ0Q5n1u0d6WUAdq1Kw==
|
||||
xterm@4.13.0-beta.1:
|
||||
version "4.13.0-beta.1"
|
||||
resolved "https://registry.yarnpkg.com/xterm/-/xterm-4.13.0-beta.1.tgz#ad2ad321c69a4add6e878c890f278a1da74fd7d0"
|
||||
integrity sha512-gAMGqBglESTxQWph1uKVyd1jO/6eKsbicNG+Mr/YAsj06TjFVcLw839Iqu6P+DVFEV7lLLspcOb8fwX6qMBH/Q==
|
||||
|
||||
yauzl@^2.9.2:
|
||||
version "2.10.0"
|
||||
|
|
|
@ -312,6 +312,14 @@ function getInsaneOptions(options: { readonly isTrusted?: boolean }): InsaneOpti
|
|||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Strips all markdown from `string`, if it's an IMarkdownString. For example
|
||||
* `# Header` would be output as `Header`. If it's not, the string is returned.
|
||||
*/
|
||||
export function renderStringAsPlaintext(string: IMarkdownString | string) {
|
||||
return typeof string === 'string' ? string : renderMarkdownAsPlaintext(string);
|
||||
}
|
||||
|
||||
/**
|
||||
* Strips all markdown from `markdown`. For example `# Header` would be output as `Header`.
|
||||
*/
|
||||
|
|
|
@ -101,16 +101,17 @@ export class Dialog extends Disposable {
|
|||
this.buttonsContainer = buttonsRowElement.appendChild($('.dialog-buttons'));
|
||||
|
||||
const messageRowElement = this.element.appendChild($('.dialog-message-row'));
|
||||
this.iconElement = messageRowElement.appendChild($('.dialog-icon'));
|
||||
this.iconElement = messageRowElement.appendChild($('#monaco-dialog-icon.dialog-icon'));
|
||||
this.iconElement.setAttribute('aria-label', this.getIconAriaLabel());
|
||||
this.messageContainer = messageRowElement.appendChild($('.dialog-message-container'));
|
||||
|
||||
if (this.options.detail || this.options.renderBody) {
|
||||
const messageElement = this.messageContainer.appendChild($('.dialog-message'));
|
||||
const messageTextElement = messageElement.appendChild($('.dialog-message-text'));
|
||||
const messageTextElement = messageElement.appendChild($('#monaco-dialog-message-text.dialog-message-text'));
|
||||
messageTextElement.innerText = this.message;
|
||||
}
|
||||
|
||||
this.messageDetailElement = this.messageContainer.appendChild($('.dialog-message-detail'));
|
||||
this.messageDetailElement = this.messageContainer.appendChild($('#monaco-dialog-message-detail.dialog-message-detail'));
|
||||
if (this.options.detail || !this.options.renderBody) {
|
||||
this.messageDetailElement.innerText = this.options.detail ? this.options.detail : message;
|
||||
} else {
|
||||
|
@ -118,7 +119,7 @@ export class Dialog extends Disposable {
|
|||
}
|
||||
|
||||
if (this.options.renderBody) {
|
||||
const customBody = this.messageContainer.appendChild($('.dialog-message-body'));
|
||||
const customBody = this.messageContainer.appendChild($('#monaco-dialog-message-body.dialog-message-body'));
|
||||
this.options.renderBody(customBody);
|
||||
|
||||
for (const el of this.messageContainer.querySelectorAll('a')) {
|
||||
|
@ -161,7 +162,7 @@ export class Dialog extends Disposable {
|
|||
this.toolbarContainer = toolbarRowElement.appendChild($('.dialog-toolbar'));
|
||||
}
|
||||
|
||||
private getAriaLabel(): string {
|
||||
private getIconAriaLabel(): string {
|
||||
let typeLabel = nls.localize('dialogInfoMessage', 'Info');
|
||||
switch (this.options.type) {
|
||||
case 'error':
|
||||
|
@ -180,7 +181,7 @@ export class Dialog extends Disposable {
|
|||
break;
|
||||
}
|
||||
|
||||
return `${typeLabel}: ${this.message} ${this.options.detail || ''}`;
|
||||
return typeLabel;
|
||||
}
|
||||
|
||||
updateMessage(message: string): void {
|
||||
|
@ -390,7 +391,7 @@ export class Dialog extends Disposable {
|
|||
|
||||
this.applyStyles();
|
||||
|
||||
this.element.setAttribute('aria-label', this.getAriaLabel());
|
||||
this.element.setAttribute('aria-labelledby', 'monaco-dialog-icon monaco-dialog-message-text monaco-dialog-message-detail monaco-dialog-message-body');
|
||||
show(this.element);
|
||||
|
||||
// Focus first element (input or button)
|
||||
|
|
|
@ -22,6 +22,23 @@ export function toSlashes(osPath: string) {
|
|||
return osPath.replace(/[\\/]/g, posix.sep);
|
||||
}
|
||||
|
||||
/**
|
||||
* Takes a Windows OS path (using backward or forward slashes) and turns it into a posix path:
|
||||
* - turns backward slashes into forward slashes
|
||||
* - makes it absolute if it starts with a drive letter
|
||||
* This should only be done for OS paths from Windows (or user provided paths potentially from Windows).
|
||||
* Using it on a Linux or MaxOS path might change it.
|
||||
*/
|
||||
export function toPosixPath(osPath: string) {
|
||||
if (osPath.indexOf('/') === -1) {
|
||||
osPath = toSlashes(osPath);
|
||||
}
|
||||
if (/^[a-zA-Z]:(\/|$)/.test(osPath)) { // starts with a drive letter
|
||||
osPath = '/' + osPath;
|
||||
}
|
||||
return osPath;
|
||||
}
|
||||
|
||||
/**
|
||||
* Computes the _root_ this path, like `getRoot('c:\files') === c:\`,
|
||||
* `getRoot('files:///files/path') === files:///`,
|
||||
|
|
|
@ -264,12 +264,7 @@ export class ExtUri implements IExtUri {
|
|||
path: newURI.path
|
||||
});
|
||||
}
|
||||
if (path.indexOf('/') === -1) { // no slashes? it's likely a Windows path
|
||||
path = extpath.toSlashes(path);
|
||||
if (/^[a-zA-Z]:(\/|$)/.test(path)) { // starts with a drive letter
|
||||
path = '/' + path;
|
||||
}
|
||||
}
|
||||
path = extpath.toPosixPath(path); // we allow path to be a windows path
|
||||
return base.with({
|
||||
path: paths.posix.resolve(base.path, path)
|
||||
});
|
||||
|
|
|
@ -327,13 +327,15 @@ export class URI implements UriComponents {
|
|||
}
|
||||
|
||||
static from(components: { scheme: string; authority?: string; path?: string; query?: string; fragment?: string }): URI {
|
||||
return new Uri(
|
||||
const result = new Uri(
|
||||
components.scheme,
|
||||
components.authority,
|
||||
components.path,
|
||||
components.query,
|
||||
components.fragment,
|
||||
);
|
||||
_validateUri(result, true);
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -49,6 +49,10 @@ body {
|
|||
width: 90px;
|
||||
}
|
||||
|
||||
.monaco-list:focus {
|
||||
outline: 0;
|
||||
}
|
||||
|
||||
.monaco-list-row:first-of-type {
|
||||
border-bottom: 1px solid;
|
||||
}
|
||||
|
|
|
@ -14,13 +14,15 @@ import { applyZoom, zoomIn, zoomOut } from 'vs/platform/windows/electron-sandbox
|
|||
import { IContextMenuItem } from 'vs/base/parts/contextmenu/common/contextmenu';
|
||||
import { popup } from 'vs/base/parts/contextmenu/electron-sandbox/contextmenu';
|
||||
import { ProcessItem } from 'vs/base/common/processes';
|
||||
import { append, $ } from 'vs/base/browser/dom';
|
||||
import { append, $, createStyleSheet } from 'vs/base/browser/dom';
|
||||
import { isRemoteDiagnosticError, IRemoteDiagnosticError } from 'vs/platform/diagnostics/common/diagnostics';
|
||||
import { ElectronIPCMainProcessService } from 'vs/platform/ipc/electron-sandbox/mainProcessService';
|
||||
import { ByteSize } from 'vs/platform/files/common/files';
|
||||
import { IListVirtualDelegate } from 'vs/base/browser/ui/list/list';
|
||||
import { IDataSource, ITreeNode, ITreeRenderer } from 'vs/base/browser/ui/tree/tree';
|
||||
import { DataTree } from 'vs/base/browser/ui/tree/dataTree';
|
||||
import { getIconsStyleSheet } from 'vs/platform/theme/browser/iconsStyleSheet';
|
||||
import { RunOnceScheduler } from 'vs/base/common/async';
|
||||
|
||||
const DEBUG_FLAGS_PATTERN = /\s--(inspect|debug)(-brk|port)?=(\d+)?/;
|
||||
const DEBUG_PORT_PATTERN = /\s--(inspect|debug)-port=(\d+)/;
|
||||
|
@ -310,8 +312,7 @@ class ProcessExplorer {
|
|||
renderers,
|
||||
new ProcessTreeDataSource(),
|
||||
{
|
||||
identityProvider:
|
||||
{
|
||||
identityProvider: {
|
||||
getId: (element: ProcessTree | ProcessItem | MachineProcessInformation | ProcessInformation | IRemoteDiagnosticError) => {
|
||||
if (isProcessItem(element)) {
|
||||
return element.pid.toString();
|
||||
|
@ -331,7 +332,7 @@ class ProcessExplorer {
|
|||
|
||||
return 'header';
|
||||
}
|
||||
}
|
||||
},
|
||||
});
|
||||
|
||||
this.tree.setInput({ processes: { processRoots } });
|
||||
|
@ -378,21 +379,45 @@ class ProcessExplorer {
|
|||
}
|
||||
|
||||
private applyStyles(styles: ProcessExplorerStyles): void {
|
||||
const styleTag = document.createElement('style');
|
||||
const styleElement = createStyleSheet();
|
||||
const content: string[] = [];
|
||||
|
||||
if (styles.hoverBackground) {
|
||||
content.push(`.monaco-list-row:hover { background-color: ${styles.hoverBackground}; }`);
|
||||
if (styles.listFocusBackground) {
|
||||
content.push(`.monaco-list:focus .monaco-list-row.focused { background-color: ${styles.listFocusBackground}; }`);
|
||||
content.push(`.monaco-list:focus .monaco-list-row.focused:hover { background-color: ${styles.listFocusBackground}; }`);
|
||||
}
|
||||
|
||||
if (styles.hoverForeground) {
|
||||
content.push(`.monaco-list-row:hover { color: ${styles.hoverForeground}; }`);
|
||||
if (styles.listFocusForeground) {
|
||||
content.push(`.monaco-list:focus .monaco-list-row.focused { color: ${styles.listFocusForeground}; }`);
|
||||
}
|
||||
|
||||
styleTag.textContent = content.join('\n');
|
||||
if (document.head) {
|
||||
document.head.appendChild(styleTag);
|
||||
if (styles.listActiveSelectionBackground) {
|
||||
content.push(`.monaco-list:focus .monaco-list-row.selected { background-color: ${styles.listActiveSelectionBackground}; }`);
|
||||
content.push(`.monaco-list:focus .monaco-list-row.selected:hover { background-color: ${styles.listActiveSelectionBackground}; }`);
|
||||
}
|
||||
|
||||
if (styles.listActiveSelectionForeground) {
|
||||
content.push(`.monaco-list:focus .monaco-list-row.selected { color: ${styles.listActiveSelectionForeground}; }`);
|
||||
}
|
||||
|
||||
if (styles.listHoverBackground) {
|
||||
content.push(`.monaco-list-row:hover:not(.selected):not(.focused) { background-color: ${styles.listHoverBackground}; }`);
|
||||
}
|
||||
|
||||
if (styles.listHoverForeground) {
|
||||
content.push(`.monaco-list-row:hover:not(.selected):not(.focused) { color: ${styles.listHoverForeground}; }`);
|
||||
}
|
||||
|
||||
if (styles.listFocusOutline) {
|
||||
content.push(`.monaco-list:focus .monaco-list-row.focused { outline: 1px solid ${styles.listFocusOutline}; outline-offset: -1px; }`);
|
||||
}
|
||||
|
||||
if (styles.listHoverOutline) {
|
||||
content.push(`.monaco-list-row:hover { outline: 1px dashed ${styles.listHoverOutline}; outline-offset: -1px; }`);
|
||||
}
|
||||
|
||||
styleElement.textContent = content.join('\n');
|
||||
|
||||
if (styles.color) {
|
||||
document.body.style.color = styles.color;
|
||||
}
|
||||
|
@ -475,9 +500,24 @@ class ProcessExplorer {
|
|||
}
|
||||
}
|
||||
|
||||
function createCodiconStyleSheet() {
|
||||
const codiconStyleSheet = createStyleSheet();
|
||||
codiconStyleSheet.id = 'codiconStyles';
|
||||
|
||||
const iconsStyleSheet = getIconsStyleSheet();
|
||||
function updateAll() {
|
||||
codiconStyleSheet.textContent = iconsStyleSheet.getCSS();
|
||||
}
|
||||
|
||||
const delayer = new RunOnceScheduler(updateAll, 0);
|
||||
iconsStyleSheet.onDidChange(() => delayer.schedule());
|
||||
delayer.schedule();
|
||||
}
|
||||
|
||||
export function startup(configuration: ProcessExplorerWindowConfiguration): void {
|
||||
const platformClass = configuration.data.platform === 'win32' ? 'windows' : configuration.data.platform === 'linux' ? 'linux' : 'mac';
|
||||
document.body.classList.add(platformClass); // used by our fonts
|
||||
createCodiconStyleSheet();
|
||||
applyZoom(configuration.data.zoomLevel);
|
||||
|
||||
new ProcessExplorer(configuration.windowId, configuration.data);
|
||||
|
|
|
@ -222,6 +222,11 @@ export interface ICursorSimpleModel {
|
|||
getLineFirstNonWhitespaceColumn(lineNumber: number): number;
|
||||
getLineLastNonWhitespaceColumn(lineNumber: number): number;
|
||||
normalizePosition(position: Position, affinity: PositionNormalizationAffinity): Position;
|
||||
/**
|
||||
* Gets the column at which indentation stops at a given line.
|
||||
* @internal
|
||||
*/
|
||||
getLineIndentColumn(lineNumber: number): number;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -38,13 +38,15 @@ export class MoveOperations {
|
|||
}
|
||||
|
||||
private static leftPositionAtomicSoftTabs(model: ICursorSimpleModel, position: Position, tabSize: number): Position {
|
||||
const minColumn = model.getLineMinColumn(position.lineNumber);
|
||||
const lineContent = model.getLineContent(position.lineNumber);
|
||||
const newPosition = AtomicTabMoveOperations.atomicPosition(lineContent, position.column - 1, tabSize, Direction.Left);
|
||||
if (newPosition === -1 || newPosition + 1 < minColumn) {
|
||||
return this.leftPosition(model, position);
|
||||
if (position.column <= model.getLineIndentColumn(position.lineNumber)) {
|
||||
const minColumn = model.getLineMinColumn(position.lineNumber);
|
||||
const lineContent = model.getLineContent(position.lineNumber);
|
||||
const newPosition = AtomicTabMoveOperations.atomicPosition(lineContent, position.column - 1, tabSize, Direction.Left);
|
||||
if (newPosition !== -1 && newPosition + 1 >= minColumn) {
|
||||
return new Position(position.lineNumber, newPosition + 1);
|
||||
}
|
||||
}
|
||||
return new Position(position.lineNumber, newPosition + 1);
|
||||
return this.leftPosition(model, position);
|
||||
}
|
||||
|
||||
private static left(config: CursorConfiguration, model: ICursorSimpleModel, position: Position): CursorPosition {
|
||||
|
@ -115,12 +117,14 @@ export class MoveOperations {
|
|||
}
|
||||
|
||||
public static rightPositionAtomicSoftTabs(model: ICursorSimpleModel, lineNumber: number, column: number, tabSize: number, indentSize: number): Position {
|
||||
const lineContent = model.getLineContent(lineNumber);
|
||||
const newPosition = AtomicTabMoveOperations.atomicPosition(lineContent, column - 1, tabSize, Direction.Right);
|
||||
if (newPosition === -1) {
|
||||
return this.rightPosition(model, lineNumber, column);
|
||||
if (column < model.getLineIndentColumn(lineNumber)) {
|
||||
const lineContent = model.getLineContent(lineNumber);
|
||||
const newPosition = AtomicTabMoveOperations.atomicPosition(lineContent, column - 1, tabSize, Direction.Right);
|
||||
if (newPosition !== -1) {
|
||||
return new Position(lineNumber, newPosition + 1);
|
||||
}
|
||||
}
|
||||
return new Position(lineNumber, newPosition + 1);
|
||||
return this.rightPosition(model, lineNumber, column);
|
||||
}
|
||||
|
||||
public static right(config: CursorConfiguration, model: ICursorSimpleModel, position: Position): CursorPosition {
|
||||
|
|
|
@ -1261,6 +1261,12 @@ export interface ITextModel {
|
|||
* @internal
|
||||
*/
|
||||
normalizePosition(position: Position, affinity: PositionNormalizationAffinity): Position;
|
||||
|
||||
/**
|
||||
* Gets the column at which indentation stops at a given line.
|
||||
* @internal
|
||||
*/
|
||||
getLineIndentColumn(lineNumber: number): number;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -3031,6 +3031,27 @@ export class TextModel extends Disposable implements model.ITextModel {
|
|||
normalizePosition(position: Position, affinity: model.PositionNormalizationAffinity): Position {
|
||||
return position;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the column at which indentation stops at a given line.
|
||||
* @internal
|
||||
*/
|
||||
public getLineIndentColumn(lineNumber: number): number {
|
||||
// Columns start with 1.
|
||||
return indentOfLine(this.getLineContent(lineNumber)) + 1;
|
||||
}
|
||||
}
|
||||
|
||||
function indentOfLine(line: string): number {
|
||||
let indent = 0;
|
||||
for (const c of line) {
|
||||
if (c === ' ' || c === '\t') {
|
||||
indent++;
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
return indent;
|
||||
}
|
||||
|
||||
//#region Decorations
|
||||
|
|
|
@ -47,6 +47,10 @@ class LinePart {
|
|||
public isWhitespace(): boolean {
|
||||
return (this.metadata & LinePartMetadata.IS_WHITESPACE_MASK ? true : false);
|
||||
}
|
||||
|
||||
public isPseudoAfter(): boolean {
|
||||
return (this.metadata & LinePartMetadata.PSEUDO_AFTER_MASK ? true : false);
|
||||
}
|
||||
}
|
||||
|
||||
export class LineRange {
|
||||
|
@ -792,14 +796,11 @@ function _applyInlineDecorations(lineContent: string, len: number, tokens: LineP
|
|||
|
||||
const lastTokenEndIndex = tokens[tokens.length - 1].endIndex;
|
||||
if (lineDecorationIndex < lineDecorationsLen && lineDecorations[lineDecorationIndex].startOffset === lastTokenEndIndex) {
|
||||
let classNames: string[] = [];
|
||||
let metadata = 0;
|
||||
while (lineDecorationIndex < lineDecorationsLen && lineDecorations[lineDecorationIndex].startOffset === lastTokenEndIndex) {
|
||||
classNames.push(lineDecorations[lineDecorationIndex].className);
|
||||
metadata |= lineDecorations[lineDecorationIndex].metadata;
|
||||
const lineDecoration = lineDecorations[lineDecorationIndex];
|
||||
result[resultLen++] = new LinePart(lastResultEndIndex, lineDecoration.className, lineDecoration.metadata);
|
||||
lineDecorationIndex++;
|
||||
}
|
||||
result[resultLen++] = new LinePart(lastResultEndIndex, classNames.join(' '), metadata);
|
||||
}
|
||||
|
||||
return result;
|
||||
|
@ -827,6 +828,7 @@ function _renderLine(input: ResolvedRenderLineInput, sb: IStringBuilder): Render
|
|||
const renderControlCharacters = input.renderControlCharacters;
|
||||
|
||||
const characterMapping = new CharacterMapping(len + 1, parts.length);
|
||||
let lastCharacterMappingDefined = false;
|
||||
|
||||
let charIndex = 0;
|
||||
let visibleColumn = startVisibleColumn;
|
||||
|
@ -999,13 +1001,20 @@ function _renderLine(input: ResolvedRenderLineInput, sb: IStringBuilder): Render
|
|||
partDisplacement = 0;
|
||||
}
|
||||
|
||||
if (charIndex >= len && !lastCharacterMappingDefined && part.isPseudoAfter()) {
|
||||
lastCharacterMappingDefined = true;
|
||||
characterMapping.setPartData(charIndex, partIndex, charOffsetInPart, partAbsoluteOffset);
|
||||
}
|
||||
|
||||
sb.appendASCIIString('</span>');
|
||||
|
||||
}
|
||||
|
||||
// When getting client rects for the last character, we will position the
|
||||
// text range at the end of the span, insteaf of at the beginning of next span
|
||||
characterMapping.setPartData(len, parts.length - 1, charOffsetInPart, partAbsoluteOffset);
|
||||
if (!lastCharacterMappingDefined) {
|
||||
// When getting client rects for the last character, we will position the
|
||||
// text range at the end of the span, insteaf of at the beginning of next span
|
||||
characterMapping.setPartData(len, parts.length - 1, charOffsetInPart, partAbsoluteOffset);
|
||||
}
|
||||
|
||||
if (isOverflowing) {
|
||||
sb.appendASCIIString('<span>…</span>');
|
||||
|
|
|
@ -78,6 +78,11 @@ export interface IViewModelLinesCollection extends IDisposable {
|
|||
getDecorationsInRange(range: Range, ownerId: number, filterOutValidation: boolean): IModelDecoration[];
|
||||
|
||||
normalizePosition(position: Position, affinity: PositionNormalizationAffinity): Position;
|
||||
/**
|
||||
* Gets the column at which indentation stops at a given line.
|
||||
* @internal
|
||||
*/
|
||||
getLineIndentColumn(lineNumber: number): number;
|
||||
}
|
||||
|
||||
export class CoordinatesConverter implements ICoordinatesConverter {
|
||||
|
@ -983,6 +988,22 @@ export class SplitLinesCollection implements IViewModelLinesCollection {
|
|||
|
||||
return this.lines[lineIndex].normalizePosition(this.model, lineIndex + 1, remainder, position, affinity);
|
||||
}
|
||||
|
||||
public getLineIndentColumn(lineNumber: number): number {
|
||||
const viewLineNumber = this._toValidViewLineNumber(lineNumber);
|
||||
const r = this.prefixSumComputer.getIndexOf(viewLineNumber - 1);
|
||||
const lineIndex = r.index;
|
||||
const remainder = r.remainder;
|
||||
|
||||
if (remainder === 0) {
|
||||
return this.model.getLineIndentColumn(lineIndex + 1);
|
||||
}
|
||||
|
||||
// wrapped lines have no indentation.
|
||||
// We deliberately don't handle the case that indentation is wrapped
|
||||
// to avoid two view lines reporting indentation for the very same model line.
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
class VisibleIdentitySplitLine implements ISplitLine {
|
||||
|
@ -1575,6 +1596,10 @@ export class IdentityLinesCollection implements IViewModelLinesCollection {
|
|||
normalizePosition(position: Position, affinity: PositionNormalizationAffinity): Position {
|
||||
return this.model.normalizePosition(position, affinity);
|
||||
}
|
||||
|
||||
public getLineIndentColumn(lineNumber: number): number {
|
||||
return this.model.getLineIndentColumn(lineNumber);
|
||||
}
|
||||
}
|
||||
|
||||
class OverviewRulerDecorations {
|
||||
|
|
|
@ -1041,4 +1041,12 @@ export class ViewModel extends Disposable implements IViewModel {
|
|||
normalizePosition(position: Position, affinity: PositionNormalizationAffinity): Position {
|
||||
return this._lines.normalizePosition(position, affinity);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the column at which indentation stops at a given line.
|
||||
* @internal
|
||||
*/
|
||||
getLineIndentColumn(lineNumber: number): number {
|
||||
return this._lines.getLineIndentColumn(lineNumber);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -2760,6 +2760,34 @@ suite('Editor Controller - Regression tests', () => {
|
|||
}
|
||||
);
|
||||
});
|
||||
|
||||
test('issue #123178: sticky tab in consecutive wrapped lines', () => {
|
||||
const model = createTextModel(' aaaa aaaa', { tabSize: 4 });
|
||||
|
||||
withTestCodeEditor(
|
||||
null,
|
||||
{
|
||||
model: model,
|
||||
wordWrap: 'wordWrapColumn',
|
||||
wordWrapColumn: 8,
|
||||
stickyTabStops: true,
|
||||
},
|
||||
(editor, viewModel) => {
|
||||
viewModel.setSelections('test', [
|
||||
new Selection(1, 9, 1, 9)
|
||||
]);
|
||||
moveRight(editor, viewModel, false);
|
||||
assertCursor(viewModel, [
|
||||
new Selection(1, 10, 1, 10),
|
||||
]);
|
||||
|
||||
moveLeft(editor, viewModel, false);
|
||||
assertCursor(viewModel, [
|
||||
new Selection(1, 9, 1, 9),
|
||||
]);
|
||||
}
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
suite('Editor Controller - Cursor Configuration', () => {
|
||||
|
|
|
@ -809,64 +809,64 @@ suite('viewLineRenderer.renderLine', () => {
|
|||
const _expected = decodeCharacterMapping(expected);
|
||||
assert.deepStrictEqual(_actual, _expected);
|
||||
}
|
||||
|
||||
function assertCharacterMapping(actual: CharacterMapping, expectedCharPartOffsets: number[][], expectedPartLengths: number[]): void {
|
||||
|
||||
assertCharPartOffsets(actual, expectedCharPartOffsets);
|
||||
|
||||
let expectedCharAbsoluteOffset: number[] = [], currentPartAbsoluteOffset = 0;
|
||||
for (let partIndex = 0; partIndex < expectedCharPartOffsets.length; partIndex++) {
|
||||
const part = expectedCharPartOffsets[partIndex];
|
||||
|
||||
for (const charIndex of part) {
|
||||
expectedCharAbsoluteOffset.push(currentPartAbsoluteOffset + charIndex);
|
||||
}
|
||||
|
||||
currentPartAbsoluteOffset += expectedPartLengths[partIndex];
|
||||
}
|
||||
|
||||
let actualCharOffset: number[] = [];
|
||||
let tmp = actual.getAbsoluteOffsets();
|
||||
for (let i = 0; i < tmp.length; i++) {
|
||||
actualCharOffset[i] = tmp[i];
|
||||
}
|
||||
assert.deepStrictEqual(actualCharOffset, expectedCharAbsoluteOffset);
|
||||
}
|
||||
|
||||
function assertCharPartOffsets(actual: CharacterMapping, expected: number[][]): void {
|
||||
|
||||
let charOffset = 0;
|
||||
for (let partIndex = 0; partIndex < expected.length; partIndex++) {
|
||||
let part = expected[partIndex];
|
||||
for (const charIndex of part) {
|
||||
// here
|
||||
let _actualPartData = actual.charOffsetToPartData(charOffset);
|
||||
let actualPartIndex = CharacterMapping.getPartIndex(_actualPartData);
|
||||
let actualCharIndex = CharacterMapping.getCharIndex(_actualPartData);
|
||||
|
||||
assert.deepStrictEqual(
|
||||
{ partIndex: actualPartIndex, charIndex: actualCharIndex },
|
||||
{ partIndex: partIndex, charIndex: charIndex },
|
||||
`character mapping for offset ${charOffset}`
|
||||
);
|
||||
|
||||
// here
|
||||
let actualOffset = actual.partDataToCharOffset(partIndex, part[part.length - 1] + 1, charIndex);
|
||||
|
||||
assert.strictEqual(
|
||||
actualOffset,
|
||||
charOffset,
|
||||
`character mapping for part ${partIndex}, ${charIndex}`
|
||||
);
|
||||
|
||||
charOffset++;
|
||||
}
|
||||
}
|
||||
|
||||
assert.strictEqual(actual.length, charOffset);
|
||||
}
|
||||
});
|
||||
|
||||
function assertCharacterMapping(actual: CharacterMapping, expectedCharPartOffsets: number[][], expectedPartLengths: number[]): void {
|
||||
|
||||
assertCharPartOffsets(actual, expectedCharPartOffsets);
|
||||
|
||||
let expectedCharAbsoluteOffset: number[] = [], currentPartAbsoluteOffset = 0;
|
||||
for (let partIndex = 0; partIndex < expectedCharPartOffsets.length; partIndex++) {
|
||||
const part = expectedCharPartOffsets[partIndex];
|
||||
|
||||
for (const charIndex of part) {
|
||||
expectedCharAbsoluteOffset.push(currentPartAbsoluteOffset + charIndex);
|
||||
}
|
||||
|
||||
currentPartAbsoluteOffset += expectedPartLengths[partIndex];
|
||||
}
|
||||
|
||||
let actualCharOffset: number[] = [];
|
||||
let tmp = actual.getAbsoluteOffsets();
|
||||
for (let i = 0; i < tmp.length; i++) {
|
||||
actualCharOffset[i] = tmp[i];
|
||||
}
|
||||
assert.deepStrictEqual(actualCharOffset, expectedCharAbsoluteOffset);
|
||||
}
|
||||
|
||||
function assertCharPartOffsets(actual: CharacterMapping, expected: number[][]): void {
|
||||
|
||||
let charOffset = 0;
|
||||
for (let partIndex = 0; partIndex < expected.length; partIndex++) {
|
||||
let part = expected[partIndex];
|
||||
for (const charIndex of part) {
|
||||
// here
|
||||
let _actualPartData = actual.charOffsetToPartData(charOffset);
|
||||
let actualPartIndex = CharacterMapping.getPartIndex(_actualPartData);
|
||||
let actualCharIndex = CharacterMapping.getCharIndex(_actualPartData);
|
||||
|
||||
assert.deepStrictEqual(
|
||||
{ partIndex: actualPartIndex, charIndex: actualCharIndex },
|
||||
{ partIndex: partIndex, charIndex: charIndex },
|
||||
`character mapping for offset ${charOffset}`
|
||||
);
|
||||
|
||||
// here
|
||||
let actualOffset = actual.partDataToCharOffset(partIndex, part[part.length - 1] + 1, charIndex);
|
||||
|
||||
assert.strictEqual(
|
||||
actualOffset,
|
||||
charOffset,
|
||||
`character mapping for part ${partIndex}, ${charIndex}`
|
||||
);
|
||||
|
||||
charOffset++;
|
||||
}
|
||||
}
|
||||
|
||||
assert.strictEqual(actual.length, charOffset);
|
||||
}
|
||||
|
||||
suite('viewLineRenderer.renderLine 2', () => {
|
||||
|
||||
function testCreateLineParts(fontIsMonospace: boolean, lineContent: string, tokens: ViewLineToken[], fauxIndentLength: number, renderWhitespace: 'none' | 'boundary' | 'selection' | 'trailing' | 'all', selections: LineRange[] | null, expected: string): void {
|
||||
|
@ -1739,7 +1739,7 @@ suite('viewLineRenderer.renderLine 2', () => {
|
|||
let expected = [
|
||||
'<span>',
|
||||
'<span class="mtk3">\u00a0\u00a0\u00a0\u00a0}</span>',
|
||||
'<span class="ced-TextEditorDecorationType2-5e9b9b3f-3 ced-TextEditorDecorationType2-3 ced-TextEditorDecorationType2-5e9b9b3f-4 ced-TextEditorDecorationType2-4"></span>',
|
||||
'<span class="ced-TextEditorDecorationType2-5e9b9b3f-3 ced-TextEditorDecorationType2-3"></span><span class="ced-TextEditorDecorationType2-5e9b9b3f-4 ced-TextEditorDecorationType2-4"></span>',
|
||||
'</span>'
|
||||
].join('');
|
||||
|
||||
|
@ -2138,6 +2138,52 @@ suite('viewLineRenderer.renderLine 2', () => {
|
|||
assert.deepStrictEqual(actual.html, expected);
|
||||
});
|
||||
|
||||
test('issue #124038: Multiple end-of-line text decorations get merged', () => {
|
||||
const actual = renderViewLine(new RenderLineInput(
|
||||
true,
|
||||
false,
|
||||
' if',
|
||||
false,
|
||||
true,
|
||||
false,
|
||||
0,
|
||||
createViewLineTokens([createPart(4, 1), createPart(6, 2)]),
|
||||
[
|
||||
new LineDecoration(7, 7, 'ced-1-TextEditorDecorationType2-17c14d98-3 ced-1-TextEditorDecorationType2-3', InlineDecorationType.Before),
|
||||
new LineDecoration(7, 7, 'ced-1-TextEditorDecorationType2-17c14d98-4 ced-1-TextEditorDecorationType2-4', InlineDecorationType.After),
|
||||
new LineDecoration(7, 7, 'ced-ghost-text-1-4', InlineDecorationType.After),
|
||||
],
|
||||
4,
|
||||
0,
|
||||
10,
|
||||
10,
|
||||
10,
|
||||
10000,
|
||||
'all',
|
||||
false,
|
||||
false,
|
||||
null
|
||||
));
|
||||
|
||||
const expected = [
|
||||
'<span>',
|
||||
'<span class="mtkw">····</span><span class="mtk2">if</span><span class="ced-1-TextEditorDecorationType2-17c14d98-3 ced-1-TextEditorDecorationType2-3"></span><span class="ced-1-TextEditorDecorationType2-17c14d98-4 ced-1-TextEditorDecorationType2-4"></span><span class="ced-ghost-text-1-4"></span>',
|
||||
'</span>'
|
||||
].join('');
|
||||
|
||||
assert.deepStrictEqual(actual.html, expected);
|
||||
assertCharacterMapping(actual.characterMapping,
|
||||
[
|
||||
[0, 1, 2, 3],
|
||||
[0, 1],
|
||||
[],
|
||||
[0],
|
||||
[],
|
||||
],
|
||||
[4, 2, 0, 0]
|
||||
);
|
||||
});
|
||||
|
||||
|
||||
function createTestGetColumnOfLinePartOffset(lineContent: string, tabSize: number, parts: ViewLineToken[], expectedPartLengths: number[]): (partIndex: number, partLength: number, offset: number, expected: number) => void {
|
||||
let renderLineOutput = renderViewLine(new RenderLineInput(
|
||||
|
|
|
@ -129,6 +129,7 @@ export class MenuId {
|
|||
static readonly TouchBarContext = new MenuId('TouchBarContext');
|
||||
static readonly TitleBarContext = new MenuId('TitleBarContext');
|
||||
static readonly TunnelContext = new MenuId('TunnelContext');
|
||||
static readonly TunnelProtocol = new MenuId('TunnelProtocol');
|
||||
static readonly TunnelPortInline = new MenuId('TunnelInline');
|
||||
static readonly TunnelTitle = new MenuId('TunnelTitle');
|
||||
static readonly TunnelLocalAddressInline = new MenuId('TunnelLocalAddressInline');
|
||||
|
@ -143,6 +144,7 @@ export class MenuId {
|
|||
static readonly CommentTitle = new MenuId('CommentTitle');
|
||||
static readonly CommentActions = new MenuId('CommentActions');
|
||||
static readonly NotebookToolbar = new MenuId('NotebookToolbar');
|
||||
static readonly NotebookRightToolbar = new MenuId('NotebookRightToolbar');
|
||||
static readonly NotebookCellTitle = new MenuId('NotebookCellTitle');
|
||||
static readonly NotebookCellInsert = new MenuId('NotebookCellInsert');
|
||||
static readonly NotebookCellBetween = new MenuId('NotebookCellBetween');
|
||||
|
|
|
@ -10,8 +10,23 @@ export class TestDialogService implements IDialogService {
|
|||
|
||||
declare readonly _serviceBrand: undefined;
|
||||
|
||||
confirm(_confirmation: IConfirmation): Promise<IConfirmationResult> { return Promise.resolve({ confirmed: false }); }
|
||||
show(_severity: Severity, _message: string, _buttons: string[], _options?: IDialogOptions): Promise<IShowResult> { return Promise.resolve({ choice: 0 }); }
|
||||
input(): Promise<IInputResult> { { return Promise.resolve({ choice: 0, values: [] }); } }
|
||||
about(): Promise<void> { return Promise.resolve(); }
|
||||
private confirmResult: IConfirmationResult | undefined = undefined;
|
||||
setConfirmResult(result: IConfirmationResult) {
|
||||
this.confirmResult = result;
|
||||
}
|
||||
|
||||
async confirm(confirmation: IConfirmation): Promise<IConfirmationResult> {
|
||||
if (this.confirmResult) {
|
||||
const confirmResult = this.confirmResult;
|
||||
this.confirmResult = undefined;
|
||||
|
||||
return confirmResult;
|
||||
}
|
||||
|
||||
return { confirmed: false };
|
||||
}
|
||||
|
||||
async show(severity: Severity, message: string, buttons: string[], options?: IDialogOptions): Promise<IShowResult> { return { choice: 0 }; }
|
||||
async input(): Promise<IInputResult> { { return { choice: 0, values: [] }; } }
|
||||
async about(): Promise<void> { }
|
||||
}
|
||||
|
|
|
@ -63,13 +63,13 @@ export const OPTIONS: OptionDescriptions<Required<NativeParsedArgs>> = {
|
|||
'verbose': { type: 'boolean', cat: 't', description: localize('verbose', "Print verbose output (implies --wait).") },
|
||||
'log': { type: 'string', cat: 't', args: 'level', description: localize('log', "Log level to use. Default is 'info'. Allowed values are 'critical', 'error', 'warn', 'info', 'debug', 'trace', 'off'.") },
|
||||
'status': { type: 'boolean', alias: 's', cat: 't', description: localize('status', "Print process usage and diagnostics information.") },
|
||||
'prof-startup': { type: 'boolean', cat: 't', description: localize('prof-startup', "Run CPU profiler during startup") },
|
||||
'prof-startup': { type: 'boolean', cat: 't', description: localize('prof-startup', "Run CPU profiler during startup.") },
|
||||
'prof-append-timers': { type: 'string' },
|
||||
'prof-startup-prefix': { type: 'string' },
|
||||
'prof-v8-extensions': { type: 'boolean' },
|
||||
'disable-extensions': { type: 'boolean', deprecates: 'disableExtensions', cat: 't', description: localize('disableExtensions', "Disable all installed extensions.") },
|
||||
'disable-extension': { type: 'string[]', cat: 't', args: 'extension-id', description: localize('disableExtension', "Disable an extension.") },
|
||||
'sync': { type: 'string', cat: 't', description: localize('turn sync', "Turn sync on or off"), args: ['on', 'off'] },
|
||||
'sync': { type: 'string', cat: 't', description: localize('turn sync', "Turn sync on or off."), args: ['on', 'off'] },
|
||||
|
||||
'inspect-extensions': { type: 'string', deprecates: 'debugPluginHost', args: 'port', cat: 't', description: localize('inspect-extensions', "Allow debugging and profiling of extensions. Check the developer tools for the connection URI.") },
|
||||
'inspect-brk-extensions': { type: 'string', deprecates: 'debugBrkPluginHost', args: 'port', cat: 't', description: localize('inspect-brk-extensions', "Allow debugging and profiling of extensions with the extension host being paused after start. Check the developer tools for the connection URI.") },
|
||||
|
|
|
@ -70,8 +70,14 @@ export interface ISettingSearchResult {
|
|||
}
|
||||
|
||||
export interface ProcessExplorerStyles extends WindowStyles {
|
||||
hoverBackground?: string;
|
||||
hoverForeground?: string;
|
||||
listHoverBackground?: string;
|
||||
listHoverForeground?: string;
|
||||
listFocusBackground?: string;
|
||||
listFocusForeground?: string;
|
||||
listFocusOutline?: string;
|
||||
listActiveSelectionBackground?: string;
|
||||
listActiveSelectionForeground?: string;
|
||||
listHoverOutline?: string;
|
||||
}
|
||||
|
||||
export interface ProcessExplorerData extends WindowData {
|
||||
|
|
|
@ -38,6 +38,7 @@ function log(logger: spdlog.Logger, level: LogLevel, message: string): void {
|
|||
case LogLevel.Critical: logger.critical(message); break;
|
||||
default: throw new Error('Invalid log level');
|
||||
}
|
||||
logger.flush();
|
||||
}
|
||||
|
||||
export class SpdLogLogger extends AbstractMessageLogger implements ILogger {
|
||||
|
|
|
@ -129,6 +129,10 @@ export interface ICommonNativeHostService {
|
|||
toggleWindowTabsBar(): Promise<void>;
|
||||
updateTouchBar(items: ISerializableCommandAction[][]): Promise<void>;
|
||||
|
||||
// macOS Shell command
|
||||
installShellCommand(): Promise<void>;
|
||||
uninstallShellCommand(): Promise<void>;
|
||||
|
||||
// Lifecycle
|
||||
notifyReady(): Promise<void>
|
||||
relaunch(options?: { addArgs?: string[], removeArgs?: string[] }): Promise<void>;
|
||||
|
|
|
@ -3,6 +3,11 @@
|
|||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import * as fs from 'fs';
|
||||
import { exec } from 'child_process';
|
||||
import { promisify } from 'util';
|
||||
import { localize } from 'vs/nls';
|
||||
import { realpath } from 'vs/base/node/extpath';
|
||||
import { Emitter, Event } from 'vs/base/common/event';
|
||||
import { IWindowsMainService, ICodeWindow, OpenContext } from 'vs/platform/windows/electron-main/windows';
|
||||
import { MessageBoxOptions, MessageBoxReturnValue, shell, OpenDevToolsOptions, SaveDialogOptions, SaveDialogReturnValue, OpenDialogOptions, OpenDialogReturnValue, Menu, BrowserWindow, app, clipboard, powerMonitor, nativeTheme, screen, Display } from 'electron';
|
||||
|
@ -15,7 +20,7 @@ import { ISerializableCommandAction } from 'vs/platform/actions/common/actions';
|
|||
import { IEnvironmentMainService } from 'vs/platform/environment/electron-main/environmentMainService';
|
||||
import { AddFirstParameterToFunctions } from 'vs/base/common/types';
|
||||
import { IDialogMainService } from 'vs/platform/dialogs/electron-main/dialogMainService';
|
||||
import { SymlinkSupport } from 'vs/base/node/pfs';
|
||||
import { exists, SymlinkSupport } from 'vs/base/node/pfs';
|
||||
import { URI } from 'vs/base/common/uri';
|
||||
import { ITelemetryData, ITelemetryService } from 'vs/platform/telemetry/common/telemetry';
|
||||
import { createDecorator } from 'vs/platform/instantiation/common/instantiation';
|
||||
|
@ -23,7 +28,7 @@ import { MouseInputEvent } from 'vs/base/parts/sandbox/common/electronTypes';
|
|||
import { arch, totalmem, release, platform, type, loadavg, freemem, cpus } from 'os';
|
||||
import { virtualMachineHint } from 'vs/base/node/id';
|
||||
import { ILogService } from 'vs/platform/log/common/log';
|
||||
import { dirname, join } from 'vs/base/common/path';
|
||||
import { dirname, join, resolve } from 'vs/base/common/path';
|
||||
import { IProductService } from 'vs/platform/product/common/productService';
|
||||
import { memoize } from 'vs/base/common/decorators';
|
||||
import { Disposable } from 'vs/base/common/lifecycle';
|
||||
|
@ -256,6 +261,99 @@ export class NativeHostMainService extends Disposable implements INativeHostMain
|
|||
//#endregion
|
||||
|
||||
|
||||
//#region macOS Shell Command
|
||||
|
||||
async installShellCommand(windowId: number | undefined): Promise<void> {
|
||||
const { source, target } = await this.getShellCommandLink();
|
||||
|
||||
// Only install unless already existing
|
||||
try {
|
||||
const { symbolicLink } = await SymlinkSupport.stat(source);
|
||||
if (symbolicLink && !symbolicLink.dangling) {
|
||||
const linkTargetRealPath = await realpath(source);
|
||||
if (target === linkTargetRealPath) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// Different source, delete it first
|
||||
await fs.promises.unlink(source);
|
||||
} catch (error) {
|
||||
if (error.code !== 'ENOENT') {
|
||||
throw error; // throw on any error but file not found
|
||||
}
|
||||
}
|
||||
|
||||
try {
|
||||
await fs.promises.symlink(target, source);
|
||||
} catch (error) {
|
||||
if (error.code !== 'EACCES' && error.code !== 'ENOENT') {
|
||||
throw error;
|
||||
}
|
||||
|
||||
const { response } = await this.showMessageBox(windowId, {
|
||||
type: 'info',
|
||||
message: localize('warnEscalation', "{0} will now prompt with 'osascript' for Administrator privileges to install the shell command.", this.productService.nameShort),
|
||||
buttons: [localize('ok', "OK"), localize('cancel', "Cancel")],
|
||||
cancelId: 1
|
||||
});
|
||||
|
||||
if (response === 0 /* OK */) {
|
||||
try {
|
||||
const command = `osascript -e "do shell script \\"mkdir -p /usr/local/bin && ln -sf \'${target}\' \'${source}\'\\" with administrator privileges"`;
|
||||
await promisify(exec)(command);
|
||||
} catch (error) {
|
||||
throw new Error(localize('cantCreateBinFolder', "Unable to install the shell command '{0}'.", source));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
async uninstallShellCommand(windowId: number | undefined): Promise<void> {
|
||||
const { source } = await this.getShellCommandLink();
|
||||
|
||||
try {
|
||||
await fs.promises.unlink(source);
|
||||
} catch (error) {
|
||||
switch (error.code) {
|
||||
case 'EACCES':
|
||||
const { response } = await this.showMessageBox(windowId, {
|
||||
type: 'info',
|
||||
message: localize('warnEscalationUninstall', "{0} will now prompt with 'osascript' for Administrator privileges to uninstall the shell command.", this.productService.nameShort),
|
||||
buttons: [localize('ok', "OK"), localize('cancel', "Cancel")],
|
||||
cancelId: 1
|
||||
});
|
||||
|
||||
if (response === 0 /* OK */) {
|
||||
try {
|
||||
const command = `osascript -e "do shell script \\"rm \'${source}\'\\" with administrator privileges"`;
|
||||
await promisify(exec)(command);
|
||||
} catch (error) {
|
||||
throw new Error(localize('cantUninstall', "Unable to uninstall the shell command '{0}'.", source));
|
||||
}
|
||||
}
|
||||
break;
|
||||
case 'ENOENT':
|
||||
break; // ignore file not found
|
||||
default:
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private async getShellCommandLink(): Promise<{ readonly source: string, readonly target: string }> {
|
||||
const target = resolve(this.environmentMainService.appRoot, 'bin', 'code');
|
||||
const source = `/usr/local/bin/${this.productService.applicationName}`;
|
||||
|
||||
// Ensure source exists
|
||||
const sourceExists = await exists(target);
|
||||
if (!sourceExists) {
|
||||
throw new Error(localize('sourceMissing', "Unable to find shell script in '{0}'", target));
|
||||
}
|
||||
|
||||
return { source, target };
|
||||
}
|
||||
|
||||
//#region Dialog
|
||||
|
||||
async showMessageBox(windowId: number | undefined, options: MessageBoxOptions): Promise<MessageBoxReturnValue> {
|
||||
|
|
|
@ -6,11 +6,12 @@
|
|||
import { Event } from 'vs/base/common/event';
|
||||
import { IOpenerService } from 'vs/platform/opener/common/opener';
|
||||
import { $, EventHelper, EventLike } from 'vs/base/browser/dom';
|
||||
import { domEvent } from 'vs/base/browser/event';
|
||||
import { DomEmitter, domEvent } 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';
|
||||
import { Color } from 'vs/base/common/color';
|
||||
import { registerThemingParticipant } from 'vs/platform/theme/common/themeService';
|
||||
import { textLinkActiveForeground, textLinkForeground } from 'vs/platform/theme/common/colorRegistry';
|
||||
|
||||
export interface ILinkDescriptor {
|
||||
readonly label: string;
|
||||
|
@ -20,20 +21,37 @@ export interface ILinkDescriptor {
|
|||
|
||||
export interface ILinkOptions {
|
||||
readonly opener?: (href: string) => void;
|
||||
}
|
||||
|
||||
export interface ILinkStyles {
|
||||
readonly textLinkForeground?: Color;
|
||||
readonly disabled?: boolean;
|
||||
readonly textLinkForeground?: string;
|
||||
}
|
||||
|
||||
export class Link extends Disposable {
|
||||
|
||||
readonly el: HTMLAnchorElement;
|
||||
private disabled: boolean;
|
||||
private styles: ILinkStyles = {
|
||||
textLinkForeground: Color.fromHex('#006AB1')
|
||||
};
|
||||
private _enabled: boolean = true;
|
||||
|
||||
get enabled(): boolean {
|
||||
return this._enabled;
|
||||
}
|
||||
|
||||
set enabled(enabled: boolean) {
|
||||
if (enabled) {
|
||||
this.el.setAttribute('aria-disabled', 'false');
|
||||
this.el.tabIndex = 0;
|
||||
this.el.style.pointerEvents = 'auto';
|
||||
this.el.style.opacity = '1';
|
||||
this.el.style.cursor = 'pointer';
|
||||
this._enabled = false;
|
||||
} else {
|
||||
this.el.setAttribute('aria-disabled', 'true');
|
||||
this.el.tabIndex = -1;
|
||||
this.el.style.pointerEvents = 'none';
|
||||
this.el.style.opacity = '0.4';
|
||||
this.el.style.cursor = 'default';
|
||||
this._enabled = true;
|
||||
}
|
||||
|
||||
this._enabled = enabled;
|
||||
}
|
||||
|
||||
constructor(
|
||||
link: ILinkDescriptor,
|
||||
|
@ -42,60 +60,45 @@ export class Link extends Disposable {
|
|||
) {
|
||||
super();
|
||||
|
||||
this.el = $<HTMLAnchorElement>('a', {
|
||||
this.el = $<HTMLAnchorElement>('a.monaco-link', {
|
||||
tabIndex: 0,
|
||||
href: link.href,
|
||||
title: link.title
|
||||
}, link.label);
|
||||
|
||||
const onClick = domEvent(this.el, 'click');
|
||||
const onClickEmitter = this._register(new DomEmitter(this.el, 'click'));
|
||||
const onEnterPress = Event.chain(domEvent(this.el, 'keypress'))
|
||||
.map(e => new StandardKeyboardEvent(e))
|
||||
.filter(e => e.keyCode === KeyCode.Enter)
|
||||
.event;
|
||||
const onOpen = Event.any<EventLike>(onClick, onEnterPress);
|
||||
const onOpen = Event.any<EventLike>(onClickEmitter.event, onEnterPress);
|
||||
|
||||
this._register(onOpen(e => {
|
||||
if (!this.enabled) {
|
||||
return;
|
||||
}
|
||||
|
||||
EventHelper.stop(e, true);
|
||||
if (!this.disabled) {
|
||||
if (options?.opener) {
|
||||
options.opener(link.href);
|
||||
} else {
|
||||
openerService.open(link.href, { allowCommands: true });
|
||||
}
|
||||
|
||||
if (options?.opener) {
|
||||
options.opener(link.href);
|
||||
} else {
|
||||
openerService.open(link.href, { allowCommands: true });
|
||||
}
|
||||
}));
|
||||
|
||||
this.disabled = false;
|
||||
this.applyStyles();
|
||||
}
|
||||
|
||||
style(styles: ILinkStyles): void {
|
||||
this.styles = styles;
|
||||
this.applyStyles();
|
||||
}
|
||||
|
||||
private applyStyles(): void {
|
||||
const color = this.styles.textLinkForeground?.toString();
|
||||
if (color) {
|
||||
this.el.style.color = color;
|
||||
}
|
||||
if (typeof this.styles.disabled === 'boolean' && this.styles.disabled !== this.disabled) {
|
||||
if (this.styles.disabled) {
|
||||
this.el.setAttribute('aria-disabled', 'true');
|
||||
this.el.tabIndex = -1;
|
||||
this.el.style.pointerEvents = 'none';
|
||||
this.el.style.opacity = '0.4';
|
||||
this.el.style.cursor = 'default';
|
||||
this.disabled = true;
|
||||
} else {
|
||||
this.el.setAttribute('aria-disabled', 'false');
|
||||
this.el.tabIndex = 0;
|
||||
this.el.style.pointerEvents = 'auto';
|
||||
this.el.style.opacity = '1';
|
||||
this.el.style.cursor = 'pointer';
|
||||
this.disabled = false;
|
||||
}
|
||||
}
|
||||
this.enabled = true;
|
||||
}
|
||||
}
|
||||
|
||||
registerThemingParticipant((theme, collector) => {
|
||||
const textLinkForegroundColor = theme.getColor(textLinkForeground);
|
||||
if (textLinkForegroundColor) {
|
||||
collector.addRule(`.monaco-link { color: ${textLinkForegroundColor}; }`);
|
||||
}
|
||||
|
||||
const textLinkActiveForegroundColor = theme.getColor(textLinkActiveForeground);
|
||||
if (textLinkActiveForegroundColor) {
|
||||
collector.addRule(`.monaco-link:hover { color: ${textLinkActiveForegroundColor}; }`);
|
||||
}
|
||||
});
|
||||
|
|
|
@ -10,7 +10,7 @@ import { IStateMainService } from 'vs/platform/state/electron-main/state';
|
|||
import { ILogService } from 'vs/platform/log/common/log';
|
||||
import { IEnvironmentMainService } from 'vs/platform/environment/electron-main/environmentMainService';
|
||||
import { ThrottledDelayer } from 'vs/base/common/async';
|
||||
import { IFileService } from 'vs/platform/files/common/files';
|
||||
import { FileOperationError, FileOperationResult, IFileService } from 'vs/platform/files/common/files';
|
||||
import { VSBuffer } from 'vs/base/common/buffer';
|
||||
|
||||
type StorageDatabase = { [key: string]: unknown; };
|
||||
|
@ -45,7 +45,7 @@ export class FileStorage {
|
|||
this.lastSavedStorageContents = (await this.fileService.readFile(this.storagePath)).value.toString();
|
||||
this.storage = JSON.parse(this.lastSavedStorageContents);
|
||||
} catch (error) {
|
||||
if (error.code !== 'ENOENT') {
|
||||
if ((<FileOperationError>error).fileOperationResult !== FileOperationResult.FILE_NOT_FOUND) {
|
||||
this.logService.error(error);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -418,6 +418,12 @@ export interface ITerminalLaunchError {
|
|||
code?: number;
|
||||
}
|
||||
|
||||
export interface IProcessReadyEvent {
|
||||
pid: number,
|
||||
cwd: string,
|
||||
requiresWindowsMode?: boolean
|
||||
}
|
||||
|
||||
/**
|
||||
* An interface representing a raw terminal child process, this contains a subset of the
|
||||
* child_process.ChildProcess node.js interface.
|
||||
|
@ -437,7 +443,7 @@ export interface ITerminalChildProcess {
|
|||
|
||||
onProcessData: Event<IProcessDataEvent | string>;
|
||||
onProcessExit: Event<number | undefined>;
|
||||
onProcessReady: Event<{ pid: number, cwd: string }>;
|
||||
onProcessReady: Event<IProcessReadyEvent>;
|
||||
onProcessTitleChanged: Event<string>;
|
||||
onProcessOverrideDimensions?: Event<ITerminalDimensionsOverride | undefined>;
|
||||
onProcessResolvedShellLaunchConfig?: Event<IShellLaunchConfig>;
|
||||
|
|
|
@ -187,6 +187,13 @@ const terminalPlatformConfiguration: IConfigurationNode = {
|
|||
description: localize('terminalProfile.windowsSource', 'A profile source that will auto detect the paths to the shell.'),
|
||||
enum: ['PowerShell', 'Git Bash']
|
||||
},
|
||||
args: {
|
||||
description: localize('terminalProfile.args', 'An optional set of arguments to run the shell executable with.'),
|
||||
type: 'array',
|
||||
items: {
|
||||
type: 'string'
|
||||
}
|
||||
},
|
||||
overrideName: {
|
||||
description: localize('terminalProfile.overrideName', 'Controls whether or not the profile name overrides the auto detected one.'),
|
||||
type: 'boolean'
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
|
||||
import { Disposable, toDisposable } from 'vs/base/common/lifecycle';
|
||||
import { IProcessEnvironment, isWindows, OperatingSystem, OS } from 'vs/base/common/platform';
|
||||
import { IPtyService, IProcessDataEvent, IShellLaunchConfig, ITerminalDimensionsOverride, ITerminalLaunchError, LocalReconnectConstants, ITerminalsLayoutInfo, IRawTerminalInstanceLayoutInfo, ITerminalTabLayoutInfoById, ITerminalInstanceLayoutInfoById, TerminalShellType } from 'vs/platform/terminal/common/terminal';
|
||||
import { IPtyService, IProcessDataEvent, IShellLaunchConfig, ITerminalDimensionsOverride, ITerminalLaunchError, LocalReconnectConstants, ITerminalsLayoutInfo, IRawTerminalInstanceLayoutInfo, ITerminalTabLayoutInfoById, ITerminalInstanceLayoutInfoById, TerminalShellType, IProcessReadyEvent } from 'vs/platform/terminal/common/terminal';
|
||||
import { AutoOpenBarrier, Queue, RunOnceScheduler } from 'vs/base/common/async';
|
||||
import { Emitter } from 'vs/base/common/event';
|
||||
import { TerminalRecorder } from 'vs/platform/terminal/common/terminalRecorder';
|
||||
|
@ -281,7 +281,7 @@ export class PersistentTerminalProcess extends Disposable {
|
|||
|
||||
private readonly _onProcessReplay = this._register(new Emitter<IPtyHostProcessReplayEvent>());
|
||||
readonly onProcessReplay = this._onProcessReplay.event;
|
||||
private readonly _onProcessReady = this._register(new Emitter<{ pid: number, cwd: string }>());
|
||||
private readonly _onProcessReady = this._register(new Emitter<IProcessReadyEvent>());
|
||||
readonly onProcessReady = this._onProcessReady.event;
|
||||
private readonly _onProcessTitleChanged = this._register(new Emitter<string>());
|
||||
readonly onProcessTitleChanged = this._onProcessTitleChanged.event;
|
||||
|
@ -377,7 +377,7 @@ export class PersistentTerminalProcess extends Disposable {
|
|||
}
|
||||
this._isStarted = true;
|
||||
} else {
|
||||
this._onProcessReady.fire({ pid: this._pid, cwd: this._cwd });
|
||||
this._onProcessReady.fire({ pid: this._pid, cwd: this._cwd, requiresWindowsMode: isWindows && getWindowsBuildNumber() < 21376 });
|
||||
this._onProcessTitleChanged.fire(this._terminalProcess.currentTitle);
|
||||
this._onProcessShellTypeChanged.fire(this._terminalProcess.shellType);
|
||||
this.triggerReplay();
|
||||
|
|
|
@ -9,7 +9,7 @@ import * as fs from 'fs';
|
|||
import * as os from 'os';
|
||||
import { Event, Emitter } from 'vs/base/common/event';
|
||||
import { Disposable } from 'vs/base/common/lifecycle';
|
||||
import { IShellLaunchConfig, ITerminalLaunchError, FlowControlConstants, ITerminalChildProcess, ITerminalDimensionsOverride, TerminalShellType } from 'vs/platform/terminal/common/terminal';
|
||||
import { IShellLaunchConfig, ITerminalLaunchError, FlowControlConstants, ITerminalChildProcess, ITerminalDimensionsOverride, TerminalShellType, IProcessReadyEvent } from 'vs/platform/terminal/common/terminal';
|
||||
import { exec } from 'child_process';
|
||||
import { ILogService } from 'vs/platform/log/common/log';
|
||||
import { findExecutable, getWindowsBuildNumber } from 'vs/platform/terminal/node/terminalEnvironment';
|
||||
|
@ -99,8 +99,8 @@ export class TerminalProcess extends Disposable implements ITerminalChildProcess
|
|||
get onProcessData(): Event<string> { return this._onProcessData.event; }
|
||||
private readonly _onProcessExit = this._register(new Emitter<number>());
|
||||
get onProcessExit(): Event<number> { return this._onProcessExit.event; }
|
||||
private readonly _onProcessReady = this._register(new Emitter<{ pid: number, cwd: string }>());
|
||||
get onProcessReady(): Event<{ pid: number, cwd: string }> { return this._onProcessReady.event; }
|
||||
private readonly _onProcessReady = this._register(new Emitter<IProcessReadyEvent>());
|
||||
get onProcessReady(): Event<IProcessReadyEvent> { return this._onProcessReady.event; }
|
||||
private readonly _onProcessTitleChanged = this._register(new Emitter<string>());
|
||||
get onProcessTitleChanged(): Event<string> { return this._onProcessTitleChanged.event; }
|
||||
private readonly _onProcessShellTypeChanged = this._register(new Emitter<TerminalShellType>());
|
||||
|
@ -324,7 +324,7 @@ export class TerminalProcess extends Disposable implements ITerminalChildProcess
|
|||
}
|
||||
|
||||
private _sendProcessId(pid: number) {
|
||||
this._onProcessReady.fire({ pid, cwd: this._initialCwd });
|
||||
this._onProcessReady.fire({ pid, cwd: this._initialCwd, requiresWindowsMode: isWindows && getWindowsBuildNumber() < 21376 });
|
||||
}
|
||||
|
||||
private _sendProcessTitle(ptyProcess: pty.IPty): void {
|
||||
|
|
|
@ -35,7 +35,7 @@ export function computeStyles(theme: IColorTheme, styleMap: IColorMapping): ICom
|
|||
}
|
||||
|
||||
export function attachStyler<T extends IColorMapping>(themeService: IThemeService, styleMap: T, widgetOrCallback: IThemable | styleFn): IDisposable {
|
||||
function applyStyles(theme: IColorTheme): void {
|
||||
function applyStyles(): void {
|
||||
const styles = computeStyles(themeService.getColorTheme(), styleMap);
|
||||
|
||||
if (typeof widgetOrCallback === 'function') {
|
||||
|
@ -45,7 +45,7 @@ export function attachStyler<T extends IColorMapping>(themeService: IThemeServic
|
|||
}
|
||||
}
|
||||
|
||||
applyStyles(themeService.getColorTheme());
|
||||
applyStyles();
|
||||
|
||||
return themeService.onDidColorThemeChange(applyStyles);
|
||||
}
|
||||
|
@ -254,16 +254,6 @@ export function attachKeybindingLabelStyler(widget: IThemable, themeService: ITh
|
|||
} as IKeybindingLabelStyleOverrides, widget);
|
||||
}
|
||||
|
||||
export interface ILinkStyleOverrides extends IStyleOverrides {
|
||||
textLinkForeground?: ColorIdentifier;
|
||||
}
|
||||
|
||||
export function attachLinkStyler(widget: IThemable, themeService: IThemeService, style?: ILinkStyleOverrides): IDisposable {
|
||||
return attachStyler(themeService, {
|
||||
textLinkForeground: style?.textLinkForeground || textLinkForeground,
|
||||
} as ILinkStyleOverrides, widget);
|
||||
}
|
||||
|
||||
export interface IProgressBarStyleOverrides extends IStyleOverrides {
|
||||
progressBarBackground?: ColorIdentifier;
|
||||
}
|
||||
|
@ -324,7 +314,7 @@ export function attachMenuStyler(widget: IThemable, themeService: IThemeService,
|
|||
return attachStyler(themeService, { ...defaultMenuStyles, ...style }, widget);
|
||||
}
|
||||
|
||||
export interface IDialogStyleOverrides extends IButtonStyleOverrides, ILinkStyleOverrides {
|
||||
export interface IDialogStyleOverrides extends IButtonStyleOverrides {
|
||||
dialogForeground?: ColorIdentifier;
|
||||
dialogBackground?: ColorIdentifier;
|
||||
dialogShadow?: ColorIdentifier;
|
||||
|
|
|
@ -34,7 +34,6 @@ import { IFileService } from 'vs/platform/files/common/files';
|
|||
import { FileAccess, Schemas } from 'vs/base/common/network';
|
||||
import { isLaunchedFromCli } from 'vs/platform/environment/node/argvHelper';
|
||||
import { CancellationToken } from 'vs/base/common/cancellation';
|
||||
import { INativeHostMainService } from 'vs/platform/native/electron-main/nativeHostMainService';
|
||||
import { IProtocolMainService } from 'vs/platform/protocol/electron-main/protocol';
|
||||
|
||||
export interface IWindowCreationOptions {
|
||||
|
@ -153,7 +152,6 @@ export class CodeWindow extends Disposable implements ICodeWindow {
|
|||
@ITelemetryService private readonly telemetryService: ITelemetryService,
|
||||
@IDialogMainService private readonly dialogMainService: IDialogMainService,
|
||||
@ILifecycleMainService private readonly lifecycleMainService: ILifecycleMainService,
|
||||
@INativeHostMainService private readonly nativeHostMainService: INativeHostMainService,
|
||||
@IProductService private readonly productService: IProductService,
|
||||
@IProtocolMainService private readonly protocolMainService: IProtocolMainService
|
||||
) {
|
||||
|
@ -510,22 +508,6 @@ export class CodeWindow extends Disposable implements ICodeWindow {
|
|||
this._lastFocusTime = Date.now();
|
||||
});
|
||||
|
||||
if (isMacintosh) {
|
||||
this._register(this.nativeHostMainService.onDidChangeDisplay(() => {
|
||||
if (!this._win) {
|
||||
return; // disposed
|
||||
}
|
||||
|
||||
// Simple fullscreen doesn't resize automatically when the resolution changes so as a workaround
|
||||
// we need to detect when display metrics change or displays are added/removed and toggle the
|
||||
// fullscreen manually.
|
||||
if (!this.useNativeFullScreen() && this.isFullScreen) {
|
||||
this.setFullScreen(false);
|
||||
this.setFullScreen(true);
|
||||
}
|
||||
}));
|
||||
}
|
||||
|
||||
// Window (Un)Maximize
|
||||
this._win.on('maximize', (e: Event) => {
|
||||
if (this.currentConfig) {
|
||||
|
|
|
@ -53,6 +53,12 @@ export interface IWorkspaceTrustManagementService {
|
|||
setTrustedFolders(folders: URI[]): Promise<void>;
|
||||
}
|
||||
|
||||
export const enum WorkspaceTrustUriResponse {
|
||||
Open = 1,
|
||||
OpenInNewWindow = 2,
|
||||
Cancel = 3
|
||||
}
|
||||
|
||||
export const IWorkspaceTrustRequestService = createDecorator<IWorkspaceTrustRequestService>('workspaceTrustRequestService');
|
||||
|
||||
export interface IWorkspaceTrustRequestService {
|
||||
|
@ -60,6 +66,7 @@ export interface IWorkspaceTrustRequestService {
|
|||
|
||||
readonly onDidInitiateWorkspaceTrustRequest: Event<WorkspaceTrustRequestOptions | undefined>;
|
||||
|
||||
requestOpenUris(uris: URI[]): Promise<WorkspaceTrustUriResponse>;
|
||||
cancelRequest(): void;
|
||||
completeRequest(trusted?: boolean): Promise<void>;
|
||||
requestWorkspaceTrust(options?: WorkspaceTrustRequestOptions): Promise<boolean | undefined>;
|
||||
|
|
38
src/vs/vscode.d.ts
vendored
38
src/vs/vscode.d.ts
vendored
|
@ -1154,7 +1154,9 @@ declare module 'vscode' {
|
|||
|
||||
/**
|
||||
* Adds a set of decorations to the text editor. If a set of decorations already exists with
|
||||
* the given {@link TextEditorDecorationType decoration type}, they will be replaced.
|
||||
* the given {@link TextEditorDecorationType decoration type}, they will be replaced. If
|
||||
* `rangesOrOptions` is empty, the existing decorations with the given {@link TextEditorDecorationType decoration type}
|
||||
* will be removed.
|
||||
*
|
||||
* @see {@link window.createTextEditorDecorationType createTextEditorDecorationType}.
|
||||
*
|
||||
|
@ -1312,6 +1314,15 @@ declare module 'vscode' {
|
|||
*/
|
||||
static joinPath(base: Uri, ...pathSegments: string[]): Uri;
|
||||
|
||||
/**
|
||||
* Create an URI from its component parts
|
||||
*
|
||||
* @see {@link Uri.toString}
|
||||
* @param components The component parts of an Uri.
|
||||
* @return A new Uri instance.
|
||||
*/
|
||||
static from(components: { scheme: string; authority?: string; path?: string; query?: string; fragment?: string }): Uri;
|
||||
|
||||
/**
|
||||
* Use the `file` and `parse` factory functions to create new `Uri` objects.
|
||||
*/
|
||||
|
@ -5573,6 +5584,14 @@ declare module 'vscode' {
|
|||
*/
|
||||
export interface StatusBarItem {
|
||||
|
||||
/**
|
||||
* The identifier of this item.
|
||||
*
|
||||
* *Note*: if no identifier was provided by the {@link window.createStatusBarItem `window.createStatusBarItem`}
|
||||
* method, the identifier will match the {@link Extension.id extension identifier}.
|
||||
*/
|
||||
readonly id: string;
|
||||
|
||||
/**
|
||||
* The alignment of this item.
|
||||
*/
|
||||
|
@ -5584,6 +5603,13 @@ declare module 'vscode' {
|
|||
*/
|
||||
readonly priority?: number;
|
||||
|
||||
/**
|
||||
* The name of the entry, like 'Python Language Indicator', 'Git Status' etc.
|
||||
* Try to keep the length of the name short, yet descriptive enough that
|
||||
* users can understand what the status bar item is about.
|
||||
*/
|
||||
name: string | undefined;
|
||||
|
||||
/**
|
||||
* The text to show for the entry. You can embed icons in the text by leveraging the syntax:
|
||||
*
|
||||
|
@ -8793,6 +8819,16 @@ declare module 'vscode' {
|
|||
*/
|
||||
export function createStatusBarItem(alignment?: StatusBarAlignment, priority?: number): StatusBarItem;
|
||||
|
||||
/**
|
||||
* Creates a status bar {@link StatusBarItem item}.
|
||||
*
|
||||
* @param id The unique identifier of the item.
|
||||
* @param alignment The alignment of the item.
|
||||
* @param priority The priority of the item. Higher values mean the item should be shown more to the left.
|
||||
* @return A new status bar item.
|
||||
*/
|
||||
export function createStatusBarItem(id: string, alignment?: StatusBarAlignment, priority?: number): StatusBarItem;
|
||||
|
||||
/**
|
||||
* Creates a {@link Terminal} with a backing shell process. The cwd of the terminal will be the workspace
|
||||
* directory if it exists.
|
||||
|
|
97
src/vs/vscode.proposed.d.ts
vendored
97
src/vs/vscode.proposed.d.ts
vendored
|
@ -915,24 +915,18 @@ declare module 'vscode' {
|
|||
|
||||
//#region Custom Tree View Drag and Drop https://github.com/microsoft/vscode/issues/32592
|
||||
export interface TreeViewOptions<T> {
|
||||
/**
|
||||
* * Whether the tree supports drag and drop.
|
||||
*/
|
||||
canDragAndDrop?: boolean;
|
||||
dragAndDropController?: DragAndDropController<T>;
|
||||
}
|
||||
|
||||
export interface TreeDataProvider<T> {
|
||||
export interface DragAndDropController<T> extends Disposable {
|
||||
/**
|
||||
* Optional method to reparent an `element`.
|
||||
* Extensions should fire `TreeDataProvider.onDidChangeTreeData` for any elements that need to be refreshed.
|
||||
*
|
||||
* **NOTE:** This method should be implemented if the tree supports drag and drop.
|
||||
*
|
||||
* @param elements The selected elements that will be reparented.
|
||||
* @param targetElement The new parent of the elements.
|
||||
* @param source
|
||||
* @param target
|
||||
*/
|
||||
setParent?(elements: T[], targetElement: T): Thenable<void>;
|
||||
onDrop(source: T[], target: T): Thenable<void>;
|
||||
}
|
||||
|
||||
//#endregion
|
||||
|
||||
//#region Task presentation group: https://github.com/microsoft/vscode/issues/47265
|
||||
|
@ -944,59 +938,6 @@ declare module 'vscode' {
|
|||
}
|
||||
//#endregion
|
||||
|
||||
//#region Status bar item with ID and Name: https://github.com/microsoft/vscode/issues/74972
|
||||
|
||||
/**
|
||||
* Options to configure the status bar item.
|
||||
*/
|
||||
export interface StatusBarItemOptions {
|
||||
|
||||
/**
|
||||
* A unique identifier of the status bar item. The identifier
|
||||
* is for example used to allow a user to show or hide the
|
||||
* status bar item in the UI.
|
||||
*/
|
||||
id: string;
|
||||
|
||||
/**
|
||||
* A human readable name of the status bar item. The name is
|
||||
* for example used as a label in the UI to show or hide the
|
||||
* status bar item.
|
||||
*/
|
||||
name: string;
|
||||
|
||||
/**
|
||||
* Accessibility information used when screen reader interacts with this status bar item.
|
||||
*/
|
||||
accessibilityInformation?: AccessibilityInformation;
|
||||
|
||||
/**
|
||||
* The alignment of the status bar item.
|
||||
*/
|
||||
alignment?: StatusBarAlignment;
|
||||
|
||||
/**
|
||||
* The priority of the status bar item. Higher value means the item should
|
||||
* be shown more to the left.
|
||||
*/
|
||||
priority?: number;
|
||||
}
|
||||
|
||||
export namespace window {
|
||||
|
||||
/**
|
||||
* Creates a status bar {@link StatusBarItem item}.
|
||||
*
|
||||
* @param options The options of the item. If not provided, some default values
|
||||
* will be assumed. For example, the `StatusBarItemOptions.id` will be the id
|
||||
* of the extension and the `StatusBarItemOptions.name` will be the extension name.
|
||||
* @return A new status bar item.
|
||||
*/
|
||||
export function createStatusBarItem(options?: StatusBarItemOptions): StatusBarItem;
|
||||
}
|
||||
|
||||
//#endregion
|
||||
|
||||
//#region Custom editor move https://github.com/microsoft/vscode/issues/86146
|
||||
|
||||
// TODO: Also for custom editor
|
||||
|
@ -1057,7 +998,6 @@ declare module 'vscode' {
|
|||
*
|
||||
* NotebookCell instances are immutable and are kept in sync for as long as they are part of their notebook.
|
||||
*/
|
||||
// todo@API support ids https://github.com/jupyter/enhancement-proposals/blob/master/62-cell-id/cell-id.md
|
||||
export interface NotebookCell {
|
||||
|
||||
/**
|
||||
|
@ -1322,7 +1262,6 @@ declare module 'vscode' {
|
|||
/**
|
||||
* NotebookCellData is the raw representation of notebook cells. Its is part of {@link NotebookData `NotebookData`}.
|
||||
*/
|
||||
// todo@API support ids https://github.com/jupyter/enhancement-proposals/blob/master/62-cell-id/cell-id.md
|
||||
export class NotebookCellData {
|
||||
|
||||
/**
|
||||
|
@ -3323,4 +3262,28 @@ declare module 'vscode' {
|
|||
}
|
||||
|
||||
//#endregion
|
||||
|
||||
//#region Expose parent session on DebugSessions - https://github.com/microsoft/vscode/issues/123403#issuecomment-843269200
|
||||
|
||||
export interface DebugSession {
|
||||
/**
|
||||
* The parent session of this debug session, if it was created as a child.
|
||||
* @see DebugSessionOptions.parentSession
|
||||
*/
|
||||
readonly parentSession?: DebugSession;
|
||||
}
|
||||
|
||||
//#endregion
|
||||
|
||||
//#region https://github.com/microsoft/vscode/issues/87110 @eamodio
|
||||
|
||||
export interface Memento {
|
||||
|
||||
/**
|
||||
* The stored keys.
|
||||
*/
|
||||
readonly keys: readonly string[];
|
||||
}
|
||||
|
||||
//#endregion
|
||||
}
|
||||
|
|
|
@ -16,7 +16,7 @@ import { isEqual, isEqualOrParent, toLocalResource } from 'vs/base/common/resour
|
|||
import { URI, UriComponents } from 'vs/base/common/uri';
|
||||
import { localize } from 'vs/nls';
|
||||
import { IFileDialogService } from 'vs/platform/dialogs/common/dialogs';
|
||||
import { FileSystemProviderCapabilities, IFileService } from 'vs/platform/files/common/files';
|
||||
import { FileOperation, FileSystemProviderCapabilities, IFileService } from 'vs/platform/files/common/files';
|
||||
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
|
||||
import { ILabelService } from 'vs/platform/label/common/label';
|
||||
import { IUndoRedoService, UndoRedoElementType } from 'vs/platform/undoRedo/common/undoRedo';
|
||||
|
@ -35,7 +35,7 @@ import { IEditorGroupsService } from 'vs/workbench/services/editor/common/editor
|
|||
import { IWorkbenchEnvironmentService } from 'vs/workbench/services/environment/common/environmentService';
|
||||
import { IExtensionService } from 'vs/workbench/services/extensions/common/extensions';
|
||||
import { IPathService } from 'vs/workbench/services/path/common/pathService';
|
||||
import { IWorkingCopyFileService } from 'vs/workbench/services/workingCopy/common/workingCopyFileService';
|
||||
import { IWorkingCopyFileService, WorkingCopyFileEvent } from 'vs/workbench/services/workingCopy/common/workingCopyFileService';
|
||||
import { IWorkingCopyService } from 'vs/workbench/services/workingCopy/common/workingCopyService';
|
||||
import { IWorkingCopy, IWorkingCopyBackup, NO_TYPE_ID, WorkingCopyCapabilities } from 'vs/workbench/services/workingCopy/common/workingCopy';
|
||||
import { ResourceWorkingCopy } from 'vs/workbench/services/workingCopy/common/resourceWorkingCopy';
|
||||
|
@ -51,6 +51,8 @@ export class MainThreadCustomEditors extends Disposable implements extHostProtoc
|
|||
|
||||
private readonly _editorProviders = new Map<string, IDisposable>();
|
||||
|
||||
private readonly _editorRenameBackups = new Map<string, CustomDocumentBackupData>();
|
||||
|
||||
constructor(
|
||||
context: extHostProtocol.IExtHostContext,
|
||||
private readonly mainThreadWebview: MainThreadWebviews,
|
||||
|
@ -61,7 +63,7 @@ export class MainThreadCustomEditors extends Disposable implements extHostProtoc
|
|||
@ICustomEditorService private readonly _customEditorService: ICustomEditorService,
|
||||
@IEditorGroupsService private readonly _editorGroupService: IEditorGroupsService,
|
||||
@IWebviewWorkbenchService private readonly _webviewWorkbenchService: IWebviewWorkbenchService,
|
||||
@IInstantiationService private readonly _instantiationService: IInstantiationService
|
||||
@IInstantiationService private readonly _instantiationService: IInstantiationService,
|
||||
) {
|
||||
super();
|
||||
|
||||
|
@ -90,6 +92,9 @@ export class MainThreadCustomEditors extends Disposable implements extHostProtoc
|
|||
},
|
||||
resolveWebview: () => { throw new Error('not implemented'); }
|
||||
}));
|
||||
|
||||
// Working copy operations
|
||||
this._register(workingCopyFileService.onWillRunWorkingCopyFileOperation(async e => this.onWillRunWorkingCopyFileOperation(e)));
|
||||
}
|
||||
|
||||
override dispose() {
|
||||
|
@ -138,9 +143,18 @@ export class MainThreadCustomEditors extends Disposable implements extHostProtoc
|
|||
webviewInput.webview.options = options;
|
||||
webviewInput.webview.extension = extension;
|
||||
|
||||
// If there's an old resource this was a move and we must resolve the backup at the same time as the webview
|
||||
// This is because the backup must be ready upon model creation, and the input resolve method comes after
|
||||
let backupId = webviewInput.backupId;
|
||||
if (webviewInput.oldResource && !webviewInput.backupId) {
|
||||
const backup = this._editorRenameBackups.get(webviewInput.oldResource.toString());
|
||||
backupId = backup?.backupId;
|
||||
this._editorRenameBackups.delete(webviewInput.oldResource.toString());
|
||||
}
|
||||
|
||||
let modelRef: IReference<ICustomEditorModel>;
|
||||
try {
|
||||
modelRef = await this.getOrCreateCustomEditorModel(modelType, resource, viewType, { backupId: webviewInput.backupId }, cancellation);
|
||||
modelRef = await this.getOrCreateCustomEditorModel(modelType, resource, viewType, { backupId }, cancellation);
|
||||
} catch (error) {
|
||||
onUnexpectedError(error);
|
||||
webviewInput.webview.html = this.mainThreadWebview.getWebviewResolvedFailedContent(viewType);
|
||||
|
@ -253,6 +267,31 @@ export class MainThreadCustomEditors extends Disposable implements extHostProtoc
|
|||
}
|
||||
return model;
|
||||
}
|
||||
|
||||
//#region Working Copy
|
||||
private async onWillRunWorkingCopyFileOperation(e: WorkingCopyFileEvent) {
|
||||
if (e.operation !== FileOperation.MOVE) {
|
||||
return;
|
||||
}
|
||||
e.waitUntil((async () => {
|
||||
const models = [];
|
||||
for (const file of e.files) {
|
||||
if (file.source) {
|
||||
models.push(...(await this._customEditorService.models.getAllModels(file.source)));
|
||||
}
|
||||
}
|
||||
for (const model of models) {
|
||||
if (model instanceof MainThreadCustomEditorModel && model.isDirty()) {
|
||||
const workingCopy = await model.backup(CancellationToken.None);
|
||||
if (workingCopy.meta) {
|
||||
// This cast is safe because we do an instanceof check above and a custom document backup data is always returned
|
||||
this._editorRenameBackups.set(model.editorResource.toString(), workingCopy.meta as CustomDocumentBackupData);
|
||||
}
|
||||
}
|
||||
}
|
||||
})());
|
||||
}
|
||||
//#endregion
|
||||
}
|
||||
|
||||
namespace HotExitState {
|
||||
|
|
|
@ -329,7 +329,8 @@ export class MainThreadDebugService implements MainThreadDebugServiceShape, IDeb
|
|||
type: session.configuration.type,
|
||||
name: session.name,
|
||||
folderUri: session.root ? session.root.uri : undefined,
|
||||
configuration: session.configuration
|
||||
configuration: session.configuration,
|
||||
parent: session.parentSession?.getId(),
|
||||
};
|
||||
}
|
||||
}
|
||||
|
|
|
@ -7,7 +7,7 @@ import { DisposableStore, dispose, IDisposable } from 'vs/base/common/lifecycle'
|
|||
import { URI } from 'vs/base/common/uri';
|
||||
import { ExtHostContext, IExtHostEditorTabsShape, IExtHostContext, MainContext, IEditorTabDto } from 'vs/workbench/api/common/extHost.protocol';
|
||||
import { extHostNamedCustomer } from 'vs/workbench/api/common/extHostCustomers';
|
||||
import { Verbosity } from 'vs/workbench/common/editor';
|
||||
import { EditorResourceAccessor, Verbosity } from 'vs/workbench/common/editor';
|
||||
import { GroupChangeKind, IEditorGroup, IEditorGroupsService } from 'vs/workbench/services/editor/common/editorGroupsService';
|
||||
import { IEditorService } from 'vs/workbench/services/editor/common/editorService';
|
||||
|
||||
|
@ -33,7 +33,7 @@ export class MainThreadEditorTabs {
|
|||
|
||||
this._proxy = extHostContext.getProxy(ExtHostContext.ExtHostEditorTabs);
|
||||
|
||||
this._editorGroupsService.groups.forEach(this._subscribeToGroup, this);
|
||||
this._editorGroupsService.whenReady.then(() => this._editorGroupsService.groups.forEach(this._subscribeToGroup, this));
|
||||
this._dispoables.add(_editorGroupsService.onDidAddGroup(this._subscribeToGroup, this));
|
||||
this._dispoables.add(_editorGroupsService.onDidRemoveGroup(e => {
|
||||
const subscription = this._groups.get(e);
|
||||
|
@ -72,7 +72,7 @@ export class MainThreadEditorTabs {
|
|||
tabs.push({
|
||||
group: group.id,
|
||||
name: editor.getTitle(Verbosity.SHORT) ?? '',
|
||||
resource: editor.resource,
|
||||
resource: EditorResourceAccessor.getOriginalUri(editor) ?? editor.resource,
|
||||
isActive: (this._editorGroupsService.activeGroup === group) && group.isActive(editor)
|
||||
});
|
||||
}
|
||||
|
|
|
@ -114,7 +114,8 @@ export class MainThreadNotebookDocuments implements MainThreadNotebookDocumentsS
|
|||
language: cell.language,
|
||||
cellKind: cell.cellKind,
|
||||
outputs: cell.outputs,
|
||||
metadata: cell.metadata
|
||||
metadata: cell.metadata,
|
||||
internalMetadata: cell.internalMetadata,
|
||||
};
|
||||
}
|
||||
|
||||
|
|
|
@ -234,7 +234,8 @@ export class MainThreadNotebooksAndEditors {
|
|||
language: cell.language,
|
||||
cellKind: cell.cellKind,
|
||||
outputs: cell.outputs,
|
||||
metadata: cell.metadata
|
||||
metadata: cell.metadata,
|
||||
internalMetadata: cell.internalMetadata,
|
||||
}))
|
||||
};
|
||||
}
|
||||
|
|
|
@ -185,7 +185,6 @@ export class MainThreadNotebookKernels implements MainThreadNotebookKernelsShape
|
|||
await that._proxy.$cancelCells(handle, uri, handles);
|
||||
}
|
||||
}(data, this._modeService);
|
||||
const registration = this._notebookKernelService.registerKernel(kernel);
|
||||
|
||||
const listener = this._notebookKernelService.onDidChangeNotebookKernelBinding(e => {
|
||||
if (e.oldKernel === kernel.id) {
|
||||
|
@ -195,6 +194,7 @@ export class MainThreadNotebookKernels implements MainThreadNotebookKernelsShape
|
|||
}
|
||||
});
|
||||
|
||||
const registration = this._notebookKernelService.registerKernel(kernel);
|
||||
this._kernels.set(handle, [kernel, combinedDisposable(listener, registration)]);
|
||||
}
|
||||
|
||||
|
|
|
@ -27,7 +27,7 @@ export class MainThreadStatusBar implements MainThreadStatusBarShape {
|
|||
this.entries.clear();
|
||||
}
|
||||
|
||||
$setEntry(id: number, statusId: string, statusName: string, text: string, tooltip: string | undefined, command: Command | undefined, color: string | ThemeColor | undefined, backgroundColor: string | ThemeColor | undefined, alignment: MainThreadStatusBarAlignment, priority: number | undefined, accessibilityInformation: IAccessibilityInformation): void {
|
||||
$setEntry(entryId: number, id: string, name: string, text: string, tooltip: string | undefined, command: Command | undefined, color: string | ThemeColor | undefined, backgroundColor: string | ThemeColor | undefined, alignment: MainThreadStatusBarAlignment, priority: number | undefined, accessibilityInformation: IAccessibilityInformation): void {
|
||||
// if there are icons in the text use the tooltip for the aria label
|
||||
let ariaLabel: string;
|
||||
let role: string | undefined = undefined;
|
||||
|
@ -37,23 +37,23 @@ export class MainThreadStatusBar implements MainThreadStatusBarShape {
|
|||
} else {
|
||||
ariaLabel = getCodiconAriaLabel(text);
|
||||
}
|
||||
const entry: IStatusbarEntry = { text, tooltip, command, color, backgroundColor, ariaLabel, role };
|
||||
const entry: IStatusbarEntry = { name, text, tooltip, command, color, backgroundColor, ariaLabel, role };
|
||||
|
||||
if (typeof priority === 'undefined') {
|
||||
priority = 0;
|
||||
}
|
||||
|
||||
// Reset existing entry if alignment or priority changed
|
||||
let existingEntry = this.entries.get(id);
|
||||
let existingEntry = this.entries.get(entryId);
|
||||
if (existingEntry && (existingEntry.alignment !== alignment || existingEntry.priority !== priority)) {
|
||||
dispose(existingEntry.accessor);
|
||||
this.entries.delete(id);
|
||||
this.entries.delete(entryId);
|
||||
existingEntry = undefined;
|
||||
}
|
||||
|
||||
// Create new entry if not existing
|
||||
if (!existingEntry) {
|
||||
this.entries.set(id, { accessor: this.statusbarService.addEntry(entry, statusId, statusName, alignment, priority), alignment, priority });
|
||||
this.entries.set(entryId, { accessor: this.statusbarService.addEntry(entry, id, alignment, priority), alignment, priority });
|
||||
}
|
||||
|
||||
// Otherwise update
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
|
||||
import { Disposable } from 'vs/base/common/lifecycle';
|
||||
import { ExtHostContext, MainThreadTreeViewsShape, ExtHostTreeViewsShape, MainContext, IExtHostContext } from 'vs/workbench/api/common/extHost.protocol';
|
||||
import { ITreeViewDataProvider, ITreeItem, IViewsService, ITreeView, IViewsRegistry, ITreeViewDescriptor, IRevealOptions, Extensions, ResolvableTreeItem } from 'vs/workbench/common/views';
|
||||
import { ITreeViewDataProvider, ITreeItem, IViewsService, ITreeView, IViewsRegistry, ITreeViewDescriptor, IRevealOptions, Extensions, ResolvableTreeItem, ITreeViewDragAndDropController } from 'vs/workbench/common/views';
|
||||
import { extHostNamedCustomer } from 'vs/workbench/api/common/extHostCustomers';
|
||||
import { distinct } from 'vs/base/common/arrays';
|
||||
import { INotificationService } from 'vs/platform/notification/common/notification';
|
||||
|
@ -37,13 +37,14 @@ export class MainThreadTreeViews extends Disposable implements MainThreadTreeVie
|
|||
this.extensionService.whenInstalledExtensionsRegistered().then(() => {
|
||||
const dataProvider = new TreeViewDataProvider(treeViewId, this._proxy, this.notificationService);
|
||||
this._dataProviders.set(treeViewId, dataProvider);
|
||||
const dndController = options.canDragAndDrop ? new TreeViewDragAndDropController(treeViewId, this._proxy) : undefined;
|
||||
const viewer = this.getTreeView(treeViewId);
|
||||
if (viewer) {
|
||||
// Order is important here. The internal tree isn't created until the dataProvider is set.
|
||||
// Set all other properties first!
|
||||
viewer.showCollapseAllAction = !!options.showCollapseAll;
|
||||
viewer.canSelectMany = !!options.canSelectMany;
|
||||
viewer.canDragAndDrop = !!options.canDragAndDrop;
|
||||
viewer.dragAndDropController = dndController;
|
||||
viewer.dataProvider = dataProvider;
|
||||
this.registerListeners(treeViewId, viewer);
|
||||
this._proxy.$setVisible(treeViewId, viewer.visible);
|
||||
|
@ -162,6 +163,16 @@ export class MainThreadTreeViews extends Disposable implements MainThreadTreeVie
|
|||
|
||||
type TreeItemHandle = string;
|
||||
|
||||
class TreeViewDragAndDropController implements ITreeViewDragAndDropController {
|
||||
|
||||
constructor(private readonly treeViewId: string,
|
||||
private readonly _proxy: ExtHostTreeViewsShape) { }
|
||||
|
||||
onDrop(treeItem: ITreeItem[], targetTreeItem: ITreeItem): Promise<void> {
|
||||
return this._proxy.$onDrop(this.treeViewId, treeItem.map(item => item.handle), targetTreeItem.handle);
|
||||
}
|
||||
}
|
||||
|
||||
class TreeViewDataProvider implements ITreeViewDataProvider {
|
||||
|
||||
private readonly itemsMap: Map<TreeItemHandle, ITreeItem> = new Map<TreeItemHandle, ITreeItem>();
|
||||
|
@ -184,10 +195,6 @@ class TreeViewDataProvider implements ITreeViewDataProvider {
|
|||
}));
|
||||
}
|
||||
|
||||
setParent(treeItem: ITreeItem[], targetTreeItem: ITreeItem): Promise<void> {
|
||||
return this._proxy.$setParent(this.treeViewId, treeItem.map(item => item.handle), targetTreeItem.handle);
|
||||
}
|
||||
|
||||
getItemsToRefresh(itemsToRefreshByHandle: { [treeItemHandle: string]: ITreeItem }): ITreeItem[] {
|
||||
const itemsToRefresh: ITreeItem[] = [];
|
||||
if (itemsToRefreshByHandle) {
|
||||
|
|
|
@ -78,23 +78,6 @@ export class RemoveFromRecentlyOpenedAPICommand {
|
|||
}
|
||||
CommandsRegistry.registerCommand(RemoveFromRecentlyOpenedAPICommand.ID, adjustHandler(RemoveFromRecentlyOpenedAPICommand.execute));
|
||||
|
||||
export interface OpenIssueReporterArgs {
|
||||
readonly extensionId: string;
|
||||
readonly issueTitle?: string;
|
||||
readonly issueBody?: string;
|
||||
}
|
||||
|
||||
export class OpenIssueReporter {
|
||||
public static readonly ID = 'vscode.openIssueReporter';
|
||||
|
||||
public static execute(executor: ICommandsExecutor, args: string | OpenIssueReporterArgs): Promise<void> {
|
||||
const commandArgs = typeof args === 'string'
|
||||
? { extensionId: args }
|
||||
: args;
|
||||
return executor.executeCommand('workbench.action.openIssueReporter', commandArgs);
|
||||
}
|
||||
}
|
||||
|
||||
interface RecentEntry {
|
||||
uri: URI;
|
||||
type: 'workspace' | 'folder' | 'file';
|
||||
|
|
|
@ -3,7 +3,6 @@
|
|||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import * as nls from 'vs/nls';
|
||||
import { CancellationTokenSource } from 'vs/base/common/cancellation';
|
||||
import * as errors from 'vs/base/common/errors';
|
||||
import { Emitter, Event } from 'vs/base/common/event';
|
||||
|
@ -597,25 +596,21 @@ export function createApiFactoryAndRegisterActors(accessor: ServicesAccessor): I
|
|||
showSaveDialog(options) {
|
||||
return extHostDialogs.showSaveDialog(options);
|
||||
},
|
||||
createStatusBarItem(alignmentOrOptions?: vscode.StatusBarAlignment | vscode.StatusBarItemOptions, priority?: number): vscode.StatusBarItem {
|
||||
let id: string;
|
||||
let name: string;
|
||||
createStatusBarItem(alignmentOrId?: vscode.StatusBarAlignment | string, priorityOrAlignment?: number | vscode.StatusBarAlignment, priorityArg?: number): vscode.StatusBarItem {
|
||||
let id: string | undefined;
|
||||
let alignment: number | undefined;
|
||||
let accessibilityInformation: vscode.AccessibilityInformation | undefined = undefined;
|
||||
let priority: number | undefined;
|
||||
|
||||
if (alignmentOrOptions && typeof alignmentOrOptions !== 'number') {
|
||||
id = alignmentOrOptions.id;
|
||||
name = alignmentOrOptions.name;
|
||||
alignment = alignmentOrOptions.alignment;
|
||||
priority = alignmentOrOptions.priority;
|
||||
accessibilityInformation = alignmentOrOptions.accessibilityInformation;
|
||||
if (typeof alignmentOrId === 'string') {
|
||||
id = alignmentOrId;
|
||||
alignment = priorityOrAlignment;
|
||||
priority = priorityArg;
|
||||
} else {
|
||||
id = extension.identifier.value;
|
||||
name = nls.localize('extensionLabel', "{0} (Extension)", extension.displayName || extension.name);
|
||||
alignment = alignmentOrOptions;
|
||||
alignment = alignmentOrId;
|
||||
priority = priorityOrAlignment;
|
||||
}
|
||||
|
||||
return extHostStatusBar.createStatusBarEntry(id, name, alignment, priority, accessibilityInformation);
|
||||
return extHostStatusBar.createStatusBarEntry(extension, id, alignment, priority);
|
||||
},
|
||||
setStatusBarMessage(text: string, timeoutOrThenable?: number | Thenable<any>): vscode.Disposable {
|
||||
return extHostStatusBar.setStatusBarMessage(text, timeoutOrThenable);
|
||||
|
|
|
@ -1217,7 +1217,7 @@ export interface ExtHostDocumentsAndEditorsShape {
|
|||
|
||||
export interface ExtHostTreeViewsShape {
|
||||
$getChildren(treeViewId: string, treeItemHandle?: string): Promise<ITreeItem[]>;
|
||||
$setParent(treeViewId: string, treeItemHandle: string[], newParentTreeItemHandle: string): Promise<void>;
|
||||
$onDrop(treeViewId: string, treeItemHandle: string[], newParentTreeItemHandle: string): Promise<void>;
|
||||
$setExpanded(treeViewId: string, treeItemHandle: string, expanded: boolean): void;
|
||||
$setSelection(treeViewId: string, treeItemHandles: string[]): void;
|
||||
$setVisible(treeViewId: string, visible: boolean): void;
|
||||
|
@ -1780,6 +1780,7 @@ export interface IDebugSessionFullDto {
|
|||
id: DebugSessionUUID;
|
||||
type: string;
|
||||
name: string;
|
||||
parent: DebugSessionUUID | undefined;
|
||||
folderUri: UriComponents | undefined;
|
||||
configuration: IConfig;
|
||||
}
|
||||
|
|
|
@ -14,7 +14,7 @@ import * as search from 'vs/workbench/contrib/search/common/search';
|
|||
import { ICommandHandlerDescription } from 'vs/platform/commands/common/commands';
|
||||
import { ApiCommand, ApiCommandArgument, ApiCommandResult, ExtHostCommands } from 'vs/workbench/api/common/extHostCommands';
|
||||
import { CustomCodeAction } from 'vs/workbench/api/common/extHostLanguageFeatures';
|
||||
import { ICommandsExecutor, RemoveFromRecentlyOpenedAPICommand, OpenIssueReporter, OpenIssueReporterArgs } from './apiCommands';
|
||||
import { ICommandsExecutor, RemoveFromRecentlyOpenedAPICommand } from './apiCommands';
|
||||
import { isFalsyOrEmpty } from 'vs/base/common/arrays';
|
||||
import { IRange } from 'vs/editor/common/core/range';
|
||||
import { IPosition } from 'vs/editor/common/core/position';
|
||||
|
@ -456,13 +456,6 @@ export class ExtHostApiCommands {
|
|||
{ name: 'path', description: 'Path to remove from recently opened.', constraint: (value: any) => typeof value === 'string' }
|
||||
]
|
||||
});
|
||||
|
||||
this._register(OpenIssueReporter.ID, adjustHandler(OpenIssueReporter.execute), {
|
||||
description: 'Opens the issue reporter with the provided extension id as the selected source',
|
||||
args: [
|
||||
{ name: 'extensionId', description: 'extensionId to report an issue on', constraint: (value: unknown) => typeof value === 'string' || (typeof value === 'object' && typeof (value as OpenIssueReporterArgs).extensionId === 'string') }
|
||||
]
|
||||
});
|
||||
}
|
||||
|
||||
// --- command impl
|
||||
|
|
|
@ -845,7 +845,8 @@ export abstract class ExtHostDebugServiceBase implements IExtHostDebugService, E
|
|||
let ds = this._debugSessions.get(dto.id);
|
||||
if (!ds) {
|
||||
const folder = await this.getFolder(dto.folderUri);
|
||||
ds = new ExtHostDebugSession(this._debugServiceProxy, dto.id, dto.type, dto.name, folder, dto.configuration);
|
||||
const parent = dto.parent ? this._debugSessions.get(dto.parent) : undefined;
|
||||
ds = new ExtHostDebugSession(this._debugServiceProxy, dto.id, dto.type, dto.name, folder, dto.configuration, parent);
|
||||
this._debugSessions.set(ds.id, ds);
|
||||
this._debugServiceProxy.$sessionCached(ds.id);
|
||||
}
|
||||
|
@ -872,7 +873,8 @@ export class ExtHostDebugSession implements vscode.DebugSession {
|
|||
private _type: string,
|
||||
private _name: string,
|
||||
private _workspaceFolder: vscode.WorkspaceFolder | undefined,
|
||||
private _configuration: vscode.DebugConfiguration) {
|
||||
private _configuration: vscode.DebugConfiguration,
|
||||
private _parentSession: vscode.DebugSession | undefined) {
|
||||
}
|
||||
|
||||
public get id(): string {
|
||||
|
@ -886,12 +888,15 @@ export class ExtHostDebugSession implements vscode.DebugSession {
|
|||
public get name(): string {
|
||||
return this._name;
|
||||
}
|
||||
|
||||
public set name(name: string) {
|
||||
this._name = name;
|
||||
this._debugServiceProxy.$setDebugSessionName(this._id, name);
|
||||
}
|
||||
|
||||
public get parentSession(): vscode.DebugSession | undefined {
|
||||
return this._parentSession;
|
||||
}
|
||||
|
||||
_acceptNameChanged(name: string) {
|
||||
this._name = name;
|
||||
}
|
||||
|
|
|
@ -292,19 +292,19 @@ export abstract class AbstractExtHostExtensionService extends Disposable impleme
|
|||
try {
|
||||
if (typeof extension.module.deactivate === 'function') {
|
||||
result = Promise.resolve(extension.module.deactivate()).then(undefined, (err) => {
|
||||
// TODO: Do something with err if this is not the shutdown case
|
||||
this._logService.error(err);
|
||||
return Promise.resolve(undefined);
|
||||
});
|
||||
}
|
||||
} catch (err) {
|
||||
// TODO: Do something with err if this is not the shutdown case
|
||||
this._logService.error(err);
|
||||
}
|
||||
|
||||
// clean up subscriptions
|
||||
try {
|
||||
dispose(extension.subscriptions);
|
||||
} catch (err) {
|
||||
// TODO: Do something with err if this is not the shutdown case
|
||||
this._logService.error(err);
|
||||
}
|
||||
|
||||
return result;
|
||||
|
|
|
@ -56,6 +56,11 @@ export class ExtensionMemento implements vscode.Memento {
|
|||
}, 0);
|
||||
}
|
||||
|
||||
get keys(): readonly string[] {
|
||||
// Filter out `undefined` values, as they can stick around in the `_value` until the `onDidChangeStorage` event runs
|
||||
return Object.entries(this._value ?? {}).filter(([, value]) => value !== undefined).map(([key]) => key);
|
||||
}
|
||||
|
||||
get whenReady(): Promise<ExtensionMemento> {
|
||||
return this._init;
|
||||
}
|
||||
|
|
|
@ -11,7 +11,7 @@ import { ExtHostDocuments } from 'vs/workbench/api/common/extHostDocuments';
|
|||
import { ExtHostDocumentsAndEditors, IExtHostModelAddedData } from 'vs/workbench/api/common/extHostDocumentsAndEditors';
|
||||
import * as extHostTypeConverters from 'vs/workbench/api/common/extHostTypeConverters';
|
||||
import * as extHostTypes from 'vs/workbench/api/common/extHostTypes';
|
||||
import { CellKind, IMainCellDto, IOutputDto, IOutputItemDto, NotebookCellMetadata, NotebookCellsChangedEventDto, NotebookCellsChangeType, NotebookCellsSplice2 } from 'vs/workbench/contrib/notebook/common/notebookCommon';
|
||||
import { CellKind, IMainCellDto, IOutputDto, IOutputItemDto, NotebookCellInternalMetadata, NotebookCellMetadata, NotebookCellsChangedEventDto, NotebookCellsChangeType, NotebookCellsSplice2 } from 'vs/workbench/contrib/notebook/common/notebookCommon';
|
||||
import * as vscode from 'vscode';
|
||||
|
||||
class RawContentChangeEvent {
|
||||
|
@ -48,7 +48,7 @@ export class ExtHostCell {
|
|||
private _metadata: extHostTypes.NotebookCellMetadata;
|
||||
private _previousResult: vscode.NotebookCellExecutionSummary | undefined;
|
||||
|
||||
private _internalMetadata: NotebookCellMetadata;
|
||||
private _internalMetadata: NotebookCellInternalMetadata;
|
||||
readonly handle: number;
|
||||
readonly uri: URI;
|
||||
readonly cellKind: CellKind;
|
||||
|
@ -64,12 +64,12 @@ export class ExtHostCell {
|
|||
this.uri = URI.revive(_cellData.uri);
|
||||
this.cellKind = _cellData.cellKind;
|
||||
this._outputs = _cellData.outputs.map(extHostTypeConverters.NotebookCellOutput.to);
|
||||
this._internalMetadata = _cellData.metadata ?? {};
|
||||
this._metadata = extHostTypeConverters.NotebookCellMetadata.to(this._internalMetadata);
|
||||
this._previousResult = extHostTypeConverters.NotebookCellPreviousExecutionResult.to(this._internalMetadata);
|
||||
this._internalMetadata = _cellData.internalMetadata ?? {};
|
||||
this._metadata = extHostTypeConverters.NotebookCellMetadata.to(_cellData.metadata ?? {});
|
||||
this._previousResult = extHostTypeConverters.NotebookCellExecutionSummary.to(_cellData.internalMetadata ?? {});
|
||||
}
|
||||
|
||||
get internalMetadata(): NotebookCellMetadata {
|
||||
get internalMetadata(): NotebookCellInternalMetadata {
|
||||
return this._internalMetadata;
|
||||
}
|
||||
|
||||
|
@ -109,9 +109,12 @@ export class ExtHostCell {
|
|||
}
|
||||
|
||||
setMetadata(newMetadata: NotebookCellMetadata): void {
|
||||
this._internalMetadata = newMetadata;
|
||||
this._metadata = extHostTypeConverters.NotebookCellMetadata.to(newMetadata);
|
||||
this._previousResult = extHostTypeConverters.NotebookCellPreviousExecutionResult.to(newMetadata);
|
||||
}
|
||||
|
||||
setInternalMetadata(newInternalMetadata: NotebookCellInternalMetadata): void {
|
||||
this._internalMetadata = newInternalMetadata;
|
||||
this._previousResult = extHostTypeConverters.NotebookCellExecutionSummary.to(newInternalMetadata);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -213,6 +216,8 @@ export class ExtHostNotebookDocument {
|
|||
this._changeCellLanguage(rawEvent.index, rawEvent.language);
|
||||
} else if (rawEvent.kind === NotebookCellsChangeType.ChangeCellMetadata) {
|
||||
this._changeCellMetadata(rawEvent.index, rawEvent.metadata);
|
||||
} else if (rawEvent.kind === NotebookCellsChangeType.ChangeCellInternalMetadata) {
|
||||
this._changeCellInternalMetadata(rawEvent.index, rawEvent.internalMetadata);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -334,7 +339,6 @@ export class ExtHostNotebookDocument {
|
|||
private _changeCellMetadata(index: number, newMetadata: NotebookCellMetadata): void {
|
||||
const cell = this._cells[index];
|
||||
|
||||
const originalInternalMetadata = cell.internalMetadata;
|
||||
const originalExtMetadata = cell.apiCell.metadata;
|
||||
cell.setMetadata(newMetadata);
|
||||
const newExtMetadata = cell.apiCell.metadata;
|
||||
|
@ -342,9 +346,16 @@ export class ExtHostNotebookDocument {
|
|||
if (!equals(originalExtMetadata, newExtMetadata)) {
|
||||
this._emitter.emitCellMetadataChange(deepFreeze({ document: this.apiNotebook, cell: cell.apiCell }));
|
||||
}
|
||||
}
|
||||
|
||||
if (originalInternalMetadata.runState !== newMetadata.runState) {
|
||||
const executionState = newMetadata.runState ?? extHostTypes.NotebookCellExecutionState.Idle;
|
||||
private _changeCellInternalMetadata(index: number, newInternalMetadata: NotebookCellInternalMetadata): void {
|
||||
const cell = this._cells[index];
|
||||
|
||||
const originalInternalMetadata = cell.internalMetadata;
|
||||
cell.setInternalMetadata(newInternalMetadata);
|
||||
|
||||
if (originalInternalMetadata.runState !== newInternalMetadata.runState) {
|
||||
const executionState = newInternalMetadata.runState ?? extHostTypes.NotebookCellExecutionState.Idle;
|
||||
this._emitter.emitCellExecutionStateChange(deepFreeze({ document: this.apiNotebook, cell: cell.apiCell, executionState }));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -16,9 +16,8 @@ import { asWebviewUri } from 'vs/workbench/api/common/shared/webview';
|
|||
import { ResourceMap } from 'vs/base/common/map';
|
||||
import { timeout } from 'vs/base/common/async';
|
||||
import { ExtHostCell, ExtHostNotebookDocument } from 'vs/workbench/api/common/extHostNotebookDocument';
|
||||
import { CellEditType, IImmediateCellEditOperation, NullablePartialNotebookCellMetadata } from 'vs/workbench/contrib/notebook/common/notebookCommon';
|
||||
import { CellEditType, IImmediateCellEditOperation, NotebookCellExecutionState, NullablePartialNotebookCellInternalMetadata } from 'vs/workbench/contrib/notebook/common/notebookCommon';
|
||||
import { CancellationTokenSource } from 'vs/base/common/cancellation';
|
||||
import { NotebookCellExecutionState } from 'vs/workbench/api/common/extHostTypes';
|
||||
import { asArray } from 'vs/base/common/arrays';
|
||||
import { ILogService } from 'vs/platform/log/common/log';
|
||||
|
||||
|
@ -373,8 +372,8 @@ class NotebookCellExecutionTask extends Disposable {
|
|||
}
|
||||
}
|
||||
|
||||
private mixinMetadata(mixinMetadata: NullablePartialNotebookCellMetadata) {
|
||||
const edit: IImmediateCellEditOperation = { editType: CellEditType.PartialMetadata, handle: this._cell.handle, metadata: mixinMetadata };
|
||||
private mixinMetadata(mixinMetadata: NullablePartialNotebookCellInternalMetadata) {
|
||||
const edit: IImmediateCellEditOperation = { editType: CellEditType.PartialInternalMetadata, handle: this._cell.handle, internalMetadata: mixinMetadata };
|
||||
this.applyEdits([edit]);
|
||||
}
|
||||
|
||||
|
@ -426,7 +425,7 @@ class NotebookCellExecutionTask extends Disposable {
|
|||
that._onDidChangeState.fire();
|
||||
|
||||
that.mixinMetadata({
|
||||
runState: NotebookCellExecutionState.Idle,
|
||||
runState: null,
|
||||
lastRunSuccess: result?.success ?? null,
|
||||
runEndTime: result?.endTime ?? null,
|
||||
});
|
||||
|
|
|
@ -10,8 +10,10 @@ import { MainContext, MainThreadStatusBarShape, IMainContext, ICommandDto } from
|
|||
import { localize } from 'vs/nls';
|
||||
import { CommandsConverter } from 'vs/workbench/api/common/extHostCommands';
|
||||
import { DisposableStore } from 'vs/base/common/lifecycle';
|
||||
import { IExtensionDescription } from 'vs/platform/extensions/common/extensions';
|
||||
|
||||
export class ExtHostStatusBarEntry implements vscode.StatusBarItem {
|
||||
|
||||
private static ID_GEN = 0;
|
||||
|
||||
private static ALLOWED_BACKGROUND_COLORS = new Map<string, ThemeColor>(
|
||||
|
@ -21,17 +23,20 @@ export class ExtHostStatusBarEntry implements vscode.StatusBarItem {
|
|||
#proxy: MainThreadStatusBarShape;
|
||||
#commands: CommandsConverter;
|
||||
|
||||
private _id: number;
|
||||
private _entryId: number;
|
||||
|
||||
private _extension?: IExtensionDescription;
|
||||
|
||||
private _id?: string;
|
||||
private _alignment: number;
|
||||
private _priority?: number;
|
||||
|
||||
private _disposed: boolean = false;
|
||||
private _visible: boolean = false;
|
||||
|
||||
private _statusId: string;
|
||||
private _statusName: string;
|
||||
|
||||
private _text: string = '';
|
||||
private _tooltip?: string;
|
||||
private _name?: string;
|
||||
private _color?: string | ThemeColor;
|
||||
private _backgroundColor?: ThemeColor;
|
||||
private readonly _internalCommandRegistration = new DisposableStore();
|
||||
|
@ -43,20 +48,23 @@ export class ExtHostStatusBarEntry implements vscode.StatusBarItem {
|
|||
private _timeoutHandle: any;
|
||||
private _accessibilityInformation?: vscode.AccessibilityInformation;
|
||||
|
||||
constructor(proxy: MainThreadStatusBarShape, commands: CommandsConverter, id: string, name: string, alignment: ExtHostStatusBarAlignment = ExtHostStatusBarAlignment.Left, priority?: number, accessibilityInformation?: vscode.AccessibilityInformation) {
|
||||
constructor(proxy: MainThreadStatusBarShape, commands: CommandsConverter, extension: IExtensionDescription, id?: string, alignment?: ExtHostStatusBarAlignment, priority?: number);
|
||||
constructor(proxy: MainThreadStatusBarShape, commands: CommandsConverter, extension: IExtensionDescription | undefined, id: string, alignment?: ExtHostStatusBarAlignment, priority?: number);
|
||||
constructor(proxy: MainThreadStatusBarShape, commands: CommandsConverter, extension?: IExtensionDescription, id?: string, alignment: ExtHostStatusBarAlignment = ExtHostStatusBarAlignment.Left, priority?: number) {
|
||||
this.#proxy = proxy;
|
||||
this.#commands = commands;
|
||||
|
||||
this._id = ExtHostStatusBarEntry.ID_GEN++;
|
||||
this._statusId = id;
|
||||
this._statusName = name;
|
||||
this._entryId = ExtHostStatusBarEntry.ID_GEN++;
|
||||
|
||||
this._extension = extension;
|
||||
|
||||
this._id = id;
|
||||
this._alignment = alignment;
|
||||
this._priority = priority;
|
||||
this._accessibilityInformation = accessibilityInformation;
|
||||
}
|
||||
|
||||
public get id(): number {
|
||||
return this._id;
|
||||
public get id(): string {
|
||||
return this._id ?? this._extension!.identifier.value;
|
||||
}
|
||||
|
||||
public get alignment(): vscode.StatusBarAlignment {
|
||||
|
@ -71,6 +79,10 @@ export class ExtHostStatusBarEntry implements vscode.StatusBarItem {
|
|||
return this._text;
|
||||
}
|
||||
|
||||
public get name(): string | undefined {
|
||||
return this._name;
|
||||
}
|
||||
|
||||
public get tooltip(): string | undefined {
|
||||
return this._tooltip;
|
||||
}
|
||||
|
@ -96,6 +108,11 @@ export class ExtHostStatusBarEntry implements vscode.StatusBarItem {
|
|||
this.update();
|
||||
}
|
||||
|
||||
public set name(name: string | undefined) {
|
||||
this._name = name;
|
||||
this.update();
|
||||
}
|
||||
|
||||
public set tooltip(tooltip: string | undefined) {
|
||||
this._tooltip = tooltip;
|
||||
this.update();
|
||||
|
@ -150,7 +167,7 @@ export class ExtHostStatusBarEntry implements vscode.StatusBarItem {
|
|||
public hide(): void {
|
||||
clearTimeout(this._timeoutHandle);
|
||||
this._visible = false;
|
||||
this.#proxy.$dispose(this.id);
|
||||
this.#proxy.$dispose(this._entryId);
|
||||
}
|
||||
|
||||
private update(): void {
|
||||
|
@ -164,6 +181,28 @@ export class ExtHostStatusBarEntry implements vscode.StatusBarItem {
|
|||
this._timeoutHandle = setTimeout(() => {
|
||||
this._timeoutHandle = undefined;
|
||||
|
||||
// If the id is not set, derive it from the extension identifier,
|
||||
// otherwise make sure to prefix it with the extension identifier
|
||||
// to get a more unique value across extensions.
|
||||
let id: string;
|
||||
if (this._extension) {
|
||||
if (this._id) {
|
||||
id = `${this._extension.identifier.value}.${this._id}`;
|
||||
} else {
|
||||
id = this._extension.identifier.value;
|
||||
}
|
||||
} else {
|
||||
id = this._id!;
|
||||
}
|
||||
|
||||
// If the name is not set, derive it from the extension descriptor
|
||||
let name: string;
|
||||
if (this._name) {
|
||||
name = this._name;
|
||||
} else {
|
||||
name = localize('extensionLabel', "{0} (Extension)", this._extension!.displayName || this._extension!.name);
|
||||
}
|
||||
|
||||
// If a background color is set, the foreground is determined
|
||||
let color = this._color;
|
||||
if (this._backgroundColor) {
|
||||
|
@ -171,7 +210,7 @@ export class ExtHostStatusBarEntry implements vscode.StatusBarItem {
|
|||
}
|
||||
|
||||
// Set to status bar
|
||||
this.#proxy.$setEntry(this.id, this._statusId, this._statusName, this._text, this._tooltip, this._command?.internal, color,
|
||||
this.#proxy.$setEntry(this._entryId, id, name, this._text, this._tooltip, this._command?.internal, color,
|
||||
this._backgroundColor, this._alignment === ExtHostStatusBarAlignment.Left ? MainThreadStatusBarAlignment.LEFT : MainThreadStatusBarAlignment.RIGHT,
|
||||
this._priority, this._accessibilityInformation);
|
||||
}, 0);
|
||||
|
@ -189,7 +228,8 @@ class StatusBarMessage {
|
|||
private _messages: { message: string }[] = [];
|
||||
|
||||
constructor(statusBar: ExtHostStatusBar) {
|
||||
this._item = statusBar.createStatusBarEntry('status.extensionMessage', localize('status.extensionMessage', "Extension Status"), ExtHostStatusBarAlignment.Left, Number.MIN_VALUE);
|
||||
this._item = statusBar.createStatusBarEntry(undefined, 'status.extensionMessage', ExtHostStatusBarAlignment.Left, Number.MIN_VALUE);
|
||||
this._item.name = localize('status.extensionMessage', "Extension Status");
|
||||
}
|
||||
|
||||
dispose() {
|
||||
|
@ -233,12 +273,13 @@ export class ExtHostStatusBar {
|
|||
this._statusMessage = new StatusBarMessage(this);
|
||||
}
|
||||
|
||||
createStatusBarEntry(id: string, name: string, alignment?: ExtHostStatusBarAlignment, priority?: number, accessibilityInformation?: vscode.AccessibilityInformation): vscode.StatusBarItem {
|
||||
return new ExtHostStatusBarEntry(this._proxy, this._commands, id, name, alignment, priority, accessibilityInformation);
|
||||
createStatusBarEntry(extension: IExtensionDescription | undefined, id: string, alignment?: ExtHostStatusBarAlignment, priority?: number): vscode.StatusBarItem;
|
||||
createStatusBarEntry(extension: IExtensionDescription, id?: string, alignment?: ExtHostStatusBarAlignment, priority?: number): vscode.StatusBarItem;
|
||||
createStatusBarEntry(extension: IExtensionDescription, id: string, alignment?: ExtHostStatusBarAlignment, priority?: number): vscode.StatusBarItem {
|
||||
return new ExtHostStatusBarEntry(this._proxy, this._commands, extension, id, alignment, priority);
|
||||
}
|
||||
|
||||
setStatusBarMessage(text: string, timeoutOrThenable?: number | Thenable<any>): Disposable {
|
||||
|
||||
const d = this._statusMessage.setMessage(text);
|
||||
let handle: any;
|
||||
|
||||
|
|
|
@ -18,7 +18,7 @@ import { serializeEnvironmentVariableCollection } from 'vs/workbench/contrib/ter
|
|||
import { CancellationTokenSource } from 'vs/base/common/cancellation';
|
||||
import { generateUuid } from 'vs/base/common/uuid';
|
||||
import { ISerializableEnvironmentVariableCollection } from 'vs/workbench/contrib/terminal/common/environmentVariable';
|
||||
import { IShellLaunchConfigDto, ITerminalChildProcess, ITerminalDimensionsOverride, ITerminalEnvironment, ITerminalLaunchError, ITerminalProfile, TerminalShellType } from 'vs/platform/terminal/common/terminal';
|
||||
import { IProcessReadyEvent, IShellLaunchConfigDto, ITerminalChildProcess, ITerminalDimensionsOverride, ITerminalEnvironment, ITerminalLaunchError, ITerminalProfile, TerminalShellType } from 'vs/platform/terminal/common/terminal';
|
||||
import { TerminalDataBufferer } from 'vs/platform/terminal/common/terminalDataBuffering';
|
||||
|
||||
export interface IExtHostTerminalService extends ExtHostTerminalServiceShape, IDisposable {
|
||||
|
@ -193,8 +193,8 @@ export class ExtHostPseudoterminal implements ITerminalChildProcess {
|
|||
public readonly onProcessData: Event<string> = this._onProcessData.event;
|
||||
private readonly _onProcessExit = new Emitter<number | undefined>();
|
||||
public readonly onProcessExit: Event<number | undefined> = this._onProcessExit.event;
|
||||
private readonly _onProcessReady = new Emitter<{ pid: number, cwd: string }>();
|
||||
public get onProcessReady(): Event<{ pid: number, cwd: string }> { return this._onProcessReady.event; }
|
||||
private readonly _onProcessReady = new Emitter<IProcessReadyEvent>();
|
||||
public get onProcessReady(): Event<IProcessReadyEvent> { return this._onProcessReady.event; }
|
||||
private readonly _onProcessTitleChanged = new Emitter<string>();
|
||||
public readonly onProcessTitleChanged: Event<string> = this._onProcessTitleChanged.event;
|
||||
private readonly _onProcessOverrideDimensions = new Emitter<ITerminalDimensionsOverride | undefined>();
|
||||
|
|
|
@ -84,7 +84,8 @@ export class ExtHostTreeViews implements ExtHostTreeViewsShape {
|
|||
if (!options || !options.treeDataProvider) {
|
||||
throw new Error('Options with treeDataProvider is mandatory');
|
||||
}
|
||||
const registerPromise = this._proxy.$registerTreeViewDataProvider(viewId, { showCollapseAll: !!options.showCollapseAll, canSelectMany: !!options.canSelectMany, canDragAndDrop: !!options.canDragAndDrop });
|
||||
const canDragAndDrop = options.dragAndDropController !== undefined;
|
||||
const registerPromise = this._proxy.$registerTreeViewDataProvider(viewId, { showCollapseAll: !!options.showCollapseAll, canSelectMany: !!options.canSelectMany, canDragAndDrop: canDragAndDrop });
|
||||
const treeView = this.createExtHostTreeView(viewId, options, extension);
|
||||
return {
|
||||
get onDidCollapseElement() { return treeView.onDidCollapseElement; },
|
||||
|
@ -127,12 +128,12 @@ export class ExtHostTreeViews implements ExtHostTreeViewsShape {
|
|||
return treeView.getChildren(treeItemHandle);
|
||||
}
|
||||
|
||||
$setParent(treeViewId: string, treeItemHandles: string[], newParentItemHandle: string): Promise<void> {
|
||||
$onDrop(treeViewId: string, treeItemHandles: string[], newParentItemHandle: string): Promise<void> {
|
||||
const treeView = this.treeViews.get(treeViewId);
|
||||
if (!treeView) {
|
||||
return Promise.reject(new Error(localize('treeView.notRegistered', 'No tree view with id \'{0}\' registered.', treeViewId)));
|
||||
}
|
||||
return treeView.setParent(treeItemHandles, newParentItemHandle);
|
||||
return treeView.onDrop(treeItemHandles, newParentItemHandle);
|
||||
}
|
||||
|
||||
async $hasResolve(treeViewId: string): Promise<boolean> {
|
||||
|
@ -204,6 +205,7 @@ class ExtHostTreeView<T> extends Disposable {
|
|||
private static readonly ID_HANDLE_PREFIX = '1';
|
||||
|
||||
private readonly dataProvider: vscode.TreeDataProvider<T>;
|
||||
private readonly dndController: vscode.DragAndDropController<T> | undefined;
|
||||
|
||||
private roots: TreeNode[] | null = null;
|
||||
private elements: Map<TreeItemHandle, T> = new Map<TreeItemHandle, T>();
|
||||
|
@ -250,6 +252,7 @@ class ExtHostTreeView<T> extends Disposable {
|
|||
}
|
||||
}
|
||||
this.dataProvider = options.treeDataProvider;
|
||||
this.dndController = options.dragAndDropController;
|
||||
if (this.dataProvider.onDidChangeTreeData) {
|
||||
this._register(this.dataProvider.onDidChangeTreeData(element => this._onDidChangeData.fire({ message: false, element })));
|
||||
}
|
||||
|
@ -377,11 +380,11 @@ class ExtHostTreeView<T> extends Disposable {
|
|||
}
|
||||
}
|
||||
|
||||
setParent(treeItemHandleOrNodes: TreeItemHandle[], newParentHandleOrNode: TreeItemHandle): Promise<void> {
|
||||
onDrop(treeItemHandleOrNodes: TreeItemHandle[], targetHandleOrNode: TreeItemHandle): Promise<void> {
|
||||
const elements = <T[]>treeItemHandleOrNodes.map(item => this.getExtensionElement(item)).filter(element => !isUndefinedOrNull(element));
|
||||
const newParentElement = this.getExtensionElement(newParentHandleOrNode);
|
||||
if (this.dataProvider.setParent && elements && newParentElement) {
|
||||
return asPromise(() => this.dataProvider.setParent!(elements, newParentElement));
|
||||
const target = this.getExtensionElement(targetHandleOrNode);
|
||||
if (elements && target) {
|
||||
return asPromise(() => this.dndController?.onDrop(elements, target));
|
||||
}
|
||||
return Promise.resolve(undefined);
|
||||
}
|
||||
|
|
|
@ -1443,8 +1443,8 @@ export namespace NotebookDocumentMetadata {
|
|||
}
|
||||
}
|
||||
|
||||
export namespace NotebookCellPreviousExecutionResult {
|
||||
export function to(data: notebooks.NotebookCellMetadata): vscode.NotebookCellExecutionSummary {
|
||||
export namespace NotebookCellExecutionSummary {
|
||||
export function to(data: notebooks.NotebookCellInternalMetadata): vscode.NotebookCellExecutionSummary {
|
||||
return {
|
||||
startTime: data.runStartTime,
|
||||
endTime: data.runEndTime,
|
||||
|
@ -1453,7 +1453,7 @@ export namespace NotebookCellPreviousExecutionResult {
|
|||
};
|
||||
}
|
||||
|
||||
export function from(data: vscode.NotebookCellExecutionSummary): Partial<notebooks.NotebookCellMetadata> {
|
||||
export function from(data: vscode.NotebookCellExecutionSummary): Partial<notebooks.NotebookCellInternalMetadata> {
|
||||
return {
|
||||
lastRunSuccess: data.success,
|
||||
runStartTime: data.startTime,
|
||||
|
@ -1492,10 +1492,8 @@ export namespace NotebookCellData {
|
|||
cellKind: NotebookCellKind.from(data.kind),
|
||||
language: data.languageId,
|
||||
source: data.value,
|
||||
metadata: {
|
||||
...data.metadata,
|
||||
...NotebookCellPreviousExecutionResult.from(data.executionSummary ?? {})
|
||||
},
|
||||
metadata: data.metadata,
|
||||
internalMetadata: NotebookCellExecutionSummary.from(data.executionSummary ?? {}),
|
||||
outputs: data.outputs ? data.outputs.map(NotebookCellOutput.from) : []
|
||||
};
|
||||
}
|
||||
|
@ -1642,15 +1640,7 @@ export namespace NotebookDocumentContentOptions {
|
|||
export function from(options: vscode.NotebookDocumentContentOptions | undefined): notebooks.TransientOptions {
|
||||
return {
|
||||
transientOutputs: options?.transientOutputs ?? false,
|
||||
transientCellMetadata: {
|
||||
...options?.transientCellMetadata,
|
||||
executionOrder: true,
|
||||
runState: true,
|
||||
runStartTime: true,
|
||||
runStartTimeAdjustment: true,
|
||||
runEndTime: true,
|
||||
lastRunSuccess: true
|
||||
},
|
||||
transientCellMetadata: options?.transientCellMetadata ?? {},
|
||||
transientDocumentMetadata: options?.transientDocumentMetadata ?? {}
|
||||
};
|
||||
}
|
||||
|
|
|
@ -182,6 +182,12 @@ const apiMenus: IAPIMenu[] = [
|
|||
description: localize('notebook.toolbar', "The contributed notebook toolbar menu"),
|
||||
proposed: true
|
||||
},
|
||||
{
|
||||
key: 'notebook/toolbar/right',
|
||||
id: MenuId.NotebookRightToolbar,
|
||||
description: localize('notebook.toolbar.right', "The contributed notebook right toolbar menu"),
|
||||
proposed: true
|
||||
},
|
||||
{
|
||||
key: 'notebook/cell/title',
|
||||
id: MenuId.NotebookCellTitle,
|
||||
|
|
|
@ -32,6 +32,7 @@ class OutputAppender {
|
|||
|
||||
append(content: string): void {
|
||||
this.appender.critical(content);
|
||||
this.flush();
|
||||
}
|
||||
|
||||
flush(): void {
|
||||
|
|
|
@ -319,7 +319,8 @@ MenuRegistry.appendMenuItem(MenuId.MenubarFileMenu, {
|
|||
MenuRegistry.appendMenuItem(MenuId.CommandPalette, {
|
||||
command: {
|
||||
id: OpenWorkspaceConfigFileAction.ID,
|
||||
title: { value: `${workspacesCategory}: ${OpenWorkspaceConfigFileAction.LABEL}`, original: 'Workspaces: Open Workspace Configuration File' },
|
||||
title: { value: OpenWorkspaceConfigFileAction.LABEL, original: 'Workspaces: Open Workspace Configuration File' },
|
||||
category: workspacesCategory
|
||||
},
|
||||
when: WorkbenchStateContext.isEqualTo('workspace')
|
||||
});
|
||||
|
|
|
@ -232,11 +232,11 @@ export class ResourcesDropHandler {
|
|||
private async handleDirtyEditorDrop(droppedDirtyEditor: IDraggedEditor): Promise<boolean> {
|
||||
const fileEditorFactory = Registry.as<IEditorInputFactoryRegistry>(EditorExtensions.EditorInputFactories).getFileEditorInputFactory();
|
||||
|
||||
// Untitled: always ensure that we open a new untitled editor for each file we drop
|
||||
// Untitled: always ensure that we open a new untitled text editor for each file we drop
|
||||
if (droppedDirtyEditor.resource.scheme === Schemas.untitled) {
|
||||
const untitledEditorResource = this.editorService.createEditorInput({ mode: droppedDirtyEditor.mode, encoding: droppedDirtyEditor.encoding, forceUntitled: true }).resource;
|
||||
if (untitledEditorResource) {
|
||||
droppedDirtyEditor.resource = untitledEditorResource;
|
||||
const untitledTextEditorResource = this.editorService.createEditorInput({ mode: droppedDirtyEditor.mode, encoding: droppedDirtyEditor.encoding, forceUntitled: true }).resource;
|
||||
if (untitledTextEditorResource) {
|
||||
droppedDirtyEditor.resource = untitledTextEditorResource;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1231,6 +1231,10 @@ export abstract class Layout extends Disposable implements IWorkbenchLayoutServi
|
|||
this.storageService.store(Storage.PANEL_SIZE, panelSize, StorageScope.GLOBAL, StorageTarget.MACHINE);
|
||||
this.storageService.store(Storage.PANEL_DIMENSION, positionToString(this.state.panel.position), StorageScope.GLOBAL, StorageTarget.MACHINE);
|
||||
|
||||
// Remember last panel size for both dimensions
|
||||
this.storageService.store(Storage.PANEL_LAST_NON_MAXIMIZED_HEIGHT, this.state.panel.lastNonMaximizedHeight, StorageScope.GLOBAL, StorageTarget.MACHINE);
|
||||
this.storageService.store(Storage.PANEL_LAST_NON_MAXIMIZED_WIDTH, this.state.panel.lastNonMaximizedWidth, StorageScope.GLOBAL, StorageTarget.MACHINE);
|
||||
|
||||
const gridSize = grid.getViewSize();
|
||||
this.storageService.store(Storage.GRID_WIDTH, gridSize.width, StorageScope.GLOBAL, StorageTarget.MACHINE);
|
||||
this.storageService.store(Storage.GRID_HEIGHT, gridSize.height, StorageScope.GLOBAL, StorageTarget.MACHINE);
|
||||
|
@ -1362,6 +1366,10 @@ export abstract class Layout extends Disposable implements IWorkbenchLayoutServi
|
|||
this.workbenchGrid.setViewVisible(this.activityBarPartView, !hidden);
|
||||
}
|
||||
|
||||
setBannerHidden(hidden: boolean): void {
|
||||
this.workbenchGrid.setViewVisible(this.bannerPartView, !hidden);
|
||||
}
|
||||
|
||||
setEditorHidden(hidden: boolean, skipLayout?: boolean): void {
|
||||
this.state.editor.hidden = hidden;
|
||||
|
||||
|
@ -1802,7 +1810,8 @@ export abstract class Layout extends Disposable implements IWorkbenchLayoutServi
|
|||
{
|
||||
type: 'leaf',
|
||||
data: { type: Parts.BANNER_PART },
|
||||
size: bannerHeight
|
||||
size: bannerHeight,
|
||||
visible: false
|
||||
},
|
||||
{
|
||||
type: 'branch',
|
||||
|
|
|
@ -1,33 +0,0 @@
|
|||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import { localize } from 'vs/nls';
|
||||
import { Action2, registerAction2 } from 'vs/platform/actions/common/actions';
|
||||
import { ServicesAccessor } from 'vs/platform/instantiation/common/instantiation';
|
||||
import { CATEGORIES } from 'vs/workbench/common/actions';
|
||||
import { IWorkbenchLayoutService, Parts } from 'vs/workbench/services/layout/browser/layoutService';
|
||||
|
||||
|
||||
class FocusBannerAction extends Action2 {
|
||||
|
||||
static readonly ID = 'workbench.action.focusBanner';
|
||||
static readonly LABEL = localize('focusBanner', "Focus Banner");
|
||||
|
||||
constructor() {
|
||||
super({
|
||||
id: FocusBannerAction.ID,
|
||||
title: { value: FocusBannerAction.LABEL, original: 'Focus Banner' },
|
||||
category: CATEGORIES.View,
|
||||
f1: true
|
||||
});
|
||||
}
|
||||
|
||||
async run(accessor: ServicesAccessor): Promise<void> {
|
||||
const layoutService = accessor.get(IWorkbenchLayoutService);
|
||||
layoutService.focusPart(Parts.BANNER_PART);
|
||||
}
|
||||
}
|
||||
|
||||
registerAction2(FocusBannerAction);
|
|
@ -4,23 +4,28 @@
|
|||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import 'vs/css!./media/bannerpart';
|
||||
import { $, append, clearNode } from 'vs/base/browser/dom';
|
||||
import { localize } from 'vs/nls';
|
||||
import { $, addDisposableListener, append, clearNode, EventType } from 'vs/base/browser/dom';
|
||||
import { ActionBar } from 'vs/base/browser/ui/actionbar/actionbar';
|
||||
import { Codicon, registerCodicon } from 'vs/base/common/codicons';
|
||||
import { registerSingleton } from 'vs/platform/instantiation/common/extensions';
|
||||
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
|
||||
import { IInstantiationService, ServicesAccessor } from 'vs/platform/instantiation/common/instantiation';
|
||||
import { IStorageService, StorageTarget } from 'vs/platform/storage/common/storage';
|
||||
import { IThemeService, registerThemingParticipant } from 'vs/platform/theme/common/themeService';
|
||||
import { Part } from 'vs/workbench/browser/part';
|
||||
import { IWorkbenchLayoutService, Parts } from 'vs/workbench/services/layout/browser/layoutService';
|
||||
import { Action } from 'vs/base/common/actions';
|
||||
import { Link } from 'vs/platform/opener/browser/link';
|
||||
import { attachLinkStyler } from 'vs/platform/theme/common/styler';
|
||||
import { MarkdownString } from 'vs/base/common/htmlContent';
|
||||
import { Emitter } from 'vs/base/common/event';
|
||||
import { IBannerItem, IBannerService } from 'vs/workbench/services/banner/browser/bannerService';
|
||||
import { MarkdownRenderer } from 'vs/editor/browser/core/markdownRenderer';
|
||||
import { BANNER_BACKGROUND, BANNER_FOREGROUND, BANNER_ICON_FOREGROUND } from 'vs/workbench/common/theme';
|
||||
import { Action2, registerAction2 } from 'vs/platform/actions/common/actions';
|
||||
import { CATEGORIES } from 'vs/workbench/common/actions';
|
||||
import { KeybindingsRegistry, KeybindingWeight } from 'vs/platform/keybinding/common/keybindingsRegistry';
|
||||
import { KeyCode } from 'vs/base/common/keyCodes';
|
||||
import { IContextKeyService, RawContextKey } from 'vs/platform/contextkey/common/contextkey';
|
||||
|
||||
|
||||
// Icons
|
||||
|
@ -32,18 +37,21 @@ const bannerCloseIcon = registerCodicon('banner-close', Codicon.close);
|
|||
|
||||
registerThemingParticipant((theme, collector) => {
|
||||
const backgroundColor = theme.getColor(BANNER_BACKGROUND);
|
||||
const foregroundColor = theme.getColor(BANNER_FOREGROUND);
|
||||
const iconForegroundColor = theme.getColor(BANNER_ICON_FOREGROUND);
|
||||
|
||||
if (backgroundColor) {
|
||||
collector.addRule(`.monaco-workbench .part.banner { background-color: ${backgroundColor}; }`);
|
||||
}
|
||||
|
||||
const foregroundColor = theme.getColor(BANNER_FOREGROUND);
|
||||
if (foregroundColor) {
|
||||
collector.addRule(`.monaco-workbench .part.banner { color: ${foregroundColor}; }`);
|
||||
collector.addRule(`.monaco-workbench .part.banner .action-container .codicon { color: ${foregroundColor}; }`);
|
||||
collector.addRule(`
|
||||
.monaco-workbench .part.banner,
|
||||
.monaco-workbench .part.banner .action-container .codicon,
|
||||
.monaco-workbench .part.banner .message-actions-container .monaco-link
|
||||
{ color: ${foregroundColor}; }
|
||||
`);
|
||||
}
|
||||
|
||||
const iconForegroundColor = theme.getColor(BANNER_ICON_FOREGROUND);
|
||||
if (iconForegroundColor) {
|
||||
collector.addRule(`.monaco-workbench .part.banner .icon-container .codicon { color: ${iconForegroundColor} }`);
|
||||
}
|
||||
|
@ -52,6 +60,8 @@ registerThemingParticipant((theme, collector) => {
|
|||
|
||||
// Banner Part
|
||||
|
||||
const CONTEXT_BANNER_FOCUSED = new RawContextKey<boolean>('bannerFocused', false, localize('bannerFocused', "Whether the banner has keyboard focus"));
|
||||
|
||||
export class BannerPart extends Part implements IBannerService {
|
||||
declare readonly _serviceBrand: undefined;
|
||||
|
||||
|
@ -79,9 +89,14 @@ export class BannerPart extends Part implements IBannerService {
|
|||
private readonly markdownRenderer: MarkdownRenderer;
|
||||
private visible = false;
|
||||
|
||||
private actionBar: ActionBar | undefined;
|
||||
private messageActionsContainer: HTMLElement | undefined;
|
||||
private focusedActionIndex: number = -1;
|
||||
|
||||
constructor(
|
||||
@IThemeService themeService: IThemeService,
|
||||
@IWorkbenchLayoutService layoutService: IWorkbenchLayoutService,
|
||||
@IContextKeyService private readonly contextKeyService: IContextKeyService,
|
||||
@IInstantiationService private readonly instantiationService: IInstantiationService,
|
||||
@IStorageService private readonly storageService: IStorageService,
|
||||
) {
|
||||
|
@ -92,6 +107,19 @@ export class BannerPart extends Part implements IBannerService {
|
|||
|
||||
override createContentArea(parent: HTMLElement): HTMLElement {
|
||||
this.element = parent;
|
||||
this.element.tabIndex = 0;
|
||||
|
||||
// Restore focused action if needed
|
||||
this._register(addDisposableListener(this.element, EventType.FOCUS, () => {
|
||||
if (this.focusedActionIndex !== -1) {
|
||||
this.focusActionLink();
|
||||
}
|
||||
}));
|
||||
|
||||
// Track focus
|
||||
const scopedContextKeyService = this.contextKeyService.createScoped(this.element);
|
||||
CONTEXT_BANNER_FOCUSED.bindTo(scopedContextKeyService).set(true);
|
||||
|
||||
return this.element;
|
||||
}
|
||||
|
||||
|
@ -110,6 +138,31 @@ export class BannerPart extends Part implements IBannerService {
|
|||
this.item = undefined;
|
||||
}
|
||||
|
||||
private focusActionLink(): void {
|
||||
const length = this.item?.actions?.length ?? 0;
|
||||
|
||||
if (this.focusedActionIndex < length) {
|
||||
const actionLink = this.messageActionsContainer?.children[this.focusedActionIndex];
|
||||
if (actionLink instanceof HTMLElement) {
|
||||
this.actionBar?.setFocusable(false);
|
||||
actionLink.focus();
|
||||
}
|
||||
} else {
|
||||
this.actionBar?.focus(0);
|
||||
}
|
||||
}
|
||||
|
||||
private getAriaLabel(item: IBannerItem): string | undefined {
|
||||
if (item.ariaLabel) {
|
||||
return item.ariaLabel;
|
||||
}
|
||||
if (typeof item.message === 'string') {
|
||||
return item.message;
|
||||
}
|
||||
|
||||
return undefined;
|
||||
}
|
||||
|
||||
private getBannerMessage(message: MarkdownString | string): HTMLElement {
|
||||
if (typeof message === 'string') {
|
||||
const element = $('span');
|
||||
|
@ -123,11 +176,32 @@ export class BannerPart extends Part implements IBannerService {
|
|||
private setVisibility(visible: boolean): void {
|
||||
if (visible !== this.visible) {
|
||||
this.visible = visible;
|
||||
this.focusedActionIndex = -1;
|
||||
|
||||
this.layoutService.setBannerHidden(!visible);
|
||||
this._onDidChangeSize.fire(undefined);
|
||||
}
|
||||
}
|
||||
|
||||
focus(): void {
|
||||
this.focusedActionIndex = -1;
|
||||
this.element.focus();
|
||||
}
|
||||
|
||||
focusNextAction(): void {
|
||||
const length = this.item?.actions?.length ?? 0;
|
||||
this.focusedActionIndex = this.focusedActionIndex < length ? this.focusedActionIndex + 1 : 0;
|
||||
|
||||
this.focusActionLink();
|
||||
}
|
||||
|
||||
focusPreviousAction(): void {
|
||||
const length = this.item?.actions?.length ?? 0;
|
||||
this.focusedActionIndex = this.focusedActionIndex > 0 ? this.focusedActionIndex - 1 : length;
|
||||
|
||||
this.focusActionLink();
|
||||
}
|
||||
|
||||
hide(id: string): void {
|
||||
if (this.item?.id !== id) {
|
||||
return;
|
||||
|
@ -149,30 +223,40 @@ export class BannerPart extends Part implements IBannerService {
|
|||
// Clear previous item
|
||||
clearNode(this.element);
|
||||
|
||||
// Banner aria label
|
||||
const ariaLabel = this.getAriaLabel(item);
|
||||
if (ariaLabel) {
|
||||
this.element.setAttribute('aria-label', ariaLabel);
|
||||
}
|
||||
|
||||
// Icon
|
||||
const iconContainer = append(this.element, $('div.icon-container'));
|
||||
iconContainer.setAttribute('aria-hidden', 'true');
|
||||
iconContainer.appendChild($(`div${item.icon.cssSelector}`));
|
||||
|
||||
// Message
|
||||
const messageContainer = append(this.element, $('div.message-container'));
|
||||
messageContainer.setAttribute('aria-hidden', 'true');
|
||||
messageContainer.appendChild(this.getBannerMessage(item.message));
|
||||
|
||||
// Message Actions
|
||||
if (item.actions) {
|
||||
const actionContainer = append(this.element, $('div.message-actions-container'));
|
||||
this.messageActionsContainer = append(this.element, $('div.message-actions-container'));
|
||||
|
||||
for (const action of item.actions) {
|
||||
const actionLink = this._register(this.instantiationService.createInstance(Link, action, {}));
|
||||
this._register(attachLinkStyler(actionLink, this.themeService, { textLinkForeground: BANNER_FOREGROUND }));
|
||||
actionContainer.appendChild(actionLink.el);
|
||||
actionLink.el.tabIndex = -1;
|
||||
actionLink.el.setAttribute('role', 'button');
|
||||
this.messageActionsContainer.appendChild(actionLink.el);
|
||||
}
|
||||
}
|
||||
|
||||
// Action
|
||||
const actionBarContainer = append(this.element, $('div.action-container'));
|
||||
const actionBar = this._register(new ActionBar(actionBarContainer));
|
||||
this.actionBar = this._register(new ActionBar(actionBarContainer));
|
||||
const closeAction = this._register(new Action('banner.close', 'Close Banner', bannerCloseIcon.classNames, true, () => this.close(item)));
|
||||
actionBar.push(closeAction, { icon: true, label: false });
|
||||
this.actionBar.push(closeAction, { icon: true, label: false });
|
||||
this.actionBar.setFocusable(false);
|
||||
|
||||
this.setVisibility(true);
|
||||
this.item = item;
|
||||
|
@ -186,3 +270,66 @@ export class BannerPart extends Part implements IBannerService {
|
|||
}
|
||||
|
||||
registerSingleton(IBannerService, BannerPart);
|
||||
|
||||
|
||||
// Keybindings
|
||||
|
||||
KeybindingsRegistry.registerCommandAndKeybindingRule({
|
||||
id: 'workbench.banner.focusBanner',
|
||||
weight: KeybindingWeight.WorkbenchContrib,
|
||||
primary: KeyCode.Escape,
|
||||
when: CONTEXT_BANNER_FOCUSED,
|
||||
handler: (accessor: ServicesAccessor) => {
|
||||
const bannerService = accessor.get(IBannerService);
|
||||
bannerService.focus();
|
||||
}
|
||||
});
|
||||
|
||||
KeybindingsRegistry.registerCommandAndKeybindingRule({
|
||||
id: 'workbench.banner.focusNextAction',
|
||||
weight: KeybindingWeight.WorkbenchContrib,
|
||||
primary: KeyCode.RightArrow,
|
||||
secondary: [KeyCode.DownArrow],
|
||||
when: CONTEXT_BANNER_FOCUSED,
|
||||
handler: (accessor: ServicesAccessor) => {
|
||||
const bannerService = accessor.get(IBannerService);
|
||||
bannerService.focusNextAction();
|
||||
}
|
||||
});
|
||||
|
||||
KeybindingsRegistry.registerCommandAndKeybindingRule({
|
||||
id: 'workbench.banner.focusPreviousAction',
|
||||
weight: KeybindingWeight.WorkbenchContrib,
|
||||
primary: KeyCode.LeftArrow,
|
||||
secondary: [KeyCode.UpArrow],
|
||||
when: CONTEXT_BANNER_FOCUSED,
|
||||
handler: (accessor: ServicesAccessor) => {
|
||||
const bannerService = accessor.get(IBannerService);
|
||||
bannerService.focusPreviousAction();
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
// Actions
|
||||
|
||||
class FocusBannerAction extends Action2 {
|
||||
|
||||
static readonly ID = 'workbench.action.focusBanner';
|
||||
static readonly LABEL = localize('focusBanner', "Focus Banner");
|
||||
|
||||
constructor() {
|
||||
super({
|
||||
id: FocusBannerAction.ID,
|
||||
title: { value: FocusBannerAction.LABEL, original: 'Focus Banner' },
|
||||
category: CATEGORIES.View,
|
||||
f1: true
|
||||
});
|
||||
}
|
||||
|
||||
async run(accessor: ServicesAccessor): Promise<void> {
|
||||
const layoutService = accessor.get(IWorkbenchLayoutService);
|
||||
layoutService.focusPart(Parts.BANNER_PART);
|
||||
}
|
||||
}
|
||||
|
||||
registerAction2(FocusBannerAction);
|
||||
|
|
|
@ -7,7 +7,7 @@
|
|||
box-sizing: border-box;
|
||||
cursor: default;
|
||||
width: 100%;
|
||||
height: 26px;
|
||||
height: 100%;
|
||||
font-size: 12px;
|
||||
display: flex;
|
||||
overflow: visible;
|
||||
|
@ -38,6 +38,7 @@
|
|||
}
|
||||
|
||||
.monaco-workbench .part.banner .message-actions-container a {
|
||||
padding: 3px;
|
||||
margin-left: 12px;
|
||||
text-decoration: underline;
|
||||
}
|
||||
|
|
|
@ -332,8 +332,8 @@ class DropOverlay extends Themable {
|
|||
proposedFilePath = joinPath(defaultFilePath, name);
|
||||
}
|
||||
|
||||
// Open as untitled file with the provided contents
|
||||
const untitledEditor = this.editorService.createEditorInput({
|
||||
// Open as untitled text file with the provided contents
|
||||
const untitledTextEditor = this.editorService.createEditorInput({
|
||||
resource: proposedFilePath,
|
||||
forceUntitled: true,
|
||||
contents: VSBuffer.wrap(new Uint8Array(event.target.result)).toString()
|
||||
|
@ -343,7 +343,7 @@ class DropOverlay extends Themable {
|
|||
targetGroup = ensureTargetGroup();
|
||||
}
|
||||
|
||||
await targetGroup.openEditor(untitledEditor);
|
||||
await targetGroup.openEditor(untitledTextEditor);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
@ -355,9 +355,7 @@ class DropOverlay extends Themable {
|
|||
else {
|
||||
const dropHandler = this.instantiationService.createInstance(ResourcesDropHandler, { allowWorkspaceOpen: true /* open workspace instead of file if dropped */ });
|
||||
dropHandler.handleDrop(event, () => ensureTargetGroup(), targetGroup => {
|
||||
if (targetGroup) {
|
||||
targetGroup.focus();
|
||||
}
|
||||
targetGroup?.focus();
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
|
@ -404,13 +404,14 @@ export class EditorStatus extends Disposable implements IWorkbenchContribution {
|
|||
if (!this.tabFocusModeElement.value) {
|
||||
const text = localize('tabFocusModeEnabled', "Tab Moves Focus");
|
||||
this.tabFocusModeElement.value = this.statusbarService.addEntry({
|
||||
name: localize('status.editor.tabFocusMode', "Accessibility Mode"),
|
||||
text,
|
||||
ariaLabel: text,
|
||||
tooltip: localize('disableTabMode', "Disable Accessibility Mode"),
|
||||
command: 'editor.action.toggleTabFocusMode',
|
||||
backgroundColor: themeColorFromId(STATUS_BAR_PROMINENT_ITEM_BACKGROUND),
|
||||
color: themeColorFromId(STATUS_BAR_PROMINENT_ITEM_FOREGROUND)
|
||||
}, 'status.editor.tabFocusMode', localize('status.editor.tabFocusMode', "Accessibility Mode"), StatusbarAlignment.RIGHT, 100.7);
|
||||
}, 'status.editor.tabFocusMode', StatusbarAlignment.RIGHT, 100.7);
|
||||
}
|
||||
} else {
|
||||
this.tabFocusModeElement.clear();
|
||||
|
@ -422,13 +423,14 @@ export class EditorStatus extends Disposable implements IWorkbenchContribution {
|
|||
if (!this.columnSelectionModeElement.value) {
|
||||
const text = localize('columnSelectionModeEnabled', "Column Selection");
|
||||
this.columnSelectionModeElement.value = this.statusbarService.addEntry({
|
||||
name: localize('status.editor.columnSelectionMode', "Column Selection Mode"),
|
||||
text,
|
||||
ariaLabel: text,
|
||||
tooltip: localize('disableColumnSelectionMode', "Disable Column Selection Mode"),
|
||||
command: 'editor.action.toggleColumnSelection',
|
||||
backgroundColor: themeColorFromId(STATUS_BAR_PROMINENT_ITEM_BACKGROUND),
|
||||
color: themeColorFromId(STATUS_BAR_PROMINENT_ITEM_FOREGROUND)
|
||||
}, 'status.editor.columnSelectionMode', localize('status.editor.columnSelectionMode', "Column Selection Mode"), StatusbarAlignment.RIGHT, 100.8);
|
||||
}, 'status.editor.columnSelectionMode', StatusbarAlignment.RIGHT, 100.8);
|
||||
}
|
||||
} else {
|
||||
this.columnSelectionModeElement.clear();
|
||||
|
@ -440,12 +442,13 @@ export class EditorStatus extends Disposable implements IWorkbenchContribution {
|
|||
if (!this.screenRedearModeElement.value) {
|
||||
const text = localize('screenReaderDetected', "Screen Reader Optimized");
|
||||
this.screenRedearModeElement.value = this.statusbarService.addEntry({
|
||||
name: localize('status.editor.screenReaderMode', "Screen Reader Mode"),
|
||||
text,
|
||||
ariaLabel: text,
|
||||
command: 'showEditorScreenReaderNotification',
|
||||
backgroundColor: themeColorFromId(STATUS_BAR_PROMINENT_ITEM_BACKGROUND),
|
||||
color: themeColorFromId(STATUS_BAR_PROMINENT_ITEM_FOREGROUND)
|
||||
}, 'status.editor.screenReaderMode', localize('status.editor.screenReaderMode', "Screen Reader Mode"), StatusbarAlignment.RIGHT, 100.6);
|
||||
}, 'status.editor.screenReaderMode', StatusbarAlignment.RIGHT, 100.6);
|
||||
}
|
||||
} else {
|
||||
this.screenRedearModeElement.clear();
|
||||
|
@ -459,13 +462,14 @@ export class EditorStatus extends Disposable implements IWorkbenchContribution {
|
|||
}
|
||||
|
||||
const props: IStatusbarEntry = {
|
||||
name: localize('status.editor.selection', "Editor Selection"),
|
||||
text,
|
||||
ariaLabel: text,
|
||||
tooltip: localize('gotoLine', "Go to Line/Column"),
|
||||
command: 'workbench.action.gotoLine'
|
||||
};
|
||||
|
||||
this.updateElement(this.selectionElement, props, 'status.editor.selection', localize('status.editor.selection', "Editor Selection"), StatusbarAlignment.RIGHT, 100.5);
|
||||
this.updateElement(this.selectionElement, props, 'status.editor.selection', StatusbarAlignment.RIGHT, 100.5);
|
||||
}
|
||||
|
||||
private updateIndentationElement(text: string | undefined): void {
|
||||
|
@ -475,13 +479,14 @@ export class EditorStatus extends Disposable implements IWorkbenchContribution {
|
|||
}
|
||||
|
||||
const props: IStatusbarEntry = {
|
||||
name: localize('status.editor.indentation', "Editor Indentation"),
|
||||
text,
|
||||
ariaLabel: text,
|
||||
tooltip: localize('selectIndentation', "Select Indentation"),
|
||||
command: 'changeEditorIndentation'
|
||||
};
|
||||
|
||||
this.updateElement(this.indentationElement, props, 'status.editor.indentation', localize('status.editor.indentation', "Editor Indentation"), StatusbarAlignment.RIGHT, 100.4);
|
||||
this.updateElement(this.indentationElement, props, 'status.editor.indentation', StatusbarAlignment.RIGHT, 100.4);
|
||||
}
|
||||
|
||||
private updateEncodingElement(text: string | undefined): void {
|
||||
|
@ -491,13 +496,14 @@ export class EditorStatus extends Disposable implements IWorkbenchContribution {
|
|||
}
|
||||
|
||||
const props: IStatusbarEntry = {
|
||||
name: localize('status.editor.encoding', "Editor Encoding"),
|
||||
text,
|
||||
ariaLabel: text,
|
||||
tooltip: localize('selectEncoding', "Select Encoding"),
|
||||
command: 'workbench.action.editor.changeEncoding'
|
||||
};
|
||||
|
||||
this.updateElement(this.encodingElement, props, 'status.editor.encoding', localize('status.editor.encoding', "Editor Encoding"), StatusbarAlignment.RIGHT, 100.3);
|
||||
this.updateElement(this.encodingElement, props, 'status.editor.encoding', StatusbarAlignment.RIGHT, 100.3);
|
||||
}
|
||||
|
||||
private updateEOLElement(text: string | undefined): void {
|
||||
|
@ -507,13 +513,14 @@ export class EditorStatus extends Disposable implements IWorkbenchContribution {
|
|||
}
|
||||
|
||||
const props: IStatusbarEntry = {
|
||||
name: localize('status.editor.eol', "Editor End of Line"),
|
||||
text,
|
||||
ariaLabel: text,
|
||||
tooltip: localize('selectEOL', "Select End of Line Sequence"),
|
||||
command: 'workbench.action.editor.changeEOL'
|
||||
};
|
||||
|
||||
this.updateElement(this.eolElement, props, 'status.editor.eol', localize('status.editor.eol', "Editor End of Line"), StatusbarAlignment.RIGHT, 100.2);
|
||||
this.updateElement(this.eolElement, props, 'status.editor.eol', StatusbarAlignment.RIGHT, 100.2);
|
||||
}
|
||||
|
||||
private updateModeElement(text: string | undefined): void {
|
||||
|
@ -523,13 +530,14 @@ export class EditorStatus extends Disposable implements IWorkbenchContribution {
|
|||
}
|
||||
|
||||
const props: IStatusbarEntry = {
|
||||
name: localize('status.editor.mode', "Editor Language"),
|
||||
text,
|
||||
ariaLabel: text,
|
||||
tooltip: localize('selectLanguageMode', "Select Language Mode"),
|
||||
command: 'workbench.action.editor.changeLanguageMode'
|
||||
};
|
||||
|
||||
this.updateElement(this.modeElement, props, 'status.editor.mode', localize('status.editor.mode', "Editor Language"), StatusbarAlignment.RIGHT, 100.1);
|
||||
this.updateElement(this.modeElement, props, 'status.editor.mode', StatusbarAlignment.RIGHT, 100.1);
|
||||
}
|
||||
|
||||
private updateMetadataElement(text: string | undefined): void {
|
||||
|
@ -539,17 +547,18 @@ export class EditorStatus extends Disposable implements IWorkbenchContribution {
|
|||
}
|
||||
|
||||
const props: IStatusbarEntry = {
|
||||
name: localize('status.editor.info', "File Information"),
|
||||
text,
|
||||
ariaLabel: text,
|
||||
tooltip: localize('fileInfo', "File Information")
|
||||
};
|
||||
|
||||
this.updateElement(this.metadataElement, props, 'status.editor.info', localize('status.editor.info', "File Information"), StatusbarAlignment.RIGHT, 100);
|
||||
this.updateElement(this.metadataElement, props, 'status.editor.info', StatusbarAlignment.RIGHT, 100);
|
||||
}
|
||||
|
||||
private updateElement(element: MutableDisposable<IStatusbarEntryAccessor>, props: IStatusbarEntry, id: string, name: string, alignment: StatusbarAlignment, priority: number) {
|
||||
private updateElement(element: MutableDisposable<IStatusbarEntryAccessor>, props: IStatusbarEntry, id: string, alignment: StatusbarAlignment, priority: number) {
|
||||
if (!element.value) {
|
||||
element.value = this.statusbarService.addEntry(props, id, name, alignment, priority);
|
||||
element.value = this.statusbarService.addEntry(props, id, alignment, priority);
|
||||
} else {
|
||||
element.value.update(props);
|
||||
}
|
||||
|
@ -923,9 +932,9 @@ class ShowCurrentMarkerInStatusbarContribution extends Disposable {
|
|||
const line = splitLines(this.currentMarker.message)[0];
|
||||
const text = `${this.getType(this.currentMarker)} ${line}`;
|
||||
if (!this.statusBarEntryAccessor.value) {
|
||||
this.statusBarEntryAccessor.value = this.statusbarService.addEntry({ text: '', ariaLabel: '' }, 'statusbar.currentProblem', localize('currentProblem', "Current Problem"), StatusbarAlignment.LEFT);
|
||||
this.statusBarEntryAccessor.value = this.statusbarService.addEntry({ name: localize('currentProblem', "Current Problem"), text: '', ariaLabel: '' }, 'statusbar.currentProblem', StatusbarAlignment.LEFT);
|
||||
}
|
||||
this.statusBarEntryAccessor.value.update({ text, ariaLabel: text });
|
||||
this.statusBarEntryAccessor.value.update({ name: localize('currentProblem', "Current Problem"), text, ariaLabel: text });
|
||||
} else {
|
||||
this.statusBarEntryAccessor.clear();
|
||||
}
|
||||
|
|
|
@ -290,7 +290,7 @@ export abstract class TitleControl extends Themable {
|
|||
return false;
|
||||
}
|
||||
|
||||
const editorOptions: ITextEditorOptions = {
|
||||
let editorOptions: ITextEditorOptions = {
|
||||
viewState: (() => {
|
||||
if (this.group.activeEditor === editor) {
|
||||
const activeControl = this.group.activeEditorPane?.getControl();
|
||||
|
@ -304,6 +304,14 @@ export abstract class TitleControl extends Themable {
|
|||
sticky: this.group.isSticky(editor)
|
||||
};
|
||||
|
||||
// If it's a custom editor or a notebook add the viewtype
|
||||
if ((editor as object).hasOwnProperty('viewType')) {
|
||||
interface EditorInputWithViewType extends IEditorInput {
|
||||
viewType: string;
|
||||
}
|
||||
editorOptions = { ...editorOptions, override: (editor as EditorInputWithViewType).viewType };
|
||||
}
|
||||
|
||||
this.instantiationService.invokeFunction(fillResourceDataTransfers, [resource], () => editorOptions, e);
|
||||
|
||||
return true;
|
||||
|
|
|
@ -71,6 +71,7 @@ export class NotificationsStatus extends Disposable {
|
|||
|
||||
// Show the bell with a dot if there are unread or in-progress notifications
|
||||
const statusProperties: IStatusbarEntry = {
|
||||
name: localize('status.notifications', "Notifications"),
|
||||
text: `${notificationsInProgress > 0 || this.newNotificationsCount > 0 ? '$(bell-dot)' : '$(bell)'}`,
|
||||
ariaLabel: localize('status.notifications', "Notifications"),
|
||||
command: this.isNotificationsCenterVisible ? HIDE_NOTIFICATIONS_CENTER : SHOW_NOTIFICATIONS_CENTER,
|
||||
|
@ -82,7 +83,6 @@ export class NotificationsStatus extends Disposable {
|
|||
this.notificationsCenterStatusItem = this.statusbarService.addEntry(
|
||||
statusProperties,
|
||||
'status.notifications',
|
||||
localize('status.notifications', "Notifications"),
|
||||
StatusbarAlignment.RIGHT,
|
||||
-Number.MAX_VALUE /* towards the far end of the right hand side */
|
||||
);
|
||||
|
@ -180,9 +180,12 @@ export class NotificationsStatus extends Disposable {
|
|||
let statusMessageEntry: IStatusbarEntryAccessor;
|
||||
let showHandle: any = setTimeout(() => {
|
||||
statusMessageEntry = this.statusbarService.addEntry(
|
||||
{ text: message, ariaLabel: message },
|
||||
{
|
||||
name: localize('status.message', "Status Message"),
|
||||
text: message,
|
||||
ariaLabel: message
|
||||
},
|
||||
'status.message',
|
||||
localize('status.message', "Status Message"),
|
||||
StatusbarAlignment.LEFT,
|
||||
-Number.MAX_VALUE /* far right on left hand side */
|
||||
);
|
||||
|
|
|
@ -42,13 +42,33 @@ import { syncing } from 'vs/platform/theme/common/iconRegistry';
|
|||
import { Action2, registerAction2 } from 'vs/platform/actions/common/actions';
|
||||
import { CATEGORIES } from 'vs/workbench/common/actions';
|
||||
import { IEditorService } from 'vs/workbench/services/editor/common/editorService';
|
||||
import { hash } from 'vs/base/common/hash';
|
||||
|
||||
interface IStatusbarEntryPriority {
|
||||
|
||||
/**
|
||||
* The main priority of the entry that
|
||||
* defines the order of appearance.
|
||||
*
|
||||
* May not be unique across all entries.
|
||||
*/
|
||||
primary: number;
|
||||
|
||||
/**
|
||||
* The secondary priority of the entry
|
||||
* is used in case the main priority
|
||||
* matches another one's priority.
|
||||
*
|
||||
* Should be unique across all entries.
|
||||
*/
|
||||
secondary: number;
|
||||
}
|
||||
|
||||
interface IPendingStatusbarEntry {
|
||||
id: string;
|
||||
name: string;
|
||||
entry: IStatusbarEntry;
|
||||
alignment: StatusbarAlignment;
|
||||
priority: number;
|
||||
priority: IStatusbarEntryPriority;
|
||||
accessor?: IStatusbarEntryAccessor;
|
||||
}
|
||||
|
||||
|
@ -56,7 +76,7 @@ interface IStatusbarViewModelEntry {
|
|||
id: string;
|
||||
name: string;
|
||||
alignment: StatusbarAlignment;
|
||||
priority: number;
|
||||
priority: IStatusbarEntryPriority;
|
||||
container: HTMLElement;
|
||||
labelContainer: HTMLElement;
|
||||
}
|
||||
|
@ -294,14 +314,16 @@ class StatusbarViewModel extends Disposable {
|
|||
|
||||
this._entries.sort((entryA, entryB) => {
|
||||
if (entryA.alignment === entryB.alignment) {
|
||||
if (entryA.priority !== entryB.priority) {
|
||||
return entryB.priority - entryA.priority; // higher priority towards the left
|
||||
if (entryA.priority.primary !== entryB.priority.primary) {
|
||||
return entryB.priority.primary - entryA.priority.primary; // higher priority towards the left (primary)
|
||||
}
|
||||
|
||||
const indexA = mapEntryToIndex.get(entryA);
|
||||
const indexB = mapEntryToIndex.get(entryB);
|
||||
if (entryA.priority.secondary !== entryB.priority.secondary) {
|
||||
return entryB.priority.secondary - entryA.priority.secondary; // higher priority towards the left (secondary)
|
||||
}
|
||||
|
||||
return indexA! - indexB!; // otherwise maintain stable order (both values known to be in map)
|
||||
// otherwise maintain stable order (both values known to be in map)
|
||||
return mapEntryToIndex.get(entryA)! - mapEntryToIndex.get(entryB)!;
|
||||
}
|
||||
|
||||
if (entryA.alignment === StatusbarAlignment.LEFT) {
|
||||
|
@ -422,20 +444,24 @@ export class StatusbarPart extends Part implements IStatusbarService {
|
|||
this._register(this.contextService.onDidChangeWorkbenchState(() => this.updateStyles()));
|
||||
}
|
||||
|
||||
addEntry(entry: IStatusbarEntry, id: string, name: string, alignment: StatusbarAlignment, priority: number = 0): IStatusbarEntryAccessor {
|
||||
addEntry(entry: IStatusbarEntry, id: string, alignment: StatusbarAlignment, primaryPriority = 0): IStatusbarEntryAccessor {
|
||||
const priority: IStatusbarEntryPriority = {
|
||||
primary: primaryPriority,
|
||||
secondary: hash(id) // derive from identifier to accomplish uniqueness
|
||||
};
|
||||
|
||||
// As long as we have not been created into a container yet, record all entries
|
||||
// that are pending so that they can get created at a later point
|
||||
if (!this.element) {
|
||||
return this.doAddPendingEntry(entry, id, name, alignment, priority);
|
||||
return this.doAddPendingEntry(entry, id, alignment, priority);
|
||||
}
|
||||
|
||||
// Otherwise add to view
|
||||
return this.doAddEntry(entry, id, name, alignment, priority);
|
||||
return this.doAddEntry(entry, id, alignment, priority);
|
||||
}
|
||||
|
||||
private doAddPendingEntry(entry: IStatusbarEntry, id: string, name: string, alignment: StatusbarAlignment, priority: number): IStatusbarEntryAccessor {
|
||||
const pendingEntry: IPendingStatusbarEntry = { entry, id, name, alignment, priority };
|
||||
private doAddPendingEntry(entry: IStatusbarEntry, id: string, alignment: StatusbarAlignment, priority: IStatusbarEntryPriority): IStatusbarEntryAccessor {
|
||||
const pendingEntry: IPendingStatusbarEntry = { entry, id, alignment, priority };
|
||||
this.pendingEntries.push(pendingEntry);
|
||||
|
||||
const accessor: IStatusbarEntryAccessor = {
|
||||
|
@ -459,7 +485,7 @@ export class StatusbarPart extends Part implements IStatusbarService {
|
|||
return accessor;
|
||||
}
|
||||
|
||||
private doAddEntry(entry: IStatusbarEntry, id: string, name: string, alignment: StatusbarAlignment, priority: number): IStatusbarEntryAccessor {
|
||||
private doAddEntry(entry: IStatusbarEntry, id: string, alignment: StatusbarAlignment, priority: IStatusbarEntryPriority): IStatusbarEntryAccessor {
|
||||
|
||||
// Create item
|
||||
const itemContainer = this.doCreateStatusItem(id, alignment, ...coalesce([entry.showBeak ? 'has-beak' : undefined]));
|
||||
|
@ -469,7 +495,15 @@ export class StatusbarPart extends Part implements IStatusbarService {
|
|||
this.appendOneStatusbarEntry(itemContainer, alignment, priority);
|
||||
|
||||
// Add to view model
|
||||
const viewModelEntry: IStatusbarViewModelEntry = { id, name, alignment, priority, container: itemContainer, labelContainer: item.labelContainer };
|
||||
const viewModelEntry: IStatusbarViewModelEntry = new class implements IStatusbarViewModelEntry {
|
||||
readonly id = id;
|
||||
readonly alignment = alignment;
|
||||
readonly priority = priority;
|
||||
readonly container = itemContainer;
|
||||
readonly labelContainer = item.labelContainer;
|
||||
|
||||
get name() { return item.name; }
|
||||
};
|
||||
const viewModelEntryDispose = this.viewModel.add(viewModelEntry);
|
||||
|
||||
return {
|
||||
|
@ -553,7 +587,7 @@ export class StatusbarPart extends Part implements IStatusbarService {
|
|||
while (this.pendingEntries.length) {
|
||||
const pending = this.pendingEntries.shift();
|
||||
if (pending) {
|
||||
pending.accessor = this.addEntry(pending.entry, pending.id, pending.name, pending.alignment, pending.priority);
|
||||
pending.accessor = this.addEntry(pending.entry, pending.id, pending.alignment, pending.priority.primary);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -571,7 +605,7 @@ export class StatusbarPart extends Part implements IStatusbarService {
|
|||
});
|
||||
}
|
||||
|
||||
private appendOneStatusbarEntry(itemContainer: HTMLElement, alignment: StatusbarAlignment, priority: number): void {
|
||||
private appendOneStatusbarEntry(itemContainer: HTMLElement, alignment: StatusbarAlignment, priority: IStatusbarEntryPriority): void {
|
||||
const entries = this.viewModel.getEntries(alignment);
|
||||
|
||||
if (alignment === StatusbarAlignment.RIGHT) {
|
||||
|
@ -584,9 +618,20 @@ export class StatusbarPart extends Part implements IStatusbarService {
|
|||
// and then insert the item before that one
|
||||
let appended = false;
|
||||
for (const entry of entries) {
|
||||
|
||||
// pick a priority that ideally is not the same
|
||||
// by falling back to secondary priority
|
||||
let existingEntryPriority = entry.priority.primary;
|
||||
let newEntryPriority = priority.primary;
|
||||
if (existingEntryPriority === newEntryPriority) {
|
||||
existingEntryPriority = entry.priority.secondary;
|
||||
newEntryPriority = priority.secondary;
|
||||
}
|
||||
|
||||
// insert according to priority
|
||||
if (
|
||||
alignment === StatusbarAlignment.LEFT && entry.priority < priority ||
|
||||
alignment === StatusbarAlignment.RIGHT && entry.priority > priority // reversing due to flex: row-reverse
|
||||
alignment === StatusbarAlignment.LEFT && existingEntryPriority < newEntryPriority ||
|
||||
alignment === StatusbarAlignment.RIGHT && existingEntryPriority > newEntryPriority // reversing due to flex: row-reverse
|
||||
) {
|
||||
target.insertBefore(itemContainer, entry.container);
|
||||
appended = true;
|
||||
|
@ -777,6 +822,7 @@ class StatusbarEntryItem extends Disposable {
|
|||
private readonly label: StatusBarCodiconLabel;
|
||||
|
||||
private entry: IStatusbarEntry | undefined = undefined;
|
||||
get name(): string { return assertIsDefined(this.entry).name; }
|
||||
|
||||
private readonly foregroundListener = this._register(new MutableDisposable());
|
||||
private readonly backgroundListener = this._register(new MutableDisposable());
|
||||
|
|
|
@ -10,7 +10,7 @@ import { IKeybindingService } from 'vs/platform/keybinding/common/keybinding';
|
|||
import { IContextMenuService } from 'vs/platform/contextview/browser/contextView';
|
||||
import { MenuId, IMenuService, registerAction2, Action2 } from 'vs/platform/actions/common/actions';
|
||||
import { IContextKeyService, ContextKeyExpr, ContextKeyEqualsExpr, RawContextKey, IContextKey } from 'vs/platform/contextkey/common/contextkey';
|
||||
import { ITreeView, ITreeViewDescriptor, IViewsRegistry, Extensions, IViewDescriptorService, ITreeItem, TreeItemCollapsibleState, ITreeViewDataProvider, TreeViewItemHandleArg, ITreeItemLabel, ViewContainer, ViewContainerLocation, ResolvableTreeItem } from 'vs/workbench/common/views';
|
||||
import { ITreeView, ITreeViewDescriptor, IViewsRegistry, Extensions, IViewDescriptorService, ITreeItem, TreeItemCollapsibleState, ITreeViewDataProvider, TreeViewItemHandleArg, ITreeItemLabel, ViewContainer, ViewContainerLocation, ResolvableTreeItem, ITreeViewDragAndDropController } from 'vs/workbench/common/views';
|
||||
import { IViewletViewOptions } from 'vs/workbench/browser/parts/views/viewsViewlet';
|
||||
import { IConfigurationService } from 'vs/platform/configuration/common/configuration';
|
||||
import { IThemeService, FileThemeIcon, FolderThemeIcon, registerThemingParticipant, ThemeIcon } from 'vs/platform/theme/common/themeService';
|
||||
|
@ -159,7 +159,6 @@ export class TreeView extends Disposable implements ITreeView {
|
|||
private treeContainer!: HTMLElement;
|
||||
private _messageValue: string | undefined;
|
||||
private _canSelectMany: boolean = false;
|
||||
private _canDragAndDrop = false;
|
||||
private messageElement!: HTMLDivElement;
|
||||
private tree: Tree | undefined;
|
||||
private treeLabels: ResourceLabels | undefined;
|
||||
|
@ -241,6 +240,13 @@ export class TreeView extends Disposable implements ITreeView {
|
|||
get viewLocation(): ViewContainerLocation {
|
||||
return this.viewDescriptorService.getViewLocationById(this.id)!;
|
||||
}
|
||||
private _dragAndDropController: ITreeViewDragAndDropController | undefined;
|
||||
get dragAndDropController(): ITreeViewDragAndDropController | undefined {
|
||||
return this._dragAndDropController;
|
||||
}
|
||||
set dragAndDropController(dnd: ITreeViewDragAndDropController | undefined) {
|
||||
this._dragAndDropController = dnd;
|
||||
}
|
||||
|
||||
private _dataProvider: ITreeViewDataProvider | undefined;
|
||||
get dataProvider(): ITreeViewDataProvider | undefined {
|
||||
|
@ -281,12 +287,6 @@ export class TreeView extends Disposable implements ITreeView {
|
|||
}
|
||||
return children;
|
||||
}
|
||||
|
||||
async setParent(nodes: ITreeItem[], parentNode: ITreeItem): Promise<void> {
|
||||
if (dataProvider.setParent) {
|
||||
await dataProvider.setParent(nodes, parentNode);
|
||||
}
|
||||
}
|
||||
};
|
||||
if (this._dataProvider.onDidChangeEmpty) {
|
||||
this._register(this._dataProvider.onDidChangeEmpty(() => this._onDidChangeWelcomeState.fire()));
|
||||
|
@ -339,14 +339,6 @@ export class TreeView extends Disposable implements ITreeView {
|
|||
this._canSelectMany = canSelectMany;
|
||||
}
|
||||
|
||||
get canDragAndDrop(): boolean {
|
||||
return this._canDragAndDrop;
|
||||
}
|
||||
|
||||
set canDragAndDrop(canDragAndDrop: boolean) {
|
||||
this._canDragAndDrop = canDragAndDrop;
|
||||
}
|
||||
|
||||
get hasIconForParentNode(): boolean {
|
||||
return this._hasIconForParentNode;
|
||||
}
|
||||
|
@ -521,7 +513,7 @@ export class TreeView extends Disposable implements ITreeView {
|
|||
return e.collapsibleState !== TreeItemCollapsibleState.Expanded;
|
||||
},
|
||||
multipleSelectionSupport: this.canSelectMany,
|
||||
dnd: this.canDragAndDrop ? this.instantiationService.createInstance(CustomTreeViewDragAndDrop, dataSource) : undefined,
|
||||
dnd: this.dragAndDropController ? this.instantiationService.createInstance(CustomTreeViewDragAndDrop, this.dragAndDropController) : undefined,
|
||||
overrideStyles: {
|
||||
listBackground: this.viewLocation === ViewContainerLocation.Sidebar ? SIDE_BAR_BACKGROUND : PANEL_BACKGROUND
|
||||
}
|
||||
|
@ -814,18 +806,6 @@ class TreeDataSource implements IAsyncDataSource<ITreeItem, ITreeItem> {
|
|||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
async setParent(elements: ITreeItem[], newParentElement: ITreeItem): Promise<void> {
|
||||
if (this.treeView.dataProvider && this.treeView.dataProvider.setParent) {
|
||||
try {
|
||||
await this.withProgress(this.treeView.dataProvider.setParent(elements, newParentElement));
|
||||
} catch (e) {
|
||||
if (!(<string>e.message).startsWith('Bad progress location:')) {
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// todo@jrieken,sandy make this proper and contributable from extensions
|
||||
|
@ -879,12 +859,18 @@ class TreeRenderer extends Disposable implements ITreeRenderer<ITreeItem, FuzzyS
|
|||
@IThemeService private readonly themeService: IThemeService,
|
||||
@IConfigurationService private readonly configurationService: IConfigurationService,
|
||||
@ILabelService private readonly labelService: ILabelService,
|
||||
@IHoverService private readonly hoverService: IHoverService
|
||||
@IHoverService private readonly hoverService: IHoverService,
|
||||
@IOpenerService openerService: IOpenerService
|
||||
) {
|
||||
super();
|
||||
this._hoverDelegate = {
|
||||
showHover: (options: IHoverDelegateOptions): IDisposable | undefined => {
|
||||
return this.hoverService.showHover(options);
|
||||
return this.hoverService.showHover({
|
||||
...options,
|
||||
linkHandler: (url: string) => {
|
||||
return openerService.open(url, { allowCommands: (!isString(options.text) && options.text.isTrusted) });
|
||||
}
|
||||
});
|
||||
},
|
||||
delay: <number>this.configurationService.getValue('workbench.hover.delay')
|
||||
};
|
||||
|
@ -1216,7 +1202,7 @@ export class CustomTreeView extends TreeView {
|
|||
}
|
||||
|
||||
export class CustomTreeViewDragAndDrop implements ITreeDragAndDrop<ITreeItem> {
|
||||
constructor(private dataSource: TreeDataSource, @ILabelService private readonly labelService: ILabelService) { }
|
||||
constructor(private dndController: ITreeViewDragAndDropController, @ILabelService private readonly labelService: ILabelService) { }
|
||||
|
||||
onDragOver(data: IDragAndDropData, targetElement: ITreeItem, targetIndex: number, originalEvent: DragEvent): boolean | ITreeDragOverReaction {
|
||||
return { accept: true, bubble: TreeDragOverBubble.Down, autoExpand: true };
|
||||
|
@ -1238,7 +1224,7 @@ export class CustomTreeViewDragAndDrop implements ITreeDragAndDrop<ITreeItem> {
|
|||
if (data instanceof ElementsDragAndDropData) {
|
||||
const elements = data.elements;
|
||||
if (targetNode) {
|
||||
await this.dataSource.setParent(elements, targetNode);
|
||||
await this.dndController.onDrop(elements, targetNode);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -7,7 +7,7 @@ import 'vs/css!./media/paneviewlet';
|
|||
import * as nls from 'vs/nls';
|
||||
import { Event, Emitter } from 'vs/base/common/event';
|
||||
import { foreground } from 'vs/platform/theme/common/colorRegistry';
|
||||
import { attachButtonStyler, attachLinkStyler, attachProgressBarStyler } from 'vs/platform/theme/common/styler';
|
||||
import { attachButtonStyler, attachProgressBarStyler } from 'vs/platform/theme/common/styler';
|
||||
import { PANEL_BACKGROUND, SIDE_BAR_BACKGROUND } from 'vs/workbench/common/theme';
|
||||
import { after, append, $, trackFocus, EventType, addDisposableListener, createCSSRule, asCSSUrl } from 'vs/base/browser/dom';
|
||||
import { IDisposable, Disposable, DisposableStore } from 'vs/base/common/lifecycle';
|
||||
|
@ -582,10 +582,9 @@ export abstract class ViewPane extends Pane implements IView {
|
|||
const link = this.instantiationService.createInstance(Link, node, {});
|
||||
append(p, link.el);
|
||||
disposables.add(link);
|
||||
disposables.add(attachLinkStyler(link, this.themeService));
|
||||
|
||||
if (precondition && node.href.startsWith('command:')) {
|
||||
const updateEnablement = () => link.style({ disabled: !this.contextKeyService.contextMatchesRules(precondition) });
|
||||
const updateEnablement = () => link.enabled = this.contextKeyService.contextMatchesRules(precondition);
|
||||
updateEnablement();
|
||||
|
||||
const keys = new Set();
|
||||
|
|
|
@ -328,7 +328,7 @@ export class Workbench extends Layout {
|
|||
// Create Parts
|
||||
[
|
||||
{ id: Parts.TITLEBAR_PART, role: 'contentinfo', classes: ['titlebar'] },
|
||||
{ id: Parts.BANNER_PART, role: 'alert', classes: ['banner'] },
|
||||
{ id: Parts.BANNER_PART, role: 'banner', classes: ['banner'] },
|
||||
{ id: Parts.ACTIVITYBAR_PART, role: 'none', classes: ['activitybar', this.state.sideBar.position === Position.LEFT ? 'left' : 'right'] }, // Use role 'none' for some parts to make screen readers less chatty #114892
|
||||
{ id: Parts.SIDEBAR_PART, role: 'none', classes: ['sidebar', this.state.sideBar.position === Position.LEFT ? 'left' : 'right'] },
|
||||
{ id: Parts.EDITOR_PART, role: 'main', classes: ['editor'], options: { restorePreviousState: this.state.editor.restoreEditors } },
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue