mirror of
https://github.com/Microsoft/vscode
synced 2024-08-27 21:09:43 +00:00
Merge branch 'main' into joh/voluminous-lobster
This commit is contained in:
commit
3622010b64
1
.github/workflows/pr-chat.yml
vendored
1
.github/workflows/pr-chat.yml
vendored
|
@ -21,5 +21,6 @@ jobs:
|
|||
with:
|
||||
token: ${{secrets.VSCODE_ISSUE_TRIAGE_BOT_PAT}}
|
||||
slack_token: ${{ secrets.SLACK_TOKEN }}
|
||||
slack_user_token: ${{ secrets.SLACK_USER_TOKEN }}
|
||||
slack_bot_name: "VSCodeBot"
|
||||
notification_channel: codereview
|
||||
|
|
7
.vscode/launch.json
vendored
7
.vscode/launch.json
vendored
|
@ -16,11 +16,7 @@
|
|||
"request": "attach",
|
||||
"restart": true,
|
||||
"name": "Attach to Extension Host",
|
||||
// set to a large number: if there is an issue we're debugging that keeps
|
||||
// the extension host from coming up, or the renderer is paused/crashes
|
||||
// before it happens, developers will get an annoying alert, e.g. #126826.
|
||||
// This can be set to 0 in 1.59.
|
||||
"timeout": 999999999,
|
||||
"timeout": 0,
|
||||
"port": 5870,
|
||||
"outFiles": [
|
||||
"${workspaceFolder}/out/**/*.js",
|
||||
|
@ -244,6 +240,7 @@
|
|||
"runtimeArgs": [
|
||||
"--inspect=5875",
|
||||
"--no-cached-data",
|
||||
"--crash-reporter-directory=${workspaceFolder}/.profile-oss/crashes",
|
||||
// for general runtime freezes: https://github.com/microsoft/vscode/issues/127861#issuecomment-904144910
|
||||
"--disable-features=CalculateNativeWinOcclusion",
|
||||
],
|
||||
|
|
2
.vscode/notebooks/api.github-issues
vendored
2
.vscode/notebooks/api.github-issues
vendored
|
@ -7,7 +7,7 @@
|
|||
{
|
||||
"kind": 2,
|
||||
"language": "github-issues",
|
||||
"value": "$repo=repo:microsoft/vscode\n$milestone=milestone:\"May 2022\""
|
||||
"value": "$repo=repo:microsoft/vscode\n$milestone=milestone:\"June 2022\""
|
||||
},
|
||||
{
|
||||
"kind": 1,
|
||||
|
|
2
.vscode/notebooks/my-work.github-issues
vendored
2
.vscode/notebooks/my-work.github-issues
vendored
|
@ -7,7 +7,7 @@
|
|||
{
|
||||
"kind": 2,
|
||||
"language": "github-issues",
|
||||
"value": "// list of repos we work in\n$repos=repo:microsoft/vscode repo:microsoft/vscode-remote-release repo:microsoft/vscode-js-debug repo:microsoft/vscode-pull-request-github repo:microsoft/vscode-github-issue-notebooks repo:microsoft/vscode-internalbacklog repo:microsoft/vscode-dev repo:microsoft/vscode-unpkg repo:microsoft/vscode-references-view repo:microsoft/vscode-anycode repo:microsoft/vscode-hexeditor repo:microsoft/vscode-extension-telemetry repo:microsoft/vscode-livepreview repo:microsoft/vscode-remotehub repo:microsoft/vscode-settings-sync-server repo:microsoft/vscode-remote-repositories-github repo:microsoft/monaco-editor repo:microsoft/vscode-vsce\n\n// current milestone name\n$milestone=milestone:\"May 2022\""
|
||||
"value": "// list of repos we work in\n$repos=repo:microsoft/vscode repo:microsoft/vscode-remote-release repo:microsoft/vscode-js-debug repo:microsoft/vscode-pull-request-github repo:microsoft/vscode-github-issue-notebooks repo:microsoft/vscode-internalbacklog repo:microsoft/vscode-dev repo:microsoft/vscode-unpkg repo:microsoft/vscode-references-view repo:microsoft/vscode-anycode repo:microsoft/vscode-hexeditor repo:microsoft/vscode-extension-telemetry repo:microsoft/vscode-livepreview repo:microsoft/vscode-remotehub repo:microsoft/vscode-settings-sync-server repo:microsoft/vscode-remote-repositories-github repo:microsoft/monaco-editor repo:microsoft/vscode-vsce\n\n// current milestone name\n$milestone=milestone:\"June 2022\""
|
||||
},
|
||||
{
|
||||
"kind": 1,
|
||||
|
|
|
@ -500,7 +500,7 @@ export async function webpackExtensions(taskName: string, isWatch: boolean, webp
|
|||
function addConfig(configOrFn: webpack.Configuration | Function) {
|
||||
let config;
|
||||
if (typeof configOrFn === 'function') {
|
||||
config = configOrFn({}, {});
|
||||
config = (configOrFn as Function)({}, {});
|
||||
webpackConfigs.push(config);
|
||||
} else {
|
||||
config = configOrFn;
|
||||
|
|
|
@ -13,6 +13,7 @@ module.exports = withDefaults({
|
|||
context: __dirname,
|
||||
entry: {
|
||||
main: './src/main.ts',
|
||||
['askpass-main']: './src/askpass-main.ts'
|
||||
['askpass-main']: './src/askpass-main.ts',
|
||||
['git-editor-main']: './src/git-editor-main.ts'
|
||||
}
|
||||
});
|
||||
|
|
|
@ -14,6 +14,7 @@
|
|||
"contribMergeEditorToolbar",
|
||||
"contribViewsWelcome",
|
||||
"scmActionButton",
|
||||
"scmInput",
|
||||
"scmSelectedProvider",
|
||||
"scmValidation",
|
||||
"timeline"
|
||||
|
@ -213,83 +214,99 @@
|
|||
"command": "git.commit",
|
||||
"title": "%command.commit%",
|
||||
"category": "Git",
|
||||
"icon": "$(check)"
|
||||
"icon": "$(check)",
|
||||
"enablement": "!commitInProgress"
|
||||
},
|
||||
{
|
||||
"command": "git.commitStaged",
|
||||
"title": "%command.commitStaged%",
|
||||
"category": "Git"
|
||||
"category": "Git",
|
||||
"enablement": "!commitInProgress"
|
||||
},
|
||||
{
|
||||
"command": "git.commitEmpty",
|
||||
"title": "%command.commitEmpty%",
|
||||
"category": "Git"
|
||||
"category": "Git",
|
||||
"enablement": "!commitInProgress"
|
||||
},
|
||||
{
|
||||
"command": "git.commitStagedSigned",
|
||||
"title": "%command.commitStagedSigned%",
|
||||
"category": "Git"
|
||||
"category": "Git",
|
||||
"enablement": "!commitInProgress"
|
||||
},
|
||||
{
|
||||
"command": "git.commitStagedAmend",
|
||||
"title": "%command.commitStagedAmend%",
|
||||
"category": "Git"
|
||||
"category": "Git",
|
||||
"enablement": "!commitInProgress"
|
||||
},
|
||||
{
|
||||
"command": "git.commitAll",
|
||||
"title": "%command.commitAll%",
|
||||
"category": "Git"
|
||||
"category": "Git",
|
||||
"enablement": "!commitInProgress"
|
||||
},
|
||||
{
|
||||
"command": "git.commitAllSigned",
|
||||
"title": "%command.commitAllSigned%",
|
||||
"category": "Git"
|
||||
"category": "Git",
|
||||
"enablement": "!commitInProgress"
|
||||
},
|
||||
{
|
||||
"command": "git.commitAllAmend",
|
||||
"title": "%command.commitAllAmend%",
|
||||
"category": "Git"
|
||||
"category": "Git",
|
||||
"enablement": "!commitInProgress"
|
||||
},
|
||||
{
|
||||
"command": "git.commitNoVerify",
|
||||
"title": "%command.commitNoVerify%",
|
||||
"category": "Git",
|
||||
"icon": "$(check)"
|
||||
"icon": "$(check)",
|
||||
"enablement": "!commitInProgress"
|
||||
},
|
||||
{
|
||||
"command": "git.commitStagedNoVerify",
|
||||
"title": "%command.commitStagedNoVerify%",
|
||||
"category": "Git"
|
||||
"category": "Git",
|
||||
"enablement": "!commitInProgress"
|
||||
},
|
||||
{
|
||||
"command": "git.commitEmptyNoVerify",
|
||||
"title": "%command.commitEmptyNoVerify%",
|
||||
"category": "Git"
|
||||
"category": "Git",
|
||||
"enablement": "!commitInProgress"
|
||||
},
|
||||
{
|
||||
"command": "git.commitStagedSignedNoVerify",
|
||||
"title": "%command.commitStagedSignedNoVerify%",
|
||||
"category": "Git"
|
||||
"category": "Git",
|
||||
"enablement": "!commitInProgress"
|
||||
},
|
||||
{
|
||||
"command": "git.commitStagedAmendNoVerify",
|
||||
"title": "%command.commitStagedAmendNoVerify%",
|
||||
"category": "Git"
|
||||
"category": "Git",
|
||||
"enablement": "!commitInProgress"
|
||||
},
|
||||
{
|
||||
"command": "git.commitAllNoVerify",
|
||||
"title": "%command.commitAllNoVerify%",
|
||||
"category": "Git"
|
||||
"category": "Git",
|
||||
"enablement": "!commitInProgress"
|
||||
},
|
||||
{
|
||||
"command": "git.commitAllSignedNoVerify",
|
||||
"title": "%command.commitAllSignedNoVerify%",
|
||||
"category": "Git"
|
||||
"category": "Git",
|
||||
"enablement": "!commitInProgress"
|
||||
},
|
||||
{
|
||||
"command": "git.commitAllAmendNoVerify",
|
||||
"title": "%command.commitAllAmendNoVerify%",
|
||||
"category": "Git"
|
||||
"category": "Git",
|
||||
"enablement": "!commitInProgress"
|
||||
},
|
||||
{
|
||||
"command": "git.restoreCommitTemplate",
|
||||
|
@ -2013,6 +2030,18 @@
|
|||
"scope": "machine",
|
||||
"description": "%config.defaultCloneDirectory%"
|
||||
},
|
||||
"git.useEditorAsCommitInput": {
|
||||
"type": "boolean",
|
||||
"scope": "resource",
|
||||
"description": "%config.useEditorAsCommitInput%",
|
||||
"default": false
|
||||
},
|
||||
"git.verboseCommit": {
|
||||
"type": "boolean",
|
||||
"scope": "resource",
|
||||
"markdownDescription": "%config.verboseCommit%",
|
||||
"default": false
|
||||
},
|
||||
"git.enableSmartCommit": {
|
||||
"type": "boolean",
|
||||
"scope": "resource",
|
||||
|
|
|
@ -140,6 +140,8 @@
|
|||
"config.ignoreLimitWarning": "Ignores the warning when there are too many changes in a repository.",
|
||||
"config.ignoreRebaseWarning": "Ignores the warning when it looks like the branch might have been rebased when pulling.",
|
||||
"config.defaultCloneDirectory": "The default location to clone a git repository.",
|
||||
"config.useEditorAsCommitInput": "Use an editor to author the commit message.",
|
||||
"config.verboseCommit": "Enable verbose output when `#git.useEditorAsCommitInput#` is enabled.",
|
||||
"config.enableSmartCommit": "Commit all changes when there are no staged changes.",
|
||||
"config.smartCommitChanges": "Control which changes are automatically staged by Smart Commit.",
|
||||
"config.smartCommitChanges.all": "Automatically stage all changes.",
|
||||
|
|
3
extensions/git/src/api/git.d.ts
vendored
3
extensions/git/src/api/git.d.ts
vendored
|
@ -137,6 +137,8 @@ export interface CommitOptions {
|
|||
empty?: boolean;
|
||||
noVerify?: boolean;
|
||||
requireUserConfig?: boolean;
|
||||
useEditor?: boolean;
|
||||
verbose?: boolean;
|
||||
}
|
||||
|
||||
export interface FetchOptions {
|
||||
|
@ -336,4 +338,5 @@ export const enum GitErrorCodes {
|
|||
PatchDoesNotApply = 'PatchDoesNotApply',
|
||||
NoPathFound = 'NoPathFound',
|
||||
UnknownPath = 'UnknownPath',
|
||||
EmptyCommitMessage = 'EmptyCommitMessage'
|
||||
}
|
||||
|
|
|
@ -6,9 +6,8 @@
|
|||
import { window, InputBoxOptions, Uri, Disposable, workspace } from 'vscode';
|
||||
import { IDisposable, EmptyDisposable, toDisposable } from './util';
|
||||
import * as path from 'path';
|
||||
import { IIPCHandler, IIPCServer, createIPCServer } from './ipc/ipcServer';
|
||||
import { IIPCHandler, IIPCServer } from './ipc/ipcServer';
|
||||
import { CredentialsProvider, Credentials } from './api/git';
|
||||
import { OutputChannelLogger } from './log';
|
||||
|
||||
export class Askpass implements IIPCHandler {
|
||||
|
||||
|
@ -16,16 +15,7 @@ export class Askpass implements IIPCHandler {
|
|||
private cache = new Map<string, Credentials>();
|
||||
private credentialsProviders = new Set<CredentialsProvider>();
|
||||
|
||||
static async create(outputChannelLogger: OutputChannelLogger, context?: string): Promise<Askpass> {
|
||||
try {
|
||||
return new Askpass(await createIPCServer(context));
|
||||
} catch (err) {
|
||||
outputChannelLogger.logError(`Failed to create git askpass IPC: ${err}`);
|
||||
return new Askpass();
|
||||
}
|
||||
}
|
||||
|
||||
private constructor(private ipc?: IIPCServer) {
|
||||
constructor(private ipc?: IIPCServer) {
|
||||
if (ipc) {
|
||||
this.disposable = ipc.registerHandler('askpass', this);
|
||||
}
|
||||
|
|
|
@ -1516,6 +1516,14 @@ export class CommandCenter {
|
|||
opts.signoff = true;
|
||||
}
|
||||
|
||||
if (config.get<boolean>('useEditorAsCommitInput')) {
|
||||
opts.useEditor = true;
|
||||
|
||||
if (config.get<boolean>('verboseCommit')) {
|
||||
opts.verbose = true;
|
||||
}
|
||||
}
|
||||
|
||||
const smartCommitChanges = config.get<'all' | 'tracked'>('smartCommitChanges');
|
||||
|
||||
if (
|
||||
|
@ -1563,7 +1571,7 @@ export class CommandCenter {
|
|||
|
||||
const message = await getCommitMessage();
|
||||
|
||||
if (!message && !opts.amend) {
|
||||
if (!message && !opts.amend && !opts.useEditor) {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -1623,10 +1631,13 @@ export class CommandCenter {
|
|||
|
||||
private async commitWithAnyInput(repository: Repository, opts?: CommitOptions): Promise<void> {
|
||||
const message = repository.inputBox.value;
|
||||
const root = Uri.file(repository.root);
|
||||
const config = workspace.getConfiguration('git', root);
|
||||
|
||||
const getCommitMessage = async () => {
|
||||
let _message: string | undefined = message;
|
||||
|
||||
if (!_message) {
|
||||
if (!_message && !config.get<boolean>('useEditorAsCommitInput')) {
|
||||
const value: string | undefined = undefined;
|
||||
|
||||
if (opts && opts.amend && repository.HEAD && repository.HEAD.commit) {
|
||||
|
@ -3010,7 +3021,7 @@ export class CommandCenter {
|
|||
};
|
||||
|
||||
let message: string;
|
||||
let type: 'error' | 'warning' = 'error';
|
||||
let type: 'error' | 'warning' | 'information' = 'error';
|
||||
|
||||
const choices = new Map<string, () => void>();
|
||||
const openOutputChannelChoice = localize('open git log', "Open Git Log");
|
||||
|
@ -3073,6 +3084,12 @@ export class CommandCenter {
|
|||
message = localize('missing user info', "Make sure you configure your 'user.name' and 'user.email' in git.");
|
||||
choices.set(localize('learn more', "Learn More"), () => commands.executeCommand('vscode.open', Uri.parse('https://aka.ms/vscode-setup-git')));
|
||||
break;
|
||||
case GitErrorCodes.EmptyCommitMessage:
|
||||
message = localize('empty commit', "Commit operation was cancelled due to empty commit message.");
|
||||
choices.clear();
|
||||
type = 'information';
|
||||
options.modal = false;
|
||||
break;
|
||||
default: {
|
||||
const hint = (err.stderr || err.message || String(err))
|
||||
.replace(/^error: /mi, '')
|
||||
|
@ -3094,10 +3111,20 @@ export class CommandCenter {
|
|||
return;
|
||||
}
|
||||
|
||||
let result: string | undefined;
|
||||
const allChoices = Array.from(choices.keys());
|
||||
const result = type === 'error'
|
||||
? await window.showErrorMessage(message, options, ...allChoices)
|
||||
: await window.showWarningMessage(message, options, ...allChoices);
|
||||
|
||||
switch (type) {
|
||||
case 'error':
|
||||
result = await window.showErrorMessage(message, options, ...allChoices);
|
||||
break;
|
||||
case 'warning':
|
||||
result = await window.showWarningMessage(message, options, ...allChoices);
|
||||
break;
|
||||
case 'information':
|
||||
result = await window.showInformationMessage(message, options, ...allChoices);
|
||||
break;
|
||||
}
|
||||
|
||||
if (result) {
|
||||
const resultFn = choices.get(result);
|
||||
|
|
1
extensions/git/src/git-editor-empty.sh
Executable file
1
extensions/git/src/git-editor-empty.sh
Executable file
|
@ -0,0 +1 @@
|
|||
#!/bin/sh
|
21
extensions/git/src/git-editor-main.ts
Normal file
21
extensions/git/src/git-editor-main.ts
Normal file
|
@ -0,0 +1,21 @@
|
|||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
import { IPCClient } from './ipc/ipcClient';
|
||||
|
||||
function fatal(err: any): void {
|
||||
console.error(err);
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
function main(argv: string[]): void {
|
||||
const ipcClient = new IPCClient('git-editor');
|
||||
const commitMessagePath = argv[argv.length - 1];
|
||||
|
||||
ipcClient.call({ commitMessagePath }).then(() => {
|
||||
setTimeout(() => process.exit(0), 0);
|
||||
}).catch(err => fatal(err));
|
||||
}
|
||||
|
||||
main(process.argv);
|
4
extensions/git/src/git-editor.sh
Executable file
4
extensions/git/src/git-editor.sh
Executable file
|
@ -0,0 +1,4 @@
|
|||
#!/bin/sh
|
||||
|
||||
ELECTRON_RUN_AS_NODE="1" \
|
||||
"$VSCODE_GIT_EDITOR_NODE" "$VSCODE_GIT_EDITOR_MAIN" $VSCODE_GIT_EDITOR_EXTRA_ARGS $@
|
|
@ -1400,20 +1400,37 @@ export class Repository {
|
|||
}
|
||||
|
||||
async commit(message: string | undefined, opts: CommitOptions = Object.create(null)): Promise<void> {
|
||||
const args = ['commit', '--quiet', '--allow-empty-message'];
|
||||
const args = ['commit', '--quiet'];
|
||||
const options: SpawnOptions = {};
|
||||
|
||||
if (message) {
|
||||
options.input = message;
|
||||
args.push('--file', '-');
|
||||
}
|
||||
|
||||
if (opts.verbose) {
|
||||
args.push('--verbose');
|
||||
}
|
||||
|
||||
if (opts.all) {
|
||||
args.push('--all');
|
||||
}
|
||||
|
||||
if (opts.amend && message) {
|
||||
if (opts.amend) {
|
||||
args.push('--amend');
|
||||
}
|
||||
|
||||
if (opts.amend && !message) {
|
||||
args.push('--amend', '--no-edit');
|
||||
} else {
|
||||
args.push('--file', '-');
|
||||
if (!opts.useEditor) {
|
||||
if (!message) {
|
||||
if (opts.amend) {
|
||||
args.push('--no-edit');
|
||||
} else {
|
||||
options.input = '';
|
||||
args.push('--file', '-');
|
||||
}
|
||||
}
|
||||
|
||||
args.push('--allow-empty-message');
|
||||
}
|
||||
|
||||
if (opts.signoff) {
|
||||
|
@ -1438,7 +1455,7 @@ export class Repository {
|
|||
}
|
||||
|
||||
try {
|
||||
await this.exec(args, !opts.amend || message ? { input: message || '' } : {});
|
||||
await this.exec(args, options);
|
||||
} catch (commitErr) {
|
||||
await this.handleCommitError(commitErr);
|
||||
}
|
||||
|
@ -1462,6 +1479,9 @@ export class Repository {
|
|||
if (/not possible because you have unmerged files/.test(commitErr.stderr || '')) {
|
||||
commitErr.gitErrorCode = GitErrorCodes.UnmergedChanges;
|
||||
throw commitErr;
|
||||
} else if (/Aborting commit due to empty commit message/.test(commitErr.stderr || '')) {
|
||||
commitErr.gitErrorCode = GitErrorCodes.EmptyCommitMessage;
|
||||
throw commitErr;
|
||||
}
|
||||
|
||||
try {
|
||||
|
|
65
extensions/git/src/gitEditor.ts
Normal file
65
extensions/git/src/gitEditor.ts
Normal file
|
@ -0,0 +1,65 @@
|
|||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
import * as path from 'path';
|
||||
import { TabInputText, Uri, window, workspace } from 'vscode';
|
||||
import { IIPCHandler, IIPCServer } from './ipc/ipcServer';
|
||||
import { EmptyDisposable, IDisposable } from './util';
|
||||
|
||||
interface GitEditorRequest {
|
||||
commitMessagePath?: string;
|
||||
}
|
||||
|
||||
export class GitEditor implements IIPCHandler {
|
||||
|
||||
private disposable: IDisposable = EmptyDisposable;
|
||||
|
||||
constructor(private ipc?: IIPCServer) {
|
||||
if (ipc) {
|
||||
this.disposable = ipc.registerHandler('git-editor', this);
|
||||
}
|
||||
}
|
||||
|
||||
async handle({ commitMessagePath }: GitEditorRequest): Promise<any> {
|
||||
if (commitMessagePath) {
|
||||
const uri = Uri.file(commitMessagePath);
|
||||
const doc = await workspace.openTextDocument(uri);
|
||||
await window.showTextDocument(doc, { preview: false });
|
||||
|
||||
return new Promise((c) => {
|
||||
const onDidClose = window.tabGroups.onDidChangeTabs(async (tabs) => {
|
||||
if (tabs.closed.some(t => t.input instanceof TabInputText && t.input.uri.toString() === uri.toString())) {
|
||||
onDidClose.dispose();
|
||||
return c(true);
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
getEnv(): { [key: string]: string } {
|
||||
if (!this.ipc) {
|
||||
return {
|
||||
GIT_EDITOR: `"${path.join(__dirname, 'git-editor-empty.sh')}"`
|
||||
};
|
||||
}
|
||||
|
||||
let env: { [key: string]: string } = {
|
||||
VSCODE_GIT_EDITOR_NODE: process.execPath,
|
||||
VSCODE_GIT_EDITOR_EXTRA_ARGS: (process.versions['electron'] && process.versions['microsoft-build']) ? '--ms-enable-electron-run-as-node' : '',
|
||||
VSCODE_GIT_EDITOR_MAIN: path.join(__dirname, 'git-editor-main.js')
|
||||
};
|
||||
|
||||
const config = workspace.getConfiguration('git');
|
||||
if (config.get<boolean>('useEditorAsCommitInput')) {
|
||||
env.GIT_EDITOR = `"${path.join(__dirname, 'git-editor.sh')}"`;
|
||||
}
|
||||
|
||||
return env;
|
||||
}
|
||||
|
||||
dispose(): void {
|
||||
this.disposable.dispose();
|
||||
}
|
||||
}
|
|
@ -25,6 +25,8 @@ import { GitTimelineProvider } from './timelineProvider';
|
|||
import { registerAPICommands } from './api/api1';
|
||||
import { TerminalEnvironmentManager } from './terminal';
|
||||
import { OutputChannelLogger } from './log';
|
||||
import { createIPCServer, IIPCServer } from './ipc/ipcServer';
|
||||
import { GitEditor } from './gitEditor';
|
||||
|
||||
const deactivateTasks: { (): Promise<any> }[] = [];
|
||||
|
||||
|
@ -60,10 +62,21 @@ async function createModel(context: ExtensionContext, outputChannelLogger: Outpu
|
|||
return !skip;
|
||||
});
|
||||
|
||||
const askpass = await Askpass.create(outputChannelLogger, context.storagePath);
|
||||
let ipc: IIPCServer | undefined = undefined;
|
||||
|
||||
try {
|
||||
ipc = await createIPCServer(context.storagePath);
|
||||
} catch (err) {
|
||||
outputChannelLogger.logError(`Failed to create git IPC: ${err}`);
|
||||
}
|
||||
|
||||
const askpass = new Askpass(ipc);
|
||||
disposables.push(askpass);
|
||||
|
||||
const environment = askpass.getEnv();
|
||||
const gitEditor = new GitEditor(ipc);
|
||||
disposables.push(gitEditor);
|
||||
|
||||
const environment = { ...askpass.getEnv(), ...gitEditor.getEnv() };
|
||||
const terminalEnvironmentManager = new TerminalEnvironmentManager(context, environment);
|
||||
disposables.push(terminalEnvironmentManager);
|
||||
|
||||
|
|
|
@ -454,6 +454,13 @@ class ProgressManager {
|
|||
const onDidChange = filterEvent(workspace.onDidChangeConfiguration, e => e.affectsConfiguration('git', Uri.file(this.repository.root)));
|
||||
onDidChange(_ => this.updateEnablement());
|
||||
this.updateEnablement();
|
||||
|
||||
this.repository.onDidChangeOperations(() => {
|
||||
const commitInProgress = this.repository.operations.isRunning(Operation.Commit);
|
||||
|
||||
this.repository.sourceControl.inputBox.enabled = !commitInProgress;
|
||||
commands.executeCommand('setContext', 'commitInProgress', commitInProgress);
|
||||
});
|
||||
}
|
||||
|
||||
private updateEnablement(): void {
|
||||
|
|
|
@ -12,6 +12,7 @@
|
|||
"../../src/vscode-dts/vscode.d.ts",
|
||||
"../../src/vscode-dts/vscode.proposed.diffCommand.d.ts",
|
||||
"../../src/vscode-dts/vscode.proposed.scmActionButton.d.ts",
|
||||
"../../src/vscode-dts/vscode.proposed.scmInput.d.ts",
|
||||
"../../src/vscode-dts/vscode.proposed.scmSelectedProvider.d.ts",
|
||||
"../../src/vscode-dts/vscode.proposed.scmValidation.d.ts",
|
||||
"../../src/vscode-dts/vscode.proposed.tabs.d.ts",
|
||||
|
|
|
@ -4,23 +4,29 @@
|
|||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import * as vscode from 'vscode';
|
||||
import { tryInsertUriList } from './dropIntoEditor';
|
||||
import { tryGetUriListSnippet } from './dropIntoEditor';
|
||||
|
||||
export function registerPasteProvider(selector: vscode.DocumentSelector) {
|
||||
return vscode.languages.registerDocumentPasteEditProvider(selector, new class implements vscode.DocumentPasteEditProvider {
|
||||
|
||||
async provideDocumentPasteEdits(
|
||||
document: vscode.TextDocument,
|
||||
range: vscode.Range,
|
||||
_ranges: readonly vscode.Range[],
|
||||
dataTransfer: vscode.DataTransfer,
|
||||
token: vscode.CancellationToken,
|
||||
): Promise<vscode.SnippetTextEdit | undefined> {
|
||||
): Promise<vscode.DocumentPasteEdit | undefined> {
|
||||
const enabled = vscode.workspace.getConfiguration('markdown', document).get('experimental.editor.pasteLinks.enabled', false);
|
||||
if (!enabled) {
|
||||
return;
|
||||
}
|
||||
|
||||
return tryInsertUriList(document, range, dataTransfer, token);
|
||||
const snippet = await tryGetUriListSnippet(document, dataTransfer, token);
|
||||
if (snippet) {
|
||||
return { insertText: snippet };
|
||||
}
|
||||
return undefined;
|
||||
}
|
||||
}, {
|
||||
pasteMimeTypes: ['text/uri-list']
|
||||
});
|
||||
}
|
||||
|
|
|
@ -25,19 +25,22 @@ const imageFileExtensions = new Set<string>([
|
|||
|
||||
export function registerDropIntoEditor(selector: vscode.DocumentSelector) {
|
||||
return vscode.languages.registerDocumentOnDropEditProvider(selector, new class implements vscode.DocumentOnDropEditProvider {
|
||||
async provideDocumentOnDropEdits(document: vscode.TextDocument, position: vscode.Position, dataTransfer: vscode.DataTransfer, token: vscode.CancellationToken): Promise<vscode.SnippetTextEdit | undefined> {
|
||||
async provideDocumentOnDropEdits(document: vscode.TextDocument, _position: vscode.Position, dataTransfer: vscode.DataTransfer, token: vscode.CancellationToken): Promise<vscode.DocumentDropEdit | undefined> {
|
||||
const enabled = vscode.workspace.getConfiguration('markdown', document).get('editor.drop.enabled', true);
|
||||
if (!enabled) {
|
||||
return;
|
||||
return undefined;
|
||||
}
|
||||
|
||||
const replacementRange = new vscode.Range(position, position);
|
||||
return tryInsertUriList(document, replacementRange, dataTransfer, token);
|
||||
const snippet = await tryGetUriListSnippet(document, dataTransfer, token);
|
||||
if (snippet) {
|
||||
return { insertText: snippet };
|
||||
}
|
||||
return undefined;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
export async function tryInsertUriList(document: vscode.TextDocument, replacementRange: vscode.Range, dataTransfer: vscode.DataTransfer, token: vscode.CancellationToken): Promise<vscode.SnippetTextEdit | undefined> {
|
||||
export async function tryGetUriListSnippet(document: vscode.TextDocument, dataTransfer: vscode.DataTransfer, token: vscode.CancellationToken): Promise<vscode.SnippetString | undefined> {
|
||||
const urlList = await dataTransfer.get('text/uri-list')?.asString();
|
||||
if (!urlList || token.isCancellationRequested) {
|
||||
return undefined;
|
||||
|
@ -72,5 +75,5 @@ export async function tryInsertUriList(document: vscode.TextDocument, replacemen
|
|||
}
|
||||
});
|
||||
|
||||
return new vscode.SnippetTextEdit(replacementRange, snippet);
|
||||
return snippet;
|
||||
}
|
||||
|
|
|
@ -142,7 +142,7 @@ export class MdRenameProvider extends Disposable implements vscode.RenameProvide
|
|||
return this.renameExternalLink(allRefsInfo, newName);
|
||||
} else if (triggerRef.kind === 'header' || (triggerRef.kind === 'link' && triggerRef.link.source.fragmentRange?.contains(position) && (triggerRef.link.kind === 'definition' || triggerRef.link.kind === 'link' && triggerRef.link.href.kind === 'internal'))) {
|
||||
return this.renameFragment(allRefsInfo, newName);
|
||||
} else if (triggerRef.kind === 'link' && !triggerRef.link.source.fragmentRange?.contains(position) && triggerRef.link.kind === 'link' && triggerRef.link.href.kind === 'internal') {
|
||||
} else if (triggerRef.kind === 'link' && !triggerRef.link.source.fragmentRange?.contains(position) && (triggerRef.link.kind === 'link' || triggerRef.link.kind === 'definition') && triggerRef.link.href.kind === 'internal') {
|
||||
return this.renameFilePath(triggerRef.link.source.resource, triggerRef.link.href, allRefsInfo, newName);
|
||||
}
|
||||
|
||||
|
|
|
@ -614,4 +614,79 @@ suite('markdown: rename', () => {
|
|||
]
|
||||
});
|
||||
});
|
||||
|
||||
test('Rename on definition path should update all references to path', async () => {
|
||||
const uri = workspacePath('doc.md');
|
||||
const doc = new InMemoryDocument(uri, joinLines(
|
||||
`[ref text][ref]`,
|
||||
`[direct](/file)`,
|
||||
`[ref]: /file`, // rename here
|
||||
));
|
||||
|
||||
const workspace = new InMemoryWorkspaceMarkdownDocuments([doc]);
|
||||
|
||||
const preparedInfo = await prepareRename(doc, new vscode.Position(2, 10), workspace);
|
||||
assert.strictEqual(preparedInfo!.placeholder, '/file');
|
||||
assertRangeEqual(preparedInfo!.range, new vscode.Range(2, 7, 2, 12));
|
||||
|
||||
const edit = await getRenameEdits(doc, new vscode.Position(2, 10), "/newFile", workspace);
|
||||
assertEditsEqual(edit!, {
|
||||
uri, edits: [
|
||||
new vscode.TextEdit(new vscode.Range(1, 9, 1, 14), '/newFile'),
|
||||
new vscode.TextEdit(new vscode.Range(2, 7, 2, 12), '/newFile'),
|
||||
]
|
||||
});
|
||||
});
|
||||
|
||||
test('Rename on definition path where file exists should also update file', async () => {
|
||||
const uri1 = workspacePath('doc.md');
|
||||
const doc1 = new InMemoryDocument(uri1, joinLines(
|
||||
`[ref text][ref]`,
|
||||
`[direct](/doc2)`,
|
||||
`[ref]: /doc2`, // rename here
|
||||
));
|
||||
|
||||
const uri2 = workspacePath('doc2.md');
|
||||
const doc2 = new InMemoryDocument(uri2, joinLines());
|
||||
|
||||
const workspace = new InMemoryWorkspaceMarkdownDocuments([doc1, doc2]);
|
||||
|
||||
const preparedInfo = await prepareRename(doc1, new vscode.Position(2, 10), workspace);
|
||||
assert.strictEqual(preparedInfo!.placeholder, '/doc2');
|
||||
assertRangeEqual(preparedInfo!.range, new vscode.Range(2, 7, 2, 12));
|
||||
|
||||
const edit = await getRenameEdits(doc1, new vscode.Position(2, 10), "/new-doc", workspace);
|
||||
assertEditsEqual(edit!, {
|
||||
uri: uri1, edits: [
|
||||
new vscode.TextEdit(new vscode.Range(1, 9, 1, 14), '/new-doc'),
|
||||
new vscode.TextEdit(new vscode.Range(2, 7, 2, 12), '/new-doc'),
|
||||
]
|
||||
}, {
|
||||
originalUri: uri2,
|
||||
newUri: workspacePath('new-doc.md')
|
||||
});
|
||||
});
|
||||
|
||||
test('Rename on definition path header should update all references to header', async () => {
|
||||
const uri = workspacePath('doc.md');
|
||||
const doc = new InMemoryDocument(uri, joinLines(
|
||||
`[ref text][ref]`,
|
||||
`[direct](/file#header)`,
|
||||
`[ref]: /file#header`, // rename here
|
||||
));
|
||||
|
||||
const workspace = new InMemoryWorkspaceMarkdownDocuments([doc]);
|
||||
|
||||
const preparedInfo = await prepareRename(doc, new vscode.Position(2, 16), workspace);
|
||||
assert.strictEqual(preparedInfo!.placeholder, 'header');
|
||||
assertRangeEqual(preparedInfo!.range, new vscode.Range(2, 13, 2, 19));
|
||||
|
||||
const edit = await getRenameEdits(doc, new vscode.Position(2, 16), "New Header", workspace);
|
||||
assertEditsEqual(edit!, {
|
||||
uri, edits: [
|
||||
new vscode.TextEdit(new vscode.Range(1, 15, 1, 21), 'new-header'),
|
||||
new vscode.TextEdit(new vscode.Range(2, 13, 2, 19), 'new-header'),
|
||||
]
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
|
@ -12,10 +12,12 @@ import * as path from 'path';
|
|||
import * as fs from 'fs';
|
||||
import * as minimatch from 'minimatch';
|
||||
import * as nls from 'vscode-nls';
|
||||
import { Utils } from 'vscode-uri';
|
||||
import { findPreferredPM } from './preferred-pm';
|
||||
import { readScripts } from './readScripts';
|
||||
|
||||
const localize = nls.loadMessageBundle();
|
||||
const excludeRegex = new RegExp('^(node_modules|.vscode-test)$', 'i');
|
||||
|
||||
export interface INpmTaskDefinition extends TaskDefinition {
|
||||
script: string;
|
||||
|
@ -156,7 +158,7 @@ export async function hasNpmScripts(): Promise<boolean> {
|
|||
}
|
||||
try {
|
||||
for (const folder of folders) {
|
||||
if (isAutoDetectionEnabled(folder)) {
|
||||
if (isAutoDetectionEnabled(folder) && !excludeRegex.test(Utils.basename(folder.uri))) {
|
||||
const relativePattern = new RelativePattern(folder, '**/package.json');
|
||||
const paths = await workspace.findFiles(relativePattern, '**/node_modules/**');
|
||||
if (paths.length > 0) {
|
||||
|
@ -182,7 +184,7 @@ async function detectNpmScripts(context: ExtensionContext, showWarning: boolean)
|
|||
}
|
||||
try {
|
||||
for (const folder of folders) {
|
||||
if (isAutoDetectionEnabled(folder)) {
|
||||
if (isAutoDetectionEnabled(folder) && !excludeRegex.test(Utils.basename(folder.uri))) {
|
||||
const relativePattern = new RelativePattern(folder, '**/package.json');
|
||||
const paths = await workspace.findFiles(relativePattern, '**/{node_modules,.vscode-test}/**');
|
||||
for (const path of paths) {
|
||||
|
@ -206,6 +208,9 @@ export async function detectNpmScriptsForFolder(context: ExtensionContext, folde
|
|||
const folderTasks: IFolderTaskItem[] = [];
|
||||
|
||||
try {
|
||||
if (excludeRegex.test(Utils.basename(folder))) {
|
||||
return folderTasks;
|
||||
}
|
||||
const relativePattern = new RelativePattern(folder.fsPath, '**/package.json');
|
||||
const paths = await workspace.findFiles(relativePattern, '**/node_modules/**');
|
||||
|
||||
|
|
|
@ -65,7 +65,7 @@
|
|||
}
|
||||
},
|
||||
{
|
||||
"scope": ["meta.embedded", "source.groovy.embedded"],
|
||||
"scope": ["meta.embedded", "source.groovy.embedded", "meta.jsx.children"],
|
||||
"settings": {
|
||||
//"background": "#002451",
|
||||
"foreground": "#FFFFFF"
|
||||
|
|
|
@ -174,6 +174,7 @@ export default class FileConfigurationManager extends Disposable {
|
|||
document);
|
||||
|
||||
const preferences: Proto.UserPreferences = {
|
||||
...config.get('unstable'),
|
||||
quotePreference: this.getQuoteStylePreference(preferencesConfig),
|
||||
importModuleSpecifierPreference: getImportModuleSpecifierPreference(preferencesConfig),
|
||||
importModuleSpecifierEnding: getImportModuleSpecifierEndingPreference(preferencesConfig),
|
||||
|
|
|
@ -18,9 +18,9 @@ import * as vscode from 'vscode';
|
|||
const notebookEditor = vscode.window.activeNotebookEditor;
|
||||
assert.ok(notebookEditor);
|
||||
|
||||
assert.strictEqual(notebookEditor.document.cellCount, 2);
|
||||
assert.strictEqual(notebookEditor.document.cellAt(0).kind, vscode.NotebookCellKind.Markup);
|
||||
assert.strictEqual(notebookEditor.document.cellAt(1).kind, vscode.NotebookCellKind.Code);
|
||||
assert.strictEqual(notebookEditor.document.cellAt(1).outputs.length, 1);
|
||||
assert.strictEqual(notebookEditor.notebook.cellCount, 2);
|
||||
assert.strictEqual(notebookEditor.notebook.cellAt(0).kind, vscode.NotebookCellKind.Markup);
|
||||
assert.strictEqual(notebookEditor.notebook.cellAt(1).kind, vscode.NotebookCellKind.Code);
|
||||
assert.strictEqual(notebookEditor.notebook.cellAt(1).outputs.length, 1);
|
||||
});
|
||||
});
|
||||
|
|
|
@ -75,11 +75,11 @@ import * as utils from '../utils';
|
|||
const uri = await utils.createRandomFile(undefined, undefined, '.nbdtest');
|
||||
|
||||
const editor = await vscode.window.showNotebookDocument(uri);
|
||||
assert.strictEqual(uri.toString(), editor.document.uri.toString());
|
||||
assert.strictEqual(uri.toString(), editor.notebook.uri.toString());
|
||||
|
||||
assert.strictEqual(notebookDocumentsFromOnDidOpen.has(editor.document), true);
|
||||
assert.strictEqual(notebookDocumentsFromOnDidOpen.has(editor.notebook), true);
|
||||
|
||||
const includes = vscode.workspace.notebookDocuments.includes(editor.document);
|
||||
const includes = vscode.workspace.notebookDocuments.includes(editor.notebook);
|
||||
assert.strictEqual(true, includes);
|
||||
|
||||
sub.dispose();
|
||||
|
@ -104,7 +104,7 @@ import * as utils from '../utils';
|
|||
const resource = await utils.createRandomFile(undefined, undefined, '.nbdtest');
|
||||
const editor = await vscode.window.showNotebookDocument(resource);
|
||||
assert.ok(await openedEditor);
|
||||
assert.strictEqual(editor.document.uri.toString(), resource.toString());
|
||||
assert.strictEqual(editor.notebook.uri.toString(), resource.toString());
|
||||
});
|
||||
|
||||
test('Active/Visible Editor', async function () {
|
||||
|
|
|
@ -77,7 +77,7 @@ export class Kernel {
|
|||
|
||||
|
||||
function getFocusedCell(editor?: vscode.NotebookEditor) {
|
||||
return editor ? editor.document.cellAt(editor.selections[0].start) : undefined;
|
||||
return editor ? editor.notebook.cellAt(editor.selections[0].start) : undefined;
|
||||
}
|
||||
|
||||
async function assertKernel(kernel: Kernel, notebook: vscode.NotebookDocument): Promise<void> {
|
||||
|
@ -204,12 +204,12 @@ const apiTestContentProvider: vscode.NotebookContentProvider = {
|
|||
const cellsChangeEvent = asPromise<vscode.NotebookDocumentChangeEvent>(vscode.workspace.onDidChangeNotebookDocument);
|
||||
await vscode.commands.executeCommand('notebook.cell.insertCodeCellBelow');
|
||||
const cellChangeEventRet = await cellsChangeEvent;
|
||||
assert.strictEqual(cellChangeEventRet.notebook, editor.document);
|
||||
assert.strictEqual(cellChangeEventRet.notebook, editor.notebook);
|
||||
assert.strictEqual(cellChangeEventRet.contentChanges.length, 1);
|
||||
assert.deepStrictEqual(cellChangeEventRet.contentChanges[0], <vscode.NotebookDocumentContentChange>{
|
||||
range: new vscode.NotebookRange(1, 1),
|
||||
removedCells: [],
|
||||
addedCells: [editor.document.cellAt(1)]
|
||||
addedCells: [editor.notebook.cellAt(1)]
|
||||
});
|
||||
|
||||
const moveCellEvent = asPromise<vscode.NotebookDocumentChangeEvent>(vscode.workspace.onDidChangeNotebookDocument);
|
||||
|
@ -220,11 +220,11 @@ const apiTestContentProvider: vscode.NotebookContentProvider = {
|
|||
await vscode.commands.executeCommand('notebook.cell.execute');
|
||||
const cellOutputsAddedRet = await cellOutputChange;
|
||||
|
||||
assert.strictEqual(cellOutputsAddedRet.notebook.uri.toString(), editor.document.uri.toString());
|
||||
assert.strictEqual(cellOutputsAddedRet.notebook.uri.toString(), editor.notebook.uri.toString());
|
||||
assert.strictEqual(cellOutputsAddedRet.metadata, undefined);
|
||||
assert.strictEqual(cellOutputsAddedRet.contentChanges.length, 0);
|
||||
assert.strictEqual(cellOutputsAddedRet.cellChanges.length, 1);
|
||||
assert.deepStrictEqual(cellOutputsAddedRet.cellChanges[0].cell, editor.document.cellAt(0));
|
||||
assert.deepStrictEqual(cellOutputsAddedRet.cellChanges[0].cell, editor.notebook.cellAt(0));
|
||||
assert.deepStrictEqual(cellOutputsAddedRet.cellChanges[0].executionSummary, { executionOrder: undefined, success: undefined, timing: undefined }); // TODO@jrieken should this be undefined instead all empty?
|
||||
assert.strictEqual(cellOutputsAddedRet.cellChanges[0].document, undefined);
|
||||
assert.strictEqual(cellOutputsAddedRet.cellChanges[0].metadata, undefined);
|
||||
|
@ -235,15 +235,15 @@ const apiTestContentProvider: vscode.NotebookContentProvider = {
|
|||
await vscode.commands.executeCommand('notebook.cell.clearOutputs');
|
||||
const cellOutputsCleardRet = await cellOutputClear;
|
||||
assert.deepStrictEqual(cellOutputsCleardRet, <vscode.NotebookDocumentChangeEvent>{
|
||||
notebook: editor.document,
|
||||
notebook: editor.notebook,
|
||||
metadata: undefined,
|
||||
contentChanges: [],
|
||||
cellChanges: [{
|
||||
cell: editor.document.cellAt(0),
|
||||
cell: editor.notebook.cellAt(0),
|
||||
document: undefined,
|
||||
executionSummary: undefined,
|
||||
metadata: undefined,
|
||||
outputs: editor.document.cellAt(0).outputs
|
||||
outputs: editor.notebook.cellAt(0).outputs
|
||||
}],
|
||||
});
|
||||
assert.strictEqual(cellOutputsCleardRet.cellChanges[0].cell.outputs.length, 0);
|
||||
|
@ -289,21 +289,21 @@ const apiTestContentProvider: vscode.NotebookContentProvider = {
|
|||
const editor = await vscode.window.showNotebookDocument(notebook);
|
||||
|
||||
const notebookChangeEvent = asPromise<vscode.NotebookDocumentChangeEvent>(vscode.workspace.onDidChangeNotebookDocument);
|
||||
const version = editor.document.version;
|
||||
const version = editor.notebook.version;
|
||||
await editor.edit(editBuilder => {
|
||||
editBuilder.replaceCells(1, 0, [{ kind: vscode.NotebookCellKind.Code, languageId: 'javascript', value: 'test 2', outputs: [], metadata: undefined }]);
|
||||
editBuilder.replaceCellMetadata(0, { inputCollapsed: false });
|
||||
});
|
||||
|
||||
await notebookChangeEvent;
|
||||
assert.strictEqual(editor.document.cellCount, 3);
|
||||
assert.strictEqual(editor.document.cellAt(0)?.metadata.inputCollapsed, false);
|
||||
assert.strictEqual(version + 1, editor.document.version);
|
||||
assert.strictEqual(editor.notebook.cellCount, 3);
|
||||
assert.strictEqual(editor.notebook.cellAt(0)?.metadata.inputCollapsed, false);
|
||||
assert.strictEqual(version + 1, editor.notebook.version);
|
||||
|
||||
await vscode.commands.executeCommand('undo');
|
||||
assert.strictEqual(version + 2, editor.document.version);
|
||||
assert.strictEqual(editor.document.cellAt(0)?.metadata.inputCollapsed, undefined);
|
||||
assert.strictEqual(editor.document.cellCount, 2);
|
||||
assert.strictEqual(version + 2, editor.notebook.version);
|
||||
assert.strictEqual(editor.notebook.cellAt(0)?.metadata.inputCollapsed, undefined);
|
||||
assert.strictEqual(editor.notebook.cellCount, 2);
|
||||
});
|
||||
|
||||
// #126371
|
||||
|
@ -326,7 +326,7 @@ const apiTestContentProvider: vscode.NotebookContentProvider = {
|
|||
assert.strictEqual(getFocusedCell(editor)?.document.getText(), 'test');
|
||||
assert.strictEqual(getFocusedCell(editor)?.document.languageId, 'typescript');
|
||||
|
||||
const secondCell = editor.document.cellAt(1);
|
||||
const secondCell = editor.notebook.cellAt(1);
|
||||
assert.strictEqual(secondCell.outputs.length, 1);
|
||||
assert.deepStrictEqual(secondCell.outputs[0].metadata, { testOutputMetadata: true, ['text/plain']: { testOutputItemMetadata: true } });
|
||||
assert.strictEqual(secondCell.outputs[0].items.length, 1);
|
||||
|
@ -353,22 +353,22 @@ const apiTestContentProvider: vscode.NotebookContentProvider = {
|
|||
let activeCell = getFocusedCell(editor);
|
||||
assert.notStrictEqual(getFocusedCell(editor), undefined);
|
||||
assert.strictEqual(activeCell!.document.getText(), '');
|
||||
assert.strictEqual(editor.document.cellCount, 4);
|
||||
assert.strictEqual(editor.document.getCells().indexOf(activeCell!), 1);
|
||||
assert.strictEqual(editor.notebook.cellCount, 4);
|
||||
assert.strictEqual(editor.notebook.getCells().indexOf(activeCell!), 1);
|
||||
|
||||
// ---- focus bottom ---- //
|
||||
await vscode.commands.executeCommand('notebook.focusBottom');
|
||||
activeCell = getFocusedCell(editor);
|
||||
assert.strictEqual(editor.document.getCells().indexOf(activeCell!), 3);
|
||||
assert.strictEqual(editor.notebook.getCells().indexOf(activeCell!), 3);
|
||||
|
||||
// ---- focus top and then copy down ---- //
|
||||
await vscode.commands.executeCommand('notebook.focusTop');
|
||||
activeCell = getFocusedCell(editor);
|
||||
assert.strictEqual(editor.document.getCells().indexOf(activeCell!), 0);
|
||||
assert.strictEqual(editor.notebook.getCells().indexOf(activeCell!), 0);
|
||||
|
||||
await vscode.commands.executeCommand('notebook.cell.copyDown');
|
||||
activeCell = getFocusedCell(editor);
|
||||
assert.strictEqual(editor.document.getCells().indexOf(activeCell!), 1);
|
||||
assert.strictEqual(editor.notebook.getCells().indexOf(activeCell!), 1);
|
||||
assert.strictEqual(activeCell?.document.getText(), 'test');
|
||||
|
||||
{
|
||||
|
@ -381,25 +381,25 @@ const apiTestContentProvider: vscode.NotebookContentProvider = {
|
|||
}
|
||||
|
||||
activeCell = getFocusedCell(editor);
|
||||
assert.strictEqual(editor.document.getCells().indexOf(activeCell!), 1);
|
||||
assert.strictEqual(editor.notebook.getCells().indexOf(activeCell!), 1);
|
||||
assert.strictEqual(activeCell?.document.getText(), '');
|
||||
|
||||
// ---- focus top and then copy up ---- //
|
||||
await vscode.commands.executeCommand('notebook.focusTop');
|
||||
await vscode.commands.executeCommand('notebook.cell.copyUp');
|
||||
assert.strictEqual(editor.document.cellCount, 5);
|
||||
assert.strictEqual(editor.document.cellAt(0).document.getText(), 'test');
|
||||
assert.strictEqual(editor.document.cellAt(1).document.getText(), 'test');
|
||||
assert.strictEqual(editor.document.cellAt(2).document.getText(), '');
|
||||
assert.strictEqual(editor.document.cellAt(3).document.getText(), '');
|
||||
assert.strictEqual(editor.notebook.cellCount, 5);
|
||||
assert.strictEqual(editor.notebook.cellAt(0).document.getText(), 'test');
|
||||
assert.strictEqual(editor.notebook.cellAt(1).document.getText(), 'test');
|
||||
assert.strictEqual(editor.notebook.cellAt(2).document.getText(), '');
|
||||
assert.strictEqual(editor.notebook.cellAt(3).document.getText(), '');
|
||||
activeCell = getFocusedCell(editor);
|
||||
assert.strictEqual(editor.document.getCells().indexOf(activeCell!), 0);
|
||||
assert.strictEqual(editor.notebook.getCells().indexOf(activeCell!), 0);
|
||||
|
||||
|
||||
// ---- move up and down ---- //
|
||||
|
||||
await vscode.commands.executeCommand('notebook.cell.moveDown');
|
||||
assert.strictEqual(editor.document.getCells().indexOf(getFocusedCell(editor)!), 1,
|
||||
assert.strictEqual(editor.notebook.getCells().indexOf(getFocusedCell(editor)!), 1,
|
||||
`first move down, active cell ${getFocusedCell(editor)!.document.uri.toString()}, ${getFocusedCell(editor)!.document.getText()}`);
|
||||
|
||||
await vscode.commands.executeCommand('workbench.action.files.save');
|
||||
|
@ -427,7 +427,7 @@ const apiTestContentProvider: vscode.NotebookContentProvider = {
|
|||
// assert.strictEqual(vscode.window.activeNotebookEditor !== undefined, true, 'notebook first');
|
||||
// const editor = vscode.window.activeNotebookEditor!;
|
||||
|
||||
// const cell = editor.document.cellAt(0);
|
||||
// const cell = editor.notebook.cellAt(0);
|
||||
// assert.strictEqual(cell.outputs.length, 0);
|
||||
|
||||
// currentKernelProvider.setHasKernels(false);
|
||||
|
@ -452,7 +452,7 @@ const apiTestContentProvider: vscode.NotebookContentProvider = {
|
|||
await vscode.commands.executeCommand('vscode.openWith', resource, 'notebookCoreTest');
|
||||
assert.strictEqual(vscode.window.activeNotebookEditor !== undefined, true, 'notebook first');
|
||||
const editor = vscode.window.activeNotebookEditor!;
|
||||
const cell = editor.document.cellAt(0);
|
||||
const cell = editor.notebook.cellAt(0);
|
||||
|
||||
await vscode.commands.executeCommand('notebook.execute');
|
||||
assert.strictEqual(cell.outputs.length, 0, 'should not execute'); // not runnable, didn't work
|
||||
|
@ -463,7 +463,7 @@ const apiTestContentProvider: vscode.NotebookContentProvider = {
|
|||
await vscode.commands.executeCommand('vscode.openWith', resource, 'notebookCoreTest');
|
||||
assert.strictEqual(vscode.window.activeNotebookEditor !== undefined, true, 'notebook first');
|
||||
const editor = vscode.window.activeNotebookEditor!;
|
||||
const cell = editor.document.cellAt(0);
|
||||
const cell = editor.notebook.cellAt(0);
|
||||
|
||||
await withEvent(vscode.workspace.onDidChangeNotebookDocument, async (event) => {
|
||||
await vscode.commands.executeCommand('notebook.execute');
|
||||
|
@ -484,7 +484,7 @@ const apiTestContentProvider: vscode.NotebookContentProvider = {
|
|||
await vscode.commands.executeCommand('notebook.cell.execute', { start: 0, end: 1 }, resource);
|
||||
await event;
|
||||
assert.strictEqual(cell.outputs.length, 1, 'should execute'); // runnable, it worked
|
||||
assert.strictEqual(vscode.window.activeNotebookEditor?.document.uri.fsPath, secondResource.fsPath);
|
||||
assert.strictEqual(vscode.window.activeNotebookEditor?.notebook.uri.fsPath, secondResource.fsPath);
|
||||
});
|
||||
});
|
||||
|
||||
|
@ -524,7 +524,7 @@ const apiTestContentProvider: vscode.NotebookContentProvider = {
|
|||
await vscode.commands.executeCommand('vscode.openWith', resource, 'notebookCoreTest');
|
||||
assert.strictEqual(vscode.window.activeNotebookEditor !== undefined, true, 'notebook first');
|
||||
const editor = vscode.window.activeNotebookEditor!;
|
||||
const cell = editor.document.cellAt(0);
|
||||
const cell = editor.notebook.cellAt(0);
|
||||
|
||||
await withEvent<vscode.NotebookDocumentChangeEvent>(vscode.workspace.onDidChangeNotebookDocument, async (event) => {
|
||||
await vscode.commands.executeCommand('notebook.execute');
|
||||
|
@ -544,7 +544,7 @@ const apiTestContentProvider: vscode.NotebookContentProvider = {
|
|||
await vscode.commands.executeCommand('notebook.execute', resource);
|
||||
await event;
|
||||
assert.strictEqual(cell.outputs.length, 1, 'should execute'); // runnable, it worked
|
||||
assert.strictEqual(vscode.window.activeNotebookEditor?.document.uri.fsPath, secondResource.fsPath);
|
||||
assert.strictEqual(vscode.window.activeNotebookEditor?.notebook.uri.fsPath, secondResource.fsPath);
|
||||
});
|
||||
});
|
||||
|
||||
|
@ -553,7 +553,7 @@ const apiTestContentProvider: vscode.NotebookContentProvider = {
|
|||
const editor = await vscode.window.showNotebookDocument(notebook);
|
||||
assert.strictEqual(vscode.window.activeNotebookEditor === editor, true, 'notebook first');
|
||||
|
||||
const cell = editor.document.cellAt(0);
|
||||
const cell = editor.notebook.cellAt(0);
|
||||
|
||||
const alternativeKernel = new class extends Kernel {
|
||||
constructor() {
|
||||
|
@ -597,7 +597,7 @@ const apiTestContentProvider: vscode.NotebookContentProvider = {
|
|||
const resource = await createRandomNotebookFile();
|
||||
await vscode.commands.executeCommand('vscode.openWith', resource, 'notebookCoreTest');
|
||||
const editor = vscode.window.activeNotebookEditor!;
|
||||
const cell = editor.document.cellAt(0);
|
||||
const cell = editor.notebook.cellAt(0);
|
||||
|
||||
vscode.commands.executeCommand('notebook.cell.execute');
|
||||
let eventCount = 0;
|
||||
|
@ -636,8 +636,8 @@ const apiTestContentProvider: vscode.NotebookContentProvider = {
|
|||
const activeCell = getFocusedCell(editor);
|
||||
assert.notStrictEqual(getFocusedCell(editor), undefined);
|
||||
assert.strictEqual(activeCell!.document.getText(), '');
|
||||
assert.strictEqual(editor.document.cellCount, 4);
|
||||
assert.strictEqual(editor.document.getCells().indexOf(activeCell!), 1);
|
||||
assert.strictEqual(editor.notebook.cellCount, 4);
|
||||
assert.strictEqual(editor.notebook.getCells().indexOf(activeCell!), 1);
|
||||
|
||||
await withEvent(vscode.workspace.onDidChangeTextDocument, async event => {
|
||||
const edit = new vscode.WorkspaceEdit();
|
||||
|
@ -645,7 +645,7 @@ const apiTestContentProvider: vscode.NotebookContentProvider = {
|
|||
await vscode.workspace.applyEdit(edit);
|
||||
await event;
|
||||
assert.strictEqual(vscode.window.activeNotebookEditor === editor, true);
|
||||
assert.deepStrictEqual(editor.document.cellAt(1), getFocusedCell(editor));
|
||||
assert.deepStrictEqual(editor.notebook.cellAt(1), getFocusedCell(editor));
|
||||
assert.strictEqual(getFocusedCell(editor)?.document.getText(), 'var abc = 0;');
|
||||
});
|
||||
});
|
||||
|
@ -667,8 +667,8 @@ const apiTestContentProvider: vscode.NotebookContentProvider = {
|
|||
|
||||
// make sure that the previous dirty editor is still restored in the extension host and no data loss
|
||||
assert.strictEqual(vscode.window.activeNotebookEditor !== undefined, true);
|
||||
assert.deepStrictEqual(vscode.window.activeNotebookEditor?.document.cellAt(1), getFocusedCell(vscode.window.activeNotebookEditor));
|
||||
assert.deepStrictEqual(vscode.window.activeNotebookEditor?.document.cellCount, 4);
|
||||
assert.deepStrictEqual(vscode.window.activeNotebookEditor?.notebook.cellAt(1), getFocusedCell(vscode.window.activeNotebookEditor));
|
||||
assert.deepStrictEqual(vscode.window.activeNotebookEditor?.notebook.cellCount, 4);
|
||||
assert.strictEqual(getFocusedCell(vscode.window.activeNotebookEditor)?.document.getText(), 'var abc = 0;');
|
||||
|
||||
});
|
||||
|
@ -692,15 +692,15 @@ const apiTestContentProvider: vscode.NotebookContentProvider = {
|
|||
// switch to the first editor
|
||||
await vscode.window.showNotebookDocument(notebook);
|
||||
assert.strictEqual(vscode.window.activeNotebookEditor !== undefined, true);
|
||||
assert.deepStrictEqual(vscode.window.activeNotebookEditor?.document.cellAt(1), getFocusedCell(vscode.window.activeNotebookEditor));
|
||||
assert.deepStrictEqual(vscode.window.activeNotebookEditor?.document.cellCount, 4);
|
||||
assert.deepStrictEqual(vscode.window.activeNotebookEditor?.notebook.cellAt(1), getFocusedCell(vscode.window.activeNotebookEditor));
|
||||
assert.deepStrictEqual(vscode.window.activeNotebookEditor?.notebook.cellCount, 4);
|
||||
assert.strictEqual(getFocusedCell(vscode.window.activeNotebookEditor)?.document.getText(), 'var abc = 0;');
|
||||
|
||||
// switch to the second editor
|
||||
await vscode.window.showNotebookDocument(secondNotebook);
|
||||
assert.strictEqual(vscode.window.activeNotebookEditor !== undefined, true);
|
||||
assert.deepStrictEqual(vscode.window.activeNotebookEditor?.document.cellAt(1), getFocusedCell(vscode.window.activeNotebookEditor));
|
||||
assert.deepStrictEqual(vscode.window.activeNotebookEditor?.document.cellCount, 3);
|
||||
assert.deepStrictEqual(vscode.window.activeNotebookEditor?.notebook.cellAt(1), getFocusedCell(vscode.window.activeNotebookEditor));
|
||||
assert.deepStrictEqual(vscode.window.activeNotebookEditor?.notebook.cellCount, 3);
|
||||
assert.strictEqual(getFocusedCell(vscode.window.activeNotebookEditor)?.document.getText(), '');
|
||||
|
||||
});
|
||||
|
@ -721,7 +721,7 @@ const apiTestContentProvider: vscode.NotebookContentProvider = {
|
|||
assert.strictEqual(getFocusedCell(vscode.window.activeNotebookEditor!)?.document.languageId, 'typescript');
|
||||
|
||||
assert.notStrictEqual(firstNotebookEditor, secondNotebookEditor);
|
||||
assert.strictEqual(firstNotebookEditor?.document, secondNotebookEditor?.document, 'split notebook editors share the same document');
|
||||
assert.strictEqual(firstNotebookEditor?.notebook, secondNotebookEditor?.notebook, 'split notebook editors share the same document');
|
||||
|
||||
});
|
||||
|
||||
|
@ -737,7 +737,7 @@ const apiTestContentProvider: vscode.NotebookContentProvider = {
|
|||
// await vscode.commands.executeCommand('vscode.open', cell.document.uri, vscode.ViewColumn.Active);
|
||||
|
||||
assert.strictEqual(!!vscode.window.activeNotebookEditor, true);
|
||||
assert.strictEqual(vscode.window.activeNotebookEditor!.document.uri.toString(), document.uri.toString());
|
||||
assert.strictEqual(vscode.window.activeNotebookEditor!.notebook.uri.toString(), document.uri.toString());
|
||||
});
|
||||
|
||||
test('Cannot open notebook from cell-uri with vscode.open-command', async function () {
|
||||
|
@ -752,7 +752,7 @@ const apiTestContentProvider: vscode.NotebookContentProvider = {
|
|||
// removes the fragment if it matches something numeric. For notebooks that's not wanted...
|
||||
await vscode.commands.executeCommand('vscode.open', cell.document.uri);
|
||||
|
||||
assert.strictEqual(vscode.window.activeNotebookEditor!.document.uri.toString(), document.uri.toString());
|
||||
assert.strictEqual(vscode.window.activeNotebookEditor!.notebook.uri.toString(), document.uri.toString());
|
||||
});
|
||||
|
||||
test('#97830, #97764. Support switch to other editor types', async function () {
|
||||
|
@ -805,15 +805,15 @@ const apiTestContentProvider: vscode.NotebookContentProvider = {
|
|||
await vscode.commands.executeCommand('notebook.cell.copyDown');
|
||||
await vscode.commands.executeCommand('notebook.cell.edit');
|
||||
activeCell = getFocusedCell(vscode.window.activeNotebookEditor);
|
||||
assert.strictEqual(vscode.window.activeNotebookEditor!.document.getCells().indexOf(activeCell!), 1);
|
||||
assert.strictEqual(vscode.window.activeNotebookEditor!.notebook.getCells().indexOf(activeCell!), 1);
|
||||
assert.strictEqual(activeCell?.document.getText(), 'test');
|
||||
|
||||
const edit = new vscode.WorkspaceEdit();
|
||||
edit.insert(getFocusedCell(vscode.window.activeNotebookEditor)!.document.uri, new vscode.Position(0, 0), 'var abc = 0;');
|
||||
await vscode.workspace.applyEdit(edit);
|
||||
|
||||
assert.strictEqual(vscode.window.activeNotebookEditor!.document.getCells().length, 3);
|
||||
assert.notStrictEqual(vscode.window.activeNotebookEditor!.document.cellAt(0).document.getText(), vscode.window.activeNotebookEditor!.document.cellAt(1).document.getText());
|
||||
assert.strictEqual(vscode.window.activeNotebookEditor!.notebook.getCells().length, 3);
|
||||
assert.notStrictEqual(vscode.window.activeNotebookEditor!.notebook.cellAt(0).document.getText(), vscode.window.activeNotebookEditor!.notebook.cellAt(1).document.getText());
|
||||
|
||||
await closeAllEditors();
|
||||
});
|
||||
|
@ -876,7 +876,7 @@ const apiTestContentProvider: vscode.NotebookContentProvider = {
|
|||
const resource = await createRandomNotebookFile();
|
||||
await vscode.commands.executeCommand('vscode.openWith', resource, 'notebookCoreTest');
|
||||
const editor = vscode.window.activeNotebookEditor!;
|
||||
const cell = editor.document.cellAt(0);
|
||||
const cell = editor.notebook.cellAt(0);
|
||||
|
||||
assert.strictEqual(cell.executionSummary?.success, undefined);
|
||||
assert.strictEqual(cell.executionSummary?.executionOrder, undefined);
|
||||
|
@ -999,7 +999,7 @@ const apiTestContentProvider: vscode.NotebookContentProvider = {
|
|||
const notebook = await openRandomNotebookDocument();
|
||||
const editor = await vscode.window.showNotebookDocument(notebook);
|
||||
|
||||
assert.strictEqual(editor.document.metadata.custom?.testMetadata, false);
|
||||
assert.strictEqual(editor.notebook.metadata.custom?.testMetadata, false);
|
||||
assert.strictEqual(getFocusedCell(editor)?.metadata.custom?.testCellMetadata, 123);
|
||||
assert.strictEqual(getFocusedCell(editor)?.document.languageId, 'typescript');
|
||||
});
|
||||
|
|
|
@ -200,7 +200,7 @@
|
|||
"style-loader": "^1.0.0",
|
||||
"ts-loader": "^9.2.7",
|
||||
"tsec": "0.1.4",
|
||||
"typescript": "^4.8.0-dev.20220518",
|
||||
"typescript": "^4.8.0-dev.20220608",
|
||||
"typescript-formatter": "7.1.0",
|
||||
"underscore": "^1.12.1",
|
||||
"util": "^0.12.4",
|
||||
|
|
|
@ -724,10 +724,21 @@ export interface CodeActionProvider {
|
|||
/**
|
||||
* @internal
|
||||
*/
|
||||
export interface DocumentPasteEditProvider {
|
||||
prepareDocumentPaste?(model: model.ITextModel, selection: Selection, dataTransfer: VSDataTransfer, token: CancellationToken): Promise<undefined | VSDataTransfer>;
|
||||
export interface DocumentPasteEdit {
|
||||
insertText: string | { snippet: string };
|
||||
additionalEdit?: WorkspaceEdit;
|
||||
}
|
||||
|
||||
provideDocumentPasteEdits(model: model.ITextModel, selection: Selection, dataTransfer: VSDataTransfer, token: CancellationToken): Promise<WorkspaceEdit | SnippetTextEdit | undefined>;
|
||||
/**
|
||||
* @internal
|
||||
*/
|
||||
export interface DocumentPasteEditProvider {
|
||||
|
||||
readonly pasteMimeTypes: readonly string[];
|
||||
|
||||
prepareDocumentPaste?(model: model.ITextModel, selections: readonly Selection[], dataTransfer: VSDataTransfer, token: CancellationToken): Promise<undefined | VSDataTransfer>;
|
||||
|
||||
provideDocumentPasteEdits(model: model.ITextModel, selections: readonly Selection[], dataTransfer: VSDataTransfer, token: CancellationToken): Promise<DocumentPasteEdit | undefined>;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -1123,11 +1134,6 @@ export interface DocumentSymbolProvider {
|
|||
|
||||
export type TextEdit = { range: IRange; text: string; eol?: model.EndOfLineSequence };
|
||||
|
||||
export interface SnippetTextEdit {
|
||||
range: IRange;
|
||||
snippet: string;
|
||||
}
|
||||
|
||||
/**
|
||||
* Interface used to format a model
|
||||
*/
|
||||
|
@ -1800,10 +1806,17 @@ export enum ExternalUriOpenerPriority {
|
|||
Preferred = 3,
|
||||
}
|
||||
|
||||
/**
|
||||
* @internal
|
||||
*/
|
||||
export interface DocumentOnDropEdit {
|
||||
insertText: string | { snippet: string };
|
||||
additionalEdit?: WorkspaceEdit;
|
||||
}
|
||||
|
||||
/**
|
||||
* @internal
|
||||
*/
|
||||
export interface DocumentOnDropEditProvider {
|
||||
provideDocumentOnDropEdits(model: model.ITextModel, position: IPosition, dataTransfer: VSDataTransfer, token: CancellationToken): ProviderResult<SnippetTextEdit>;
|
||||
provideDocumentOnDropEdits(model: model.ITextModel, position: IPosition, dataTransfer: VSDataTransfer, token: CancellationToken): ProviderResult<DocumentOnDropEdit>;
|
||||
}
|
||||
|
|
|
@ -3,6 +3,7 @@
|
|||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import { DataTransfers } from 'vs/base/browser/dnd';
|
||||
import { addDisposableListener } from 'vs/base/browser/dom';
|
||||
import { CancelablePromise, createCancelablePromise } from 'vs/base/common/async';
|
||||
import { CancellationToken } from 'vs/base/common/cancellation';
|
||||
|
@ -15,26 +16,26 @@ import { ICodeEditor } from 'vs/editor/browser/editorBrowser';
|
|||
import { IBulkEditService, ResourceEdit } from 'vs/editor/browser/services/bulkEditService';
|
||||
import { Selection } from 'vs/editor/common/core/selection';
|
||||
import { IEditorContribution } from 'vs/editor/common/editorCommon';
|
||||
import { DocumentPasteEditProvider, SnippetTextEdit, WorkspaceEdit } from 'vs/editor/common/languages';
|
||||
import { DocumentPasteEdit, DocumentPasteEditProvider } from 'vs/editor/common/languages';
|
||||
import { ITextModel } from 'vs/editor/common/model';
|
||||
import { ILanguageFeaturesService } from 'vs/editor/common/services/languageFeatures';
|
||||
import { CodeEditorStateFlag, EditorStateCancellationTokenSource } from 'vs/editor/contrib/editorState/browser/editorState';
|
||||
import { performSnippetEdit } from 'vs/editor/contrib/snippet/browser/snippetController2';
|
||||
import { SnippetParser } from 'vs/editor/contrib/snippet/browser/snippetParser';
|
||||
import { IClipboardService } from 'vs/platform/clipboard/common/clipboardService';
|
||||
import { IConfigurationService } from 'vs/platform/configuration/common/configuration';
|
||||
|
||||
const vscodeClipboardMime = 'application/vnd.code.copyId';
|
||||
|
||||
const defaultPasteEditProvider = new class implements DocumentPasteEditProvider {
|
||||
async provideDocumentPasteEdits(model: ITextModel, selection: Selection, dataTransfer: VSDataTransfer, _token: CancellationToken): Promise<WorkspaceEdit | undefined> {
|
||||
pasteMimeTypes = [Mimes.text, 'text'];
|
||||
|
||||
async provideDocumentPasteEdits(model: ITextModel, selections: Selection[], dataTransfer: VSDataTransfer, _token: CancellationToken): Promise<DocumentPasteEdit | undefined> {
|
||||
const textDataTransfer = dataTransfer.get(Mimes.text) ?? dataTransfer.get('text');
|
||||
if (textDataTransfer) {
|
||||
const text = await textDataTransfer.asString();
|
||||
return {
|
||||
edits: [{
|
||||
resource: model.uri,
|
||||
edit: { range: selection, text },
|
||||
}]
|
||||
insertText: text
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -76,8 +77,8 @@ export class CopyPasteController extends Disposable implements IEditorContributi
|
|||
}
|
||||
|
||||
const model = editor.getModel();
|
||||
const selection = this._editor.getSelection();
|
||||
if (!model || !selection) {
|
||||
const selections = this._editor.getSelections();
|
||||
if (!model || !selections?.length) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -98,7 +99,7 @@ export class CopyPasteController extends Disposable implements IEditorContributi
|
|||
|
||||
const promise = createCancelablePromise(async token => {
|
||||
const results = await Promise.all(providers.map(provider => {
|
||||
return provider.prepareDocumentPaste!(model, selection, dataTransfer, token);
|
||||
return provider.prepareDocumentPaste!(model, selections, dataTransfer, token);
|
||||
}));
|
||||
|
||||
for (const result of results) {
|
||||
|
@ -115,8 +116,8 @@ export class CopyPasteController extends Disposable implements IEditorContributi
|
|||
}));
|
||||
|
||||
this._register(addDisposableListener(container, 'paste', async (e: ClipboardEvent) => {
|
||||
const selection = this._editor.getSelection();
|
||||
if (!e.clipboardData || !selection || !editor.hasModel()) {
|
||||
const selections = this._editor.getSelections();
|
||||
if (!e.clipboardData || !selections?.length || !editor.hasModel()) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -125,21 +126,20 @@ export class CopyPasteController extends Disposable implements IEditorContributi
|
|||
return;
|
||||
}
|
||||
|
||||
const originalDocVersion = model.getVersionId();
|
||||
const handle = e.clipboardData?.getData(vscodeClipboardMime);
|
||||
if (typeof handle !== 'string') {
|
||||
return;
|
||||
}
|
||||
|
||||
const providers = this._languageFeaturesService.documentPasteEditProvider.ordered(model);
|
||||
if (!providers.length) {
|
||||
return;
|
||||
}
|
||||
|
||||
const handle = e.clipboardData?.getData(vscodeClipboardMime);
|
||||
if (typeof handle !== 'string') {
|
||||
return;
|
||||
}
|
||||
|
||||
e.preventDefault();
|
||||
e.stopImmediatePropagation();
|
||||
|
||||
const originalDocVersion = model.getVersionId();
|
||||
const tokenSource = new EditorStateCancellationTokenSource(editor, CodeEditorStateFlag.Value | CodeEditorStateFlag.Selection);
|
||||
|
||||
try {
|
||||
|
@ -148,7 +148,7 @@ export class CopyPasteController extends Disposable implements IEditorContributi
|
|||
if (handle && this._currentClipboardItem?.handle === handle) {
|
||||
const toMergeDataTransfer = await this._currentClipboardItem.dataTransferPromise;
|
||||
toMergeDataTransfer.forEach((value, key) => {
|
||||
dataTransfer.append(key, value);
|
||||
dataTransfer.replace(key, value);
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -163,16 +163,25 @@ export class CopyPasteController extends Disposable implements IEditorContributi
|
|||
dataTransfer.delete(vscodeClipboardMime);
|
||||
|
||||
for (const provider of [...providers, defaultPasteEditProvider]) {
|
||||
const edit = await provider.provideDocumentPasteEdits(model, selection, dataTransfer, tokenSource.token);
|
||||
if (!provider.pasteMimeTypes.some(type => {
|
||||
if (type.toLowerCase() === DataTransfers.FILES.toLowerCase()) {
|
||||
return [...dataTransfer.values()].some(item => item.asFile());
|
||||
}
|
||||
return dataTransfer.has(type);
|
||||
})) {
|
||||
continue;
|
||||
}
|
||||
|
||||
const edit = await provider.provideDocumentPasteEdits(model, selections, dataTransfer, tokenSource.token);
|
||||
if (originalDocVersion !== model.getVersionId()) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (edit) {
|
||||
if ((edit as WorkspaceEdit).edits) {
|
||||
await this._bulkEditService.apply(ResourceEdit.convert(edit as WorkspaceEdit), { editor });
|
||||
} else {
|
||||
performSnippetEdit(editor, edit as SnippetTextEdit);
|
||||
performSnippetEdit(editor, typeof edit.insertText === 'string' ? SnippetParser.escape(edit.insertText) : edit.insertText.snippet, selections);
|
||||
|
||||
if (edit.additionalEdit) {
|
||||
await this._bulkEditService.apply(ResourceEdit.convert(edit.additionalEdit), { editor });
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
|
|
@ -13,14 +13,17 @@ import { URI } from 'vs/base/common/uri';
|
|||
import { toVSDataTransfer } from 'vs/editor/browser/dnd';
|
||||
import { ICodeEditor } from 'vs/editor/browser/editorBrowser';
|
||||
import { registerEditorContribution } from 'vs/editor/browser/editorExtensions';
|
||||
import { IBulkEditService, ResourceEdit } from 'vs/editor/browser/services/bulkEditService';
|
||||
import { IPosition } from 'vs/editor/common/core/position';
|
||||
import { Range } from 'vs/editor/common/core/range';
|
||||
import { Selection, SelectionDirection } from 'vs/editor/common/core/selection';
|
||||
import { IEditorContribution } from 'vs/editor/common/editorCommon';
|
||||
import { DocumentOnDropEditProvider, SnippetTextEdit } from 'vs/editor/common/languages';
|
||||
import { DocumentOnDropEdit, DocumentOnDropEditProvider } from 'vs/editor/common/languages';
|
||||
import { ITextModel } from 'vs/editor/common/model';
|
||||
import { ILanguageFeaturesService } from 'vs/editor/common/services/languageFeatures';
|
||||
import { CodeEditorStateFlag, EditorStateCancellationTokenSource } from 'vs/editor/contrib/editorState/browser/editorState';
|
||||
import { performSnippetEdit } from 'vs/editor/contrib/snippet/browser/snippetController2';
|
||||
import { SnippetParser } from 'vs/editor/contrib/snippet/browser/snippetParser';
|
||||
import { IConfigurationService } from 'vs/platform/configuration/common/configuration';
|
||||
import { extractEditorsDropData } from 'vs/platform/dnd/browser/dnd';
|
||||
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
|
||||
|
@ -37,6 +40,7 @@ export class DropIntoEditorController extends Disposable implements IEditorContr
|
|||
@IInstantiationService private readonly _instantiationService: IInstantiationService,
|
||||
@ILanguageFeaturesService private readonly _languageFeaturesService: ILanguageFeaturesService,
|
||||
@IConfigurationService private readonly _configurationService: IConfigurationService,
|
||||
@IBulkEditService private readonly _bulkEditService: IBulkEditService,
|
||||
) {
|
||||
super();
|
||||
|
||||
|
@ -87,7 +91,12 @@ export class DropIntoEditorController extends Disposable implements IEditorContr
|
|||
}
|
||||
|
||||
if (edit) {
|
||||
performSnippetEdit(editor, edit);
|
||||
const range = new Range(position.lineNumber, position.column, position.lineNumber, position.column);
|
||||
performSnippetEdit(editor, typeof edit.insertText === 'string' ? SnippetParser.escape(edit.insertText) : edit.insertText.snippet, [Selection.fromRange(range, SelectionDirection.LTR)]);
|
||||
|
||||
if (edit.additionalEdit) {
|
||||
await this._bulkEditService.apply(ResourceEdit.convert(edit.additionalEdit), { editor });
|
||||
}
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
@ -121,24 +130,26 @@ class DefaultOnDropProvider implements DocumentOnDropEditProvider {
|
|||
@IWorkspaceContextService private readonly _workspaceContextService: IWorkspaceContextService,
|
||||
) { }
|
||||
|
||||
async provideDocumentOnDropEdits(model: ITextModel, position: IPosition, dataTransfer: VSDataTransfer, _token: CancellationToken): Promise<SnippetTextEdit | undefined> {
|
||||
const range = new Range(position.lineNumber, position.column, position.lineNumber, position.column);
|
||||
|
||||
async provideDocumentOnDropEdits(_model: ITextModel, _position: IPosition, dataTransfer: VSDataTransfer, _token: CancellationToken): Promise<DocumentOnDropEdit | undefined> {
|
||||
const urlListEntry = dataTransfer.get('text/uri-list');
|
||||
if (urlListEntry) {
|
||||
const urlList = await urlListEntry.asString();
|
||||
return this.doUriListDrop(range, urlList);
|
||||
const snippet = this.getUriListInsertText(urlList);
|
||||
if (snippet) {
|
||||
return { insertText: snippet };
|
||||
}
|
||||
}
|
||||
|
||||
const textEntry = dataTransfer.get('text') ?? dataTransfer.get(Mimes.text);
|
||||
if (textEntry) {
|
||||
const text = await textEntry.asString();
|
||||
return { range, snippet: text };
|
||||
return { insertText: text };
|
||||
}
|
||||
|
||||
return undefined;
|
||||
}
|
||||
|
||||
private doUriListDrop(range: Range, urlList: string): SnippetTextEdit | undefined {
|
||||
private getUriListInsertText(urlList: string): string | undefined {
|
||||
const uris: URI[] = [];
|
||||
for (const resource of urlList.split('\n')) {
|
||||
try {
|
||||
|
@ -152,7 +163,7 @@ class DefaultOnDropProvider implements DocumentOnDropEditProvider {
|
|||
return;
|
||||
}
|
||||
|
||||
const snippet = uris
|
||||
return uris
|
||||
.map(uri => {
|
||||
const root = this._workspaceContextService.getWorkspaceFolder(uri);
|
||||
if (root) {
|
||||
|
@ -164,8 +175,6 @@ class DefaultOnDropProvider implements DocumentOnDropEditProvider {
|
|||
return uri.fsPath;
|
||||
})
|
||||
.join(' ');
|
||||
|
||||
return { range, snippet };
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -9,9 +9,10 @@ import { ICodeEditor } from 'vs/editor/browser/editorBrowser';
|
|||
import { EditorCommand, registerEditorCommand, registerEditorContribution } from 'vs/editor/browser/editorExtensions';
|
||||
import { Position } from 'vs/editor/common/core/position';
|
||||
import { Range } from 'vs/editor/common/core/range';
|
||||
import { ISelection } from 'vs/editor/common/core/selection';
|
||||
import { IEditorContribution } from 'vs/editor/common/editorCommon';
|
||||
import { EditorContextKeys } from 'vs/editor/common/editorContextKeys';
|
||||
import { CompletionItem, CompletionItemKind, CompletionItemProvider, SnippetTextEdit } from 'vs/editor/common/languages';
|
||||
import { CompletionItem, CompletionItemKind, CompletionItemProvider } from 'vs/editor/common/languages';
|
||||
import { ILanguageConfigurationService } from 'vs/editor/common/languages/languageConfigurationRegistry';
|
||||
import { ITextModel } from 'vs/editor/common/model';
|
||||
import { ILanguageFeaturesService } from 'vs/editor/common/services/languageFeatures';
|
||||
|
@ -335,13 +336,13 @@ registerEditorCommand(new CommandCtor({
|
|||
|
||||
// ---
|
||||
|
||||
export function performSnippetEdit(editor: ICodeEditor, edit: SnippetTextEdit) {
|
||||
export function performSnippetEdit(editor: ICodeEditor, snippet: string, selections: ISelection[]): boolean {
|
||||
const controller = SnippetController2.get(editor);
|
||||
if (!controller) {
|
||||
return false;
|
||||
}
|
||||
editor.focus();
|
||||
editor.setSelection(edit.range);
|
||||
controller.insert(edit.snippet);
|
||||
editor.setSelections(selections ?? []);
|
||||
controller.insert(snippet);
|
||||
return controller.isInSnippet();
|
||||
}
|
||||
|
|
5
src/vs/monaco.d.ts
vendored
5
src/vs/monaco.d.ts
vendored
|
@ -6758,11 +6758,6 @@ declare namespace monaco.languages {
|
|||
eol?: editor.EndOfLineSequence;
|
||||
};
|
||||
|
||||
export interface SnippetTextEdit {
|
||||
range: IRange;
|
||||
snippet: string;
|
||||
}
|
||||
|
||||
/**
|
||||
* Interface used to format a model
|
||||
*/
|
||||
|
|
|
@ -9,7 +9,7 @@ import { RemoteAuthorities } from 'vs/base/common/network';
|
|||
import { URI } from 'vs/base/common/uri';
|
||||
import { IProductService } from 'vs/platform/product/common/productService';
|
||||
import { IRemoteAuthorityResolverService, IRemoteConnectionData, ResolvedAuthority, ResolverResult } from 'vs/platform/remote/common/remoteAuthorityResolver';
|
||||
import { getRemoteServerRootPath } from 'vs/platform/remote/common/remoteHosts';
|
||||
import { getRemoteServerRootPath, parseAuthorityWithOptionalPort } from 'vs/platform/remote/common/remoteHosts';
|
||||
|
||||
export class RemoteAuthorityResolverService extends Disposable implements IRemoteAuthorityResolverService {
|
||||
|
||||
|
@ -62,12 +62,9 @@ export class RemoteAuthorityResolverService extends Disposable implements IRemot
|
|||
|
||||
private _doResolveAuthority(authority: string): ResolverResult {
|
||||
const connectionToken = this._connectionTokens.get(authority) || this._connectionToken;
|
||||
if (authority.indexOf(':') >= 0) {
|
||||
const pieces = authority.split(':');
|
||||
return { authority: { authority, host: pieces[0], port: parseInt(pieces[1], 10), connectionToken } };
|
||||
}
|
||||
const port = (/^https:/.test(window.location.href) ? 443 : 80);
|
||||
return { authority: { authority, host: authority, port: port, connectionToken } };
|
||||
const defaultPort = (/^https:/.test(window.location.href) ? 443 : 80);
|
||||
const { host, port } = parseAuthorityWithOptionalPort(authority, defaultPort);
|
||||
return { authority: { authority, host: host, port: port, connectionToken } };
|
||||
}
|
||||
|
||||
_clearResolvedAuthority(authority: string): void {
|
||||
|
|
|
@ -33,3 +33,46 @@ export function getRemoteName(authority: string | undefined): string | undefined
|
|||
export function getRemoteServerRootPath(product: { quality?: string; commit?: string }): string {
|
||||
return `/${product.quality ?? 'oss'}-${product.commit ?? 'dev'}`;
|
||||
}
|
||||
|
||||
export function parseAuthorityWithPort(authority: string): { host: string; port: number } {
|
||||
const { host, port } = parseAuthority(authority);
|
||||
if (typeof port === 'undefined') {
|
||||
throw new Error(`Remote authority doesn't contain a port!`);
|
||||
}
|
||||
return { host, port };
|
||||
}
|
||||
|
||||
export function parseAuthorityWithOptionalPort(authority: string, defaultPort: number): { host: string; port: number } {
|
||||
let { host, port } = parseAuthority(authority);
|
||||
if (typeof port === 'undefined') {
|
||||
port = defaultPort;
|
||||
}
|
||||
return { host, port };
|
||||
}
|
||||
|
||||
function parseAuthority(authority: string): { host: string; port: number | undefined } {
|
||||
if (authority.indexOf('+') >= 0) {
|
||||
throw new Error(`Remote authorities containing '+' need to be resolved!`);
|
||||
}
|
||||
|
||||
// check for ipv6 with port
|
||||
const m1 = authority.match(/^(\[[0-9a-z:]+\]):(\d+)$/);
|
||||
if (m1) {
|
||||
return { host: m1[1], port: parseInt(m1[2], 10) };
|
||||
}
|
||||
|
||||
// check for ipv6 without port
|
||||
const m2 = authority.match(/^(\[[0-9a-z:]+\])$/);
|
||||
if (m2) {
|
||||
return { host: m2[1], port: undefined };
|
||||
}
|
||||
|
||||
// anything with a trailing port
|
||||
const m3 = authority.match(/(.*):(\d+)$/);
|
||||
if (m3) {
|
||||
return { host: m3[1], port: parseInt(m3[2], 10) };
|
||||
}
|
||||
|
||||
// doesn't contain a port
|
||||
return { host: authority, port: undefined };
|
||||
}
|
||||
|
|
38
src/vs/platform/remote/test/common/remoteHosts.test.ts
Normal file
38
src/vs/platform/remote/test/common/remoteHosts.test.ts
Normal file
|
@ -0,0 +1,38 @@
|
|||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import * as assert from 'assert';
|
||||
import { parseAuthorityWithOptionalPort, parseAuthorityWithPort } from 'vs/platform/remote/common/remoteHosts';
|
||||
|
||||
suite('remoteHosts', () => {
|
||||
|
||||
test('parseAuthority hostname', () => {
|
||||
assert.deepStrictEqual(parseAuthorityWithPort('localhost:8080'), { host: 'localhost', port: 8080 });
|
||||
});
|
||||
|
||||
test('parseAuthority ipv4', () => {
|
||||
assert.deepStrictEqual(parseAuthorityWithPort('127.0.0.1:8080'), { host: '127.0.0.1', port: 8080 });
|
||||
});
|
||||
|
||||
test('parseAuthority ipv6', () => {
|
||||
assert.deepStrictEqual(parseAuthorityWithPort('[2001:0db8:85a3:0000:0000:8a2e:0370:7334]:8080'), { host: '[2001:0db8:85a3:0000:0000:8a2e:0370:7334]', port: 8080 });
|
||||
});
|
||||
|
||||
test('parseAuthorityWithOptionalPort hostname', () => {
|
||||
assert.deepStrictEqual(parseAuthorityWithOptionalPort('localhost:8080', 123), { host: 'localhost', port: 8080 });
|
||||
assert.deepStrictEqual(parseAuthorityWithOptionalPort('localhost', 123), { host: 'localhost', port: 123 });
|
||||
});
|
||||
|
||||
test('parseAuthorityWithOptionalPort ipv4', () => {
|
||||
assert.deepStrictEqual(parseAuthorityWithOptionalPort('127.0.0.1:8080', 123), { host: '127.0.0.1', port: 8080 });
|
||||
assert.deepStrictEqual(parseAuthorityWithOptionalPort('127.0.0.1', 123), { host: '127.0.0.1', port: 123 });
|
||||
});
|
||||
|
||||
test('parseAuthorityWithOptionalPort ipv6', () => {
|
||||
assert.deepStrictEqual(parseAuthorityWithOptionalPort('[2001:0db8:85a3:0000:0000:8a2e:0370:7334]:8080', 123), { host: '[2001:0db8:85a3:0000:0000:8a2e:0370:7334]', port: 8080 });
|
||||
assert.deepStrictEqual(parseAuthorityWithOptionalPort('[2001:0db8:85a3:0000:0000:8a2e:0370:7334]', 123), { host: '[2001:0db8:85a3:0000:0000:8a2e:0370:7334]', port: 123 });
|
||||
});
|
||||
|
||||
});
|
|
@ -30,7 +30,7 @@ import * as callh from 'vs/workbench/contrib/callHierarchy/common/callHierarchy'
|
|||
import * as search from 'vs/workbench/contrib/search/common/search';
|
||||
import * as typeh from 'vs/workbench/contrib/typeHierarchy/common/typeHierarchy';
|
||||
import { extHostNamedCustomer, IExtHostContext } from 'vs/workbench/services/extensions/common/extHostCustomers';
|
||||
import { ExtHostContext, ExtHostLanguageFeaturesShape, ICallHierarchyItemDto, ICodeActionDto, ICodeActionProviderMetadataDto, IdentifiableInlineCompletion, IdentifiableInlineCompletions, IDocumentFilterDto, IIndentationRuleDto, IInlayHintDto, ILanguageConfigurationDto, ILanguageWordDefinitionDto, ILinkDto, ILocationDto, ILocationLinkDto, IOnEnterRuleDto, IRegExpDto, ISignatureHelpProviderMetadataDto, ISuggestDataDto, ISuggestDataDtoField, ISuggestResultDtoField, ITypeHierarchyItemDto, IWorkspaceEditDto, IWorkspaceSymbolDto, MainContext, MainThreadLanguageFeaturesShape, reviveWorkspaceEditDto } from '../common/extHost.protocol';
|
||||
import { ExtHostContext, ExtHostLanguageFeaturesShape, ICallHierarchyItemDto, ICodeActionDto, ICodeActionProviderMetadataDto, IdentifiableInlineCompletion, IdentifiableInlineCompletions, IDocumentFilterDto, IIndentationRuleDto, IInlayHintDto, ILanguageConfigurationDto, ILanguageWordDefinitionDto, ILinkDto, ILocationDto, ILocationLinkDto, IOnEnterRuleDto, IRegExpDto, ISignatureHelpProviderMetadataDto, ISuggestDataDto, ISuggestDataDtoField, ISuggestResultDtoField, ITypeHierarchyItemDto, IWorkspaceSymbolDto, MainContext, MainThreadLanguageFeaturesShape, reviveWorkspaceEditDto } from '../common/extHost.protocol';
|
||||
|
||||
@extHostNamedCustomer(MainContext.MainThreadLanguageFeatures)
|
||||
export class MainThreadLanguageFeatures extends Disposable implements MainThreadLanguageFeaturesShape {
|
||||
|
@ -368,21 +368,22 @@ export class MainThreadLanguageFeatures extends Disposable implements MainThread
|
|||
|
||||
// --- copy paste action provider
|
||||
|
||||
$registerPasteEditProvider(handle: number, selector: IDocumentFilterDto[], supportsCopy: boolean): void {
|
||||
$registerPasteEditProvider(handle: number, selector: IDocumentFilterDto[], supportsCopy: boolean, pasteMimeTypes: readonly string[]): void {
|
||||
const provider: languages.DocumentPasteEditProvider = {
|
||||
pasteMimeTypes: pasteMimeTypes,
|
||||
|
||||
prepareDocumentPaste: supportsCopy
|
||||
? async (model: ITextModel, selection: Selection, dataTransfer: VSDataTransfer, token: CancellationToken): Promise<VSDataTransfer | undefined> => {
|
||||
? async (model: ITextModel, selections: Selection[], dataTransfer: VSDataTransfer, token: CancellationToken): Promise<VSDataTransfer | undefined> => {
|
||||
const dataTransferDto = await typeConvert.DataTransfer.toDataTransferDTO(dataTransfer);
|
||||
if (token.isCancellationRequested) {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
const result = await this._proxy.$prepareDocumentPaste(handle, model.uri, selection, dataTransferDto, token);
|
||||
const result = await this._proxy.$prepareDocumentPaste(handle, model.uri, selections, dataTransferDto, token);
|
||||
if (!result) {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
|
||||
const dataTransferOut = new VSDataTransfer();
|
||||
result.items.forEach(([type, item]) => {
|
||||
dataTransferOut.replace(type, createStringDataTransferItem(item.asString));
|
||||
|
@ -391,16 +392,17 @@ export class MainThreadLanguageFeatures extends Disposable implements MainThread
|
|||
}
|
||||
: undefined,
|
||||
|
||||
provideDocumentPasteEdits: async (model: ITextModel, selection: Selection, dataTransfer: VSDataTransfer, token: CancellationToken) => {
|
||||
provideDocumentPasteEdits: async (model: ITextModel, selections: Selection[], dataTransfer: VSDataTransfer, token: CancellationToken) => {
|
||||
const d = await typeConvert.DataTransfer.toDataTransferDTO(dataTransfer);
|
||||
const result = await this._proxy.$providePasteEdits(handle, model.uri, selection, d, token);
|
||||
const result = await this._proxy.$providePasteEdits(handle, model.uri, selections, d, token);
|
||||
if (!result) {
|
||||
return;
|
||||
} else if ((result as IWorkspaceEditDto).edits) {
|
||||
return reviveWorkspaceEditDto(result as IWorkspaceEditDto);
|
||||
} else {
|
||||
return result as languages.SnippetTextEdit;
|
||||
return undefined;
|
||||
}
|
||||
|
||||
return {
|
||||
insertText: result.insertText,
|
||||
additionalEdit: result.additionalEdit ? reviveWorkspaceEditDto(result.additionalEdit) : undefined,
|
||||
};
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -933,11 +935,18 @@ class MainThreadDocumentOnDropEditProvider implements languages.DocumentOnDropEd
|
|||
private readonly _proxy: ExtHostLanguageFeaturesShape,
|
||||
) { }
|
||||
|
||||
async provideDocumentOnDropEdits(model: ITextModel, position: IPosition, dataTransfer: VSDataTransfer, token: CancellationToken): Promise<languages.SnippetTextEdit | null | undefined> {
|
||||
async provideDocumentOnDropEdits(model: ITextModel, position: IPosition, dataTransfer: VSDataTransfer, token: CancellationToken): Promise<languages.DocumentOnDropEdit | null | undefined> {
|
||||
const request = this.dataTransfers.add(dataTransfer);
|
||||
try {
|
||||
const dataTransferDto = await typeConvert.DataTransfer.toDataTransferDTO(dataTransfer);
|
||||
return await this._proxy.$provideDocumentOnDropEdits(this.handle, request.id, model.uri, position, dataTransferDto, token);
|
||||
const edit = await this._proxy.$provideDocumentOnDropEdits(this.handle, request.id, model.uri, position, dataTransferDto, token);
|
||||
if (!edit) {
|
||||
return undefined;
|
||||
}
|
||||
return {
|
||||
insertText: edit.insertText,
|
||||
additionalEdit: reviveWorkspaceEditDto(edit.additionalEdit),
|
||||
};
|
||||
} finally {
|
||||
request.dispose();
|
||||
}
|
||||
|
|
|
@ -457,9 +457,9 @@ export function createApiFactoryAndRegisterActors(accessor: ServicesAccessor): I
|
|||
registerCodeActionsProvider(selector: vscode.DocumentSelector, provider: vscode.CodeActionProvider, metadata?: vscode.CodeActionProviderMetadata): vscode.Disposable {
|
||||
return extHostLanguageFeatures.registerCodeActionProvider(extension, checkSelector(selector), provider, metadata);
|
||||
},
|
||||
registerDocumentPasteEditProvider(selector: vscode.DocumentSelector, provider: vscode.DocumentPasteEditProvider): vscode.Disposable {
|
||||
registerDocumentPasteEditProvider(selector: vscode.DocumentSelector, provider: vscode.DocumentPasteEditProvider, metadata: vscode.DocumentPasteProviderMetadata): vscode.Disposable {
|
||||
checkProposedApiEnabled(extension, 'documentPaste');
|
||||
return extHostLanguageFeatures.registerDocumentPasteEditProvider(extension, checkSelector(selector), provider);
|
||||
return extHostLanguageFeatures.registerDocumentPasteEditProvider(extension, checkSelector(selector), provider, metadata);
|
||||
},
|
||||
registerCodeLensProvider(selector: vscode.DocumentSelector, provider: vscode.CodeLensProvider): vscode.Disposable {
|
||||
return extHostLanguageFeatures.registerCodeLensProvider(extension, checkSelector(selector), provider);
|
||||
|
@ -1267,7 +1267,6 @@ export function createApiFactoryAndRegisterActors(accessor: ServicesAccessor): I
|
|||
SignatureHelpTriggerKind: extHostTypes.SignatureHelpTriggerKind,
|
||||
SignatureInformation: extHostTypes.SignatureInformation,
|
||||
SnippetString: extHostTypes.SnippetString,
|
||||
SnippetTextEdit: extHostTypes.SnippetTextEdit,
|
||||
SourceBreakpoint: extHostTypes.SourceBreakpoint,
|
||||
StandardTokenType: extHostTypes.StandardTokenType,
|
||||
StatusBarAlignment: extHostTypes.StatusBarAlignment,
|
||||
|
|
|
@ -372,7 +372,7 @@ export interface MainThreadLanguageFeaturesShape extends IDisposable {
|
|||
$registerLinkedEditingRangeProvider(handle: number, selector: IDocumentFilterDto[]): void;
|
||||
$registerReferenceSupport(handle: number, selector: IDocumentFilterDto[]): void;
|
||||
$registerQuickFixSupport(handle: number, selector: IDocumentFilterDto[], metadata: ICodeActionProviderMetadataDto, displayName: string, supportsResolve: boolean): void;
|
||||
$registerPasteEditProvider(handle: number, selector: IDocumentFilterDto[], supportsCopy: boolean): void;
|
||||
$registerPasteEditProvider(handle: number, selector: IDocumentFilterDto[], supportsCopy: boolean, pasteMimeTypes: readonly string[]): void;
|
||||
$registerDocumentFormattingSupport(handle: number, selector: IDocumentFilterDto[], extensionId: ExtensionIdentifier, displayName: string): void;
|
||||
$registerRangeFormattingSupport(handle: number, selector: IDocumentFilterDto[], extensionId: ExtensionIdentifier, displayName: string): void;
|
||||
$registerOnTypeFormattingSupport(handle: number, selector: IDocumentFilterDto[], autoFormatTriggerCharacters: string[], extensionId: ExtensionIdentifier): void;
|
||||
|
@ -1713,6 +1713,16 @@ export interface IInlineValueContextDto {
|
|||
|
||||
export type ITypeHierarchyItemDto = Dto<TypeHierarchyItem>;
|
||||
|
||||
export interface IPasteEditDto {
|
||||
insertText: string | { snippet: string };
|
||||
additionalEdit?: IWorkspaceEditDto;
|
||||
}
|
||||
|
||||
export interface IDocumentOnDropEditDto {
|
||||
insertText: string | { snippet: string };
|
||||
additionalEdit?: IWorkspaceEditDto;
|
||||
}
|
||||
|
||||
export interface ExtHostLanguageFeaturesShape {
|
||||
$provideDocumentSymbols(handle: number, resource: UriComponents, token: CancellationToken): Promise<languages.DocumentSymbol[] | undefined>;
|
||||
$provideCodeLenses(handle: number, resource: UriComponents, token: CancellationToken): Promise<ICodeLensListDto | undefined>;
|
||||
|
@ -1731,8 +1741,8 @@ export interface ExtHostLanguageFeaturesShape {
|
|||
$provideCodeActions(handle: number, resource: UriComponents, rangeOrSelection: IRange | ISelection, context: languages.CodeActionContext, token: CancellationToken): Promise<ICodeActionListDto | undefined>;
|
||||
$resolveCodeAction(handle: number, id: ChainedCacheId, token: CancellationToken): Promise<IWorkspaceEditDto | undefined>;
|
||||
$releaseCodeActions(handle: number, cacheId: number): void;
|
||||
$prepareDocumentPaste(handle: number, uri: UriComponents, range: IRange, dataTransfer: DataTransferDTO, token: CancellationToken): Promise<DataTransferDTO | undefined>;
|
||||
$providePasteEdits(handle: number, uri: UriComponents, range: IRange, dataTransfer: DataTransferDTO, token: CancellationToken): Promise<IWorkspaceEditDto | Dto<languages.SnippetTextEdit> | undefined>;
|
||||
$prepareDocumentPaste(handle: number, uri: UriComponents, ranges: IRange[], dataTransfer: DataTransferDTO, token: CancellationToken): Promise<DataTransferDTO | undefined>;
|
||||
$providePasteEdits(handle: number, uri: UriComponents, ranges: IRange[], dataTransfer: DataTransferDTO, token: CancellationToken): Promise<IPasteEditDto | undefined>;
|
||||
$provideDocumentFormattingEdits(handle: number, resource: UriComponents, options: languages.FormattingOptions, token: CancellationToken): Promise<ISingleEditOperation[] | undefined>;
|
||||
$provideDocumentRangeFormattingEdits(handle: number, resource: UriComponents, range: IRange, options: languages.FormattingOptions, token: CancellationToken): Promise<ISingleEditOperation[] | undefined>;
|
||||
$provideOnTypeFormattingEdits(handle: number, resource: UriComponents, position: IPosition, ch: string, options: languages.FormattingOptions, token: CancellationToken): Promise<ISingleEditOperation[] | undefined>;
|
||||
|
@ -1771,7 +1781,7 @@ export interface ExtHostLanguageFeaturesShape {
|
|||
$provideTypeHierarchySupertypes(handle: number, sessionId: string, itemId: string, token: CancellationToken): Promise<ITypeHierarchyItemDto[] | undefined>;
|
||||
$provideTypeHierarchySubtypes(handle: number, sessionId: string, itemId: string, token: CancellationToken): Promise<ITypeHierarchyItemDto[] | undefined>;
|
||||
$releaseTypeHierarchy(handle: number, sessionId: string): void;
|
||||
$provideDocumentOnDropEdits(handle: number, requestId: number, resource: UriComponents, position: IPosition, dataTransferDto: DataTransferDTO, token: CancellationToken): Promise<Dto<languages.SnippetTextEdit> | undefined>;
|
||||
$provideDocumentOnDropEdits(handle: number, requestId: number, resource: UriComponents, position: IPosition, dataTransferDto: DataTransferDTO, token: CancellationToken): Promise<IDocumentOnDropEditDto | undefined>;
|
||||
}
|
||||
|
||||
export interface ExtHostQuickOpenShape {
|
||||
|
|
|
@ -7,7 +7,7 @@ import { URI, UriComponents } from 'vs/base/common/uri';
|
|||
import { mixin } from 'vs/base/common/objects';
|
||||
import type * as vscode from 'vscode';
|
||||
import * as typeConvert from 'vs/workbench/api/common/extHostTypeConverters';
|
||||
import { Range, Disposable, CompletionList, SnippetString, CodeActionKind, SymbolInformation, DocumentSymbol, SemanticTokensEdits, SemanticTokens, SemanticTokensEdit, Location, InlineCompletionTriggerKindNew, InlineCompletionTriggerKind, WorkspaceEdit } from 'vs/workbench/api/common/extHostTypes';
|
||||
import { Range, Disposable, CompletionList, SnippetString, CodeActionKind, SymbolInformation, DocumentSymbol, SemanticTokensEdits, SemanticTokens, SemanticTokensEdit, Location, InlineCompletionTriggerKindNew, InlineCompletionTriggerKind } from 'vs/workbench/api/common/extHostTypes';
|
||||
import { ISingleEditOperation } from 'vs/editor/common/core/editOperation';
|
||||
import * as languages from 'vs/editor/common/languages';
|
||||
import { ExtHostDocuments } from 'vs/workbench/api/common/extHostDocuments';
|
||||
|
@ -34,7 +34,6 @@ import { StopWatch } from 'vs/base/common/stopwatch';
|
|||
import { isCancellationError, NotImplementedError } from 'vs/base/common/errors';
|
||||
import { raceCancellationError } from 'vs/base/common/async';
|
||||
import { isProposedApiEnabled } from 'vs/workbench/services/extensions/common/extensions';
|
||||
import { Dto } from 'vs/workbench/services/extensions/common/proxyIdentifier';
|
||||
|
||||
// --- adapter
|
||||
|
||||
|
@ -494,40 +493,39 @@ class DocumentPasteEditProvider {
|
|||
private readonly _handle: number,
|
||||
) { }
|
||||
|
||||
async prepareDocumentPaste(resource: URI, range: IRange, dataTransferDto: extHostProtocol.DataTransferDTO, token: CancellationToken): Promise<extHostProtocol.DataTransferDTO | undefined> {
|
||||
async prepareDocumentPaste(resource: URI, ranges: IRange[], dataTransferDto: extHostProtocol.DataTransferDTO, token: CancellationToken): Promise<extHostProtocol.DataTransferDTO | undefined> {
|
||||
if (!this._provider.prepareDocumentPaste) {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
const doc = this._documents.getDocument(resource);
|
||||
const vscodeRange = typeConvert.Range.to(range);
|
||||
const vscodeRanges = ranges.map(range => typeConvert.Range.to(range));
|
||||
|
||||
const dataTransfer = typeConvert.DataTransfer.toDataTransfer(dataTransferDto, () => {
|
||||
throw new NotImplementedError();
|
||||
});
|
||||
await this._provider.prepareDocumentPaste(doc, vscodeRange, dataTransfer, token);
|
||||
await this._provider.prepareDocumentPaste(doc, vscodeRanges, dataTransfer, token);
|
||||
|
||||
return typeConvert.DataTransfer.toDataTransferDTO(dataTransfer);
|
||||
}
|
||||
|
||||
async providePasteEdits(requestId: number, resource: URI, range: IRange, dataTransferDto: extHostProtocol.DataTransferDTO, token: CancellationToken): Promise<undefined | extHostProtocol.IWorkspaceEditDto | Dto<languages.SnippetTextEdit>> {
|
||||
async providePasteEdits(requestId: number, resource: URI, ranges: IRange[], dataTransferDto: extHostProtocol.DataTransferDTO, token: CancellationToken): Promise<undefined | extHostProtocol.IPasteEditDto> {
|
||||
const doc = this._documents.getDocument(resource);
|
||||
const vscodeRange = typeConvert.Range.to(range);
|
||||
const vscodeRanges = ranges.map(range => typeConvert.Range.to(range));
|
||||
|
||||
const dataTransfer = typeConvert.DataTransfer.toDataTransfer(dataTransferDto, async (index) => {
|
||||
return (await this._proxy.$resolveDocumentOnDropFileData(this._handle, requestId, index)).buffer;
|
||||
});
|
||||
|
||||
const edit = await this._provider.provideDocumentPasteEdits(doc, vscodeRange, dataTransfer, token);
|
||||
const edit = await this._provider.provideDocumentPasteEdits(doc, vscodeRanges, dataTransfer, token);
|
||||
if (!edit) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (edit instanceof WorkspaceEdit) {
|
||||
return typeConvert.WorkspaceEdit.from(edit);
|
||||
} else {
|
||||
return typeConvert.SnippetTextEdit.from(edit as vscode.SnippetTextEdit);
|
||||
}
|
||||
return {
|
||||
insertText: typeof edit.insertText === 'string' ? edit.insertText : { snippet: edit.insertText.value },
|
||||
additionalEdit: edit.additionalEdit ? typeConvert.WorkspaceEdit.from(edit.additionalEdit) : undefined,
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1799,7 +1797,7 @@ class DocumentOnDropEditAdapter {
|
|||
private readonly _handle: number,
|
||||
) { }
|
||||
|
||||
async provideDocumentOnDropEdits(requestId: number, uri: URI, position: IPosition, dataTransferDto: extHostProtocol.DataTransferDTO, token: CancellationToken): Promise<Dto<languages.SnippetTextEdit> | undefined> {
|
||||
async provideDocumentOnDropEdits(requestId: number, uri: URI, position: IPosition, dataTransferDto: extHostProtocol.DataTransferDTO, token: CancellationToken): Promise<extHostProtocol.IDocumentOnDropEditDto | undefined> {
|
||||
const doc = this._documents.getDocument(uri);
|
||||
const pos = typeConvert.Position.to(position);
|
||||
const dataTransfer = typeConvert.DataTransfer.toDataTransfer(dataTransferDto, async (index) => {
|
||||
|
@ -1810,7 +1808,10 @@ class DocumentOnDropEditAdapter {
|
|||
if (!edit) {
|
||||
return undefined;
|
||||
}
|
||||
return typeConvert.SnippetTextEdit.from(edit);
|
||||
return {
|
||||
insertText: typeof edit.insertText === 'string' ? edit.insertText : { snippet: edit.insertText.value },
|
||||
additionalEdit: edit.additionalEdit ? typeConvert.WorkspaceEdit.from(edit.additionalEdit) : undefined,
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -2454,26 +2455,26 @@ export class ExtHostLanguageFeatures implements extHostProtocol.ExtHostLanguageF
|
|||
return this._createDisposable(handle);
|
||||
}
|
||||
|
||||
$provideDocumentOnDropEdits(handle: number, requestId: number, resource: UriComponents, position: IPosition, dataTransferDto: extHostProtocol.DataTransferDTO, token: CancellationToken): Promise<Dto<languages.SnippetTextEdit> | undefined> {
|
||||
$provideDocumentOnDropEdits(handle: number, requestId: number, resource: UriComponents, position: IPosition, dataTransferDto: extHostProtocol.DataTransferDTO, token: CancellationToken): Promise<extHostProtocol.IDocumentOnDropEditDto | undefined> {
|
||||
return this._withAdapter(handle, DocumentOnDropEditAdapter, adapter =>
|
||||
Promise.resolve(adapter.provideDocumentOnDropEdits(requestId, URI.revive(resource), position, dataTransferDto, token)), undefined, undefined);
|
||||
}
|
||||
|
||||
// --- copy/paste actions
|
||||
|
||||
registerDocumentPasteEditProvider(extension: IExtensionDescription, selector: vscode.DocumentSelector, provider: vscode.DocumentPasteEditProvider): vscode.Disposable {
|
||||
registerDocumentPasteEditProvider(extension: IExtensionDescription, selector: vscode.DocumentSelector, provider: vscode.DocumentPasteEditProvider, metadata: vscode.DocumentPasteProviderMetadata): vscode.Disposable {
|
||||
const handle = this._nextHandle();
|
||||
this._adapter.set(handle, new AdapterData(new DocumentPasteEditProvider(this._proxy, this._documents, provider, handle), extension));
|
||||
this._proxy.$registerPasteEditProvider(handle, this._transformDocumentSelector(selector), !!provider.prepareDocumentPaste);
|
||||
this._proxy.$registerPasteEditProvider(handle, this._transformDocumentSelector(selector), !!provider.prepareDocumentPaste, metadata.pasteMimeTypes);
|
||||
return this._createDisposable(handle);
|
||||
}
|
||||
|
||||
$prepareDocumentPaste(handle: number, resource: UriComponents, range: IRange, dataTransfer: extHostProtocol.DataTransferDTO, token: CancellationToken): Promise<extHostProtocol.DataTransferDTO | undefined> {
|
||||
return this._withAdapter(handle, DocumentPasteEditProvider, adapter => adapter.prepareDocumentPaste(URI.revive(resource), range, dataTransfer, token), undefined, token);
|
||||
$prepareDocumentPaste(handle: number, resource: UriComponents, ranges: IRange[], dataTransfer: extHostProtocol.DataTransferDTO, token: CancellationToken): Promise<extHostProtocol.DataTransferDTO | undefined> {
|
||||
return this._withAdapter(handle, DocumentPasteEditProvider, adapter => adapter.prepareDocumentPaste(URI.revive(resource), ranges, dataTransfer, token), undefined, token);
|
||||
}
|
||||
|
||||
$providePasteEdits(handle: number, resource: UriComponents, range: IRange, dataTransferDto: extHostProtocol.DataTransferDTO, token: CancellationToken): Promise<extHostProtocol.IWorkspaceEditDto | Dto<languages.SnippetTextEdit> | undefined> {
|
||||
return this._withAdapter(handle, DocumentPasteEditProvider, adapter => adapter.providePasteEdits(0, URI.revive(resource), range, dataTransferDto, token), undefined, token);
|
||||
$providePasteEdits(handle: number, resource: UriComponents, ranges: IRange[], dataTransferDto: extHostProtocol.DataTransferDTO, token: CancellationToken): Promise<extHostProtocol.IPasteEditDto | undefined> {
|
||||
return this._withAdapter(handle, DocumentPasteEditProvider, adapter => adapter.providePasteEdits(0, URI.revive(resource), ranges, dataTransferDto, token), undefined, token);
|
||||
}
|
||||
|
||||
// --- configuration
|
||||
|
|
|
@ -562,15 +562,6 @@ export namespace TextEdit {
|
|||
}
|
||||
}
|
||||
|
||||
export namespace SnippetTextEdit {
|
||||
export function from(edit: vscode.SnippetTextEdit): languages.SnippetTextEdit {
|
||||
return {
|
||||
range: Range.from(edit.range),
|
||||
snippet: edit.snippet.value
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
export namespace WorkspaceEdit {
|
||||
|
||||
export interface IVersionInformationProvider {
|
||||
|
|
|
@ -647,17 +647,6 @@ export class NotebookEdit implements vscode.NotebookEdit {
|
|||
}
|
||||
}
|
||||
|
||||
export class SnippetTextEdit implements vscode.SnippetTextEdit {
|
||||
|
||||
range: vscode.Range;
|
||||
snippet: vscode.SnippetString;
|
||||
|
||||
constructor(range: Range, snippet: SnippetString) {
|
||||
this.range = range;
|
||||
this.snippet = snippet;
|
||||
}
|
||||
}
|
||||
|
||||
export interface IFileOperationOptions {
|
||||
overwrite?: boolean;
|
||||
ignoreIfExists?: boolean;
|
||||
|
|
|
@ -23,7 +23,7 @@ import { TextDiffEditor } from 'vs/workbench/browser/parts/editor/textDiffEditor
|
|||
import { BinaryResourceDiffEditor } from 'vs/workbench/browser/parts/editor/binaryDiffEditor';
|
||||
import { ChangeEncodingAction, ChangeEOLAction, ChangeLanguageAction, EditorStatus } from 'vs/workbench/browser/parts/editor/editorStatus';
|
||||
import { IWorkbenchActionRegistry, Extensions as ActionExtensions, CATEGORIES } from 'vs/workbench/common/actions';
|
||||
import { SyncActionDescriptor, MenuRegistry, MenuId, IMenuItem } from 'vs/platform/actions/common/actions';
|
||||
import { SyncActionDescriptor, MenuRegistry, MenuId, IMenuItem, registerAction2 } from 'vs/platform/actions/common/actions';
|
||||
import { SyncDescriptor } from 'vs/platform/instantiation/common/descriptors';
|
||||
import { KeyMod, KeyChord, KeyCode } from 'vs/base/common/keyCodes';
|
||||
import {
|
||||
|
@ -244,8 +244,6 @@ registry.registerWorkbenchAction(SyncActionDescriptor.from(NewEditorGroupLeftAct
|
|||
registry.registerWorkbenchAction(SyncActionDescriptor.from(NewEditorGroupRightAction), 'View: New Editor Group to the Right', CATEGORIES.View.value);
|
||||
registry.registerWorkbenchAction(SyncActionDescriptor.from(NewEditorGroupAboveAction), 'View: New Editor Group Above', CATEGORIES.View.value);
|
||||
registry.registerWorkbenchAction(SyncActionDescriptor.from(NewEditorGroupBelowAction), 'View: New Editor Group Below', CATEGORIES.View.value);
|
||||
registry.registerWorkbenchAction(SyncActionDescriptor.from(NavigateForwardAction, { primary: 0, win: { primary: KeyMod.Alt | KeyCode.RightArrow }, mac: { primary: KeyMod.WinCtrl | KeyMod.Shift | KeyCode.Minus }, linux: { primary: KeyMod.CtrlCmd | KeyMod.Shift | KeyCode.Minus } }), 'Go Forward');
|
||||
registry.registerWorkbenchAction(SyncActionDescriptor.from(NavigateBackwardsAction, { primary: 0, win: { primary: KeyMod.Alt | KeyCode.LeftArrow }, mac: { primary: KeyMod.WinCtrl | KeyCode.Minus }, linux: { primary: KeyMod.CtrlCmd | KeyMod.Alt | KeyCode.Minus } }), 'Go Back');
|
||||
registry.registerWorkbenchAction(SyncActionDescriptor.from(NavigatePreviousAction), 'Go Previous');
|
||||
registry.registerWorkbenchAction(SyncActionDescriptor.from(NavigateForwardInEditsAction), 'Go Forward in Edit Locations');
|
||||
registry.registerWorkbenchAction(SyncActionDescriptor.from(NavigateBackwardsInEditsAction), 'Go Back in Edit Locations');
|
||||
|
@ -273,6 +271,9 @@ registry.registerWorkbenchAction(SyncActionDescriptor.from(QuickAccessPreviousRe
|
|||
registry.registerWorkbenchAction(SyncActionDescriptor.from(QuickAccessLeastRecentlyUsedEditorInGroupAction, { primary: KeyMod.CtrlCmd | KeyMod.Shift | KeyCode.Tab, mac: { primary: KeyMod.WinCtrl | KeyMod.Shift | KeyCode.Tab } }, ActiveEditorGroupEmptyContext.toNegated()), 'View: Quick Open Least Recently Used Editor in Group', CATEGORIES.View.value);
|
||||
registry.registerWorkbenchAction(SyncActionDescriptor.from(QuickAccessPreviousEditorFromHistoryAction), 'Quick Open Previous Editor from History');
|
||||
|
||||
registerAction2(NavigateForwardAction);
|
||||
registerAction2(NavigateBackwardsAction);
|
||||
|
||||
const quickAccessNavigateNextInEditorPickerId = 'workbench.action.quickOpenNavigateNextInEditorPicker';
|
||||
KeybindingsRegistry.registerCommandAndKeybindingRule({
|
||||
id: quickAccessNavigateNextInEditorPickerId,
|
||||
|
@ -314,9 +315,6 @@ if (isMacintosh) {
|
|||
});
|
||||
}
|
||||
|
||||
MenuRegistry.appendMenuItem(MenuId.CommandCenter, { order: 1, command: { id: NavigateBackwardsAction.ID, title: NavigateBackwardsAction.LABEL, icon: Codicon.arrowLeft } });
|
||||
MenuRegistry.appendMenuItem(MenuId.CommandCenter, { order: 2, command: { id: NavigateForwardAction.ID, title: NavigateForwardAction.LABEL, icon: Codicon.arrowRight } });
|
||||
|
||||
// Empty Editor Group Toolbar
|
||||
MenuRegistry.appendMenuItem(MenuId.EmptyEditorGroup, { command: { id: UNLOCK_GROUP_COMMAND_ID, title: localize('unlockGroupAction', "Unlock Group"), icon: Codicon.lock }, group: 'navigation', order: 10, when: ActiveEditorGroupLockedContext });
|
||||
MenuRegistry.appendMenuItem(MenuId.EmptyEditorGroup, { command: { id: CLOSE_EDITOR_GROUP_COMMAND_ID, title: localize('closeGroupAction', "Close Group"), icon: Codicon.close }, group: 'navigation', order: 20 });
|
||||
|
@ -775,27 +773,6 @@ MenuRegistry.appendMenuItem(MenuId.MenubarLayoutMenu, {
|
|||
|
||||
// Main Menu Bar Contributions:
|
||||
|
||||
// Forward/Back
|
||||
MenuRegistry.appendMenuItem(MenuId.MenubarGoMenu, {
|
||||
group: '1_history_nav',
|
||||
command: {
|
||||
id: 'workbench.action.navigateBack',
|
||||
title: localize({ key: 'miBack', comment: ['&& denotes a mnemonic'] }, "&&Back"),
|
||||
precondition: ContextKeyExpr.has('canNavigateBack')
|
||||
},
|
||||
order: 1
|
||||
});
|
||||
|
||||
MenuRegistry.appendMenuItem(MenuId.MenubarGoMenu, {
|
||||
group: '1_history_nav',
|
||||
command: {
|
||||
id: 'workbench.action.navigateForward',
|
||||
title: localize({ key: 'miForward', comment: ['&& denotes a mnemonic'] }, "&&Forward"),
|
||||
precondition: ContextKeyExpr.has('canNavigateForward')
|
||||
},
|
||||
order: 2
|
||||
});
|
||||
|
||||
MenuRegistry.appendMenuItem(MenuId.MenubarGoMenu, {
|
||||
group: '1_history_nav',
|
||||
command: {
|
||||
|
|
|
@ -26,6 +26,11 @@ import { Codicon } from 'vs/base/common/codicons';
|
|||
import { IFilesConfigurationService, AutoSaveMode } from 'vs/workbench/services/filesConfiguration/common/filesConfigurationService';
|
||||
import { IEditorResolverService } from 'vs/workbench/services/editor/common/editorResolverService';
|
||||
import { isLinux, isNative, isWindows } from 'vs/base/common/platform';
|
||||
import { Action2, MenuId } from 'vs/platform/actions/common/actions';
|
||||
import { ServicesAccessor } from 'vs/platform/instantiation/common/instantiation';
|
||||
import { ContextKeyExpr } from 'vs/platform/contextkey/common/contextkey';
|
||||
import { KeyCode, KeyMod } from 'vs/base/common/keyCodes';
|
||||
import { KeybindingWeight } from 'vs/platform/keybinding/common/keybindingsRegistry';
|
||||
|
||||
export class ExecuteCommandAction extends Action {
|
||||
|
||||
|
@ -1258,39 +1263,67 @@ export class OpenLastEditorInGroup extends AbstractNavigateEditorAction {
|
|||
}
|
||||
}
|
||||
|
||||
export class NavigateForwardAction extends Action {
|
||||
export class NavigateForwardAction extends Action2 {
|
||||
|
||||
static readonly ID = 'workbench.action.navigateForward';
|
||||
static readonly LABEL = localize('navigateForward', "Go Forward");
|
||||
|
||||
constructor(
|
||||
id: string,
|
||||
label: string,
|
||||
@IHistoryService private readonly historyService: IHistoryService
|
||||
) {
|
||||
super(id, label);
|
||||
constructor() {
|
||||
super({
|
||||
id: NavigateForwardAction.ID,
|
||||
title: { value: localize('navigateForward', "Go Forward"), original: 'Go Forward', mnemonicTitle: localize({ key: 'miForward', comment: ['&& denotes a mnemonic'] }, "&&Forward") },
|
||||
f1: true,
|
||||
icon: Codicon.arrowRight,
|
||||
precondition: ContextKeyExpr.has('canNavigateForward'),
|
||||
keybinding: {
|
||||
weight: KeybindingWeight.WorkbenchContrib,
|
||||
win: { primary: KeyMod.Alt | KeyCode.RightArrow },
|
||||
mac: { primary: KeyMod.WinCtrl | KeyMod.Shift | KeyCode.Minus },
|
||||
linux: { primary: KeyMod.CtrlCmd | KeyMod.Shift | KeyCode.Minus }
|
||||
},
|
||||
menu: [
|
||||
{ id: MenuId.MenubarGoMenu, group: '1_history_nav', order: 2 },
|
||||
{ id: MenuId.CommandCenter, order: 2 }
|
||||
]
|
||||
});
|
||||
}
|
||||
|
||||
override async run(): Promise<void> {
|
||||
await this.historyService.goForward(GoFilter.NONE);
|
||||
async run(accessor: ServicesAccessor): Promise<void> {
|
||||
const historyService = accessor.get(IHistoryService);
|
||||
|
||||
await historyService.goForward(GoFilter.NONE);
|
||||
}
|
||||
}
|
||||
|
||||
export class NavigateBackwardsAction extends Action {
|
||||
export class NavigateBackwardsAction extends Action2 {
|
||||
|
||||
static readonly ID = 'workbench.action.navigateBack';
|
||||
static readonly LABEL = localize('navigateBack', "Go Back");
|
||||
|
||||
constructor(
|
||||
id: string,
|
||||
label: string,
|
||||
@IHistoryService private readonly historyService: IHistoryService
|
||||
) {
|
||||
super(id, label);
|
||||
constructor() {
|
||||
super({
|
||||
id: NavigateBackwardsAction.ID,
|
||||
title: { value: localize('navigateBack', "Go Back"), original: 'Go Back', mnemonicTitle: localize({ key: 'miBack', comment: ['&& denotes a mnemonic'] }, "&&Back") },
|
||||
f1: true,
|
||||
precondition: ContextKeyExpr.has('canNavigateBack'),
|
||||
icon: Codicon.arrowLeft,
|
||||
keybinding: {
|
||||
weight: KeybindingWeight.WorkbenchContrib,
|
||||
win: { primary: KeyMod.Alt | KeyCode.LeftArrow },
|
||||
mac: { primary: KeyMod.WinCtrl | KeyCode.Minus },
|
||||
linux: { primary: KeyMod.CtrlCmd | KeyMod.Alt | KeyCode.Minus }
|
||||
},
|
||||
menu: [
|
||||
{ id: MenuId.MenubarGoMenu, group: '1_history_nav', order: 1 },
|
||||
{ id: MenuId.CommandCenter, order: 1 }
|
||||
]
|
||||
});
|
||||
}
|
||||
|
||||
override async run(): Promise<void> {
|
||||
await this.historyService.goBack(GoFilter.NONE);
|
||||
async run(accessor: ServicesAccessor): Promise<void> {
|
||||
const historyService = accessor.get(IHistoryService);
|
||||
|
||||
await historyService.goBack(GoFilter.NONE);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -597,6 +597,7 @@ export class EditorDropTarget extends Themable {
|
|||
private registerListeners(): void {
|
||||
this._register(addDisposableListener(this.container, EventType.DRAG_ENTER, e => this.onDragEnter(e)));
|
||||
this._register(addDisposableListener(this.container, EventType.DRAG_LEAVE, () => this.onDragLeave()));
|
||||
this._register(addDisposableListener(this.container, EventType.DRAG_OVER, e => this.onDragEnter(e)));
|
||||
[this.container, window].forEach(node => this._register(addDisposableListener(node as HTMLElement, EventType.DRAG_END, () => this.onDragEnd())));
|
||||
}
|
||||
|
||||
|
|
|
@ -690,8 +690,11 @@ export class DebugService implements IDebugService {
|
|||
const dataBreakpoints = this.model.getDataBreakpoints().filter(dbp => !dbp.canPersist);
|
||||
dataBreakpoints.forEach(dbp => this.model.removeDataBreakpoints(dbp.getId()));
|
||||
|
||||
if (this.viewsService.isViewVisible(REPL_VIEW_ID) && this.configurationService.getValue<IDebugConfiguration>('debug').console.closeOnEnd) {
|
||||
this.viewsService.closeView(REPL_VIEW_ID);
|
||||
if (this.configurationService.getValue<IDebugConfiguration>('debug').console.closeOnEnd) {
|
||||
const debugConsoleContainer = this.viewDescriptorService.getViewContainerByViewId(REPL_VIEW_ID);
|
||||
if (debugConsoleContainer && this.viewsService.isViewContainerVisible(debugConsoleContainer.id)) {
|
||||
this.viewsService.closeViewContainer(debugConsoleContainer.id);
|
||||
}
|
||||
}
|
||||
}
|
||||
}));
|
||||
|
|
|
@ -96,10 +96,10 @@ export class VariablesView extends ViewPane {
|
|||
const viewState = this.savedViewState.get(stackFrame.getId());
|
||||
await this.tree.setInput(stackFrame, viewState);
|
||||
|
||||
// Automatically expand the first scope if it is not expensive and if all scopes are collapsed
|
||||
// Automatically expand the first non-expensive scope
|
||||
const scopes = await stackFrame.getScopes();
|
||||
const toExpand = scopes.find(s => !s.expensive);
|
||||
if (toExpand && (scopes.every(s => this.tree.isCollapsed(s)) || !this.autoExpandedScopes.has(toExpand.getId()))) {
|
||||
if (toExpand) {
|
||||
this.autoExpandedScopes.add(toExpand.getId());
|
||||
await this.tree.expand(toExpand);
|
||||
}
|
||||
|
|
|
@ -7,6 +7,7 @@ import { distinct, lastIndex } from 'vs/base/common/arrays';
|
|||
import { RunOnceScheduler } from 'vs/base/common/async';
|
||||
import { decodeBase64, encodeBase64, VSBuffer } from 'vs/base/common/buffer';
|
||||
import { CancellationTokenSource } from 'vs/base/common/cancellation';
|
||||
import { stringHash } from 'vs/base/common/hash';
|
||||
import { Emitter, Event } from 'vs/base/common/event';
|
||||
import { Disposable } from 'vs/base/common/lifecycle';
|
||||
import { mixin } from 'vs/base/common/objects';
|
||||
|
@ -351,7 +352,7 @@ export class Scope extends ExpressionContainer implements IScope {
|
|||
|
||||
constructor(
|
||||
stackFrame: IStackFrame,
|
||||
index: number,
|
||||
id: number,
|
||||
public readonly name: string,
|
||||
reference: number,
|
||||
public expensive: boolean,
|
||||
|
@ -359,7 +360,7 @@ export class Scope extends ExpressionContainer implements IScope {
|
|||
indexedVariables?: number,
|
||||
public readonly range?: IRange
|
||||
) {
|
||||
super(stackFrame.thread.session, stackFrame.thread.threadId, reference, `scope:${name}:${index}`, namedVariables, indexedVariables);
|
||||
super(stackFrame.thread.session, stackFrame.thread.threadId, reference, `scope:${name}:${id}`, namedVariables, indexedVariables);
|
||||
}
|
||||
|
||||
override toString(): string {
|
||||
|
@ -417,12 +418,17 @@ export class StackFrame implements IStackFrame {
|
|||
return [];
|
||||
}
|
||||
|
||||
const scopeNameIndexes = new Map<string, number>();
|
||||
const usedIds = new Set<number>();
|
||||
return response.body.scopes.map(rs => {
|
||||
const previousIndex = scopeNameIndexes.get(rs.name);
|
||||
const index = typeof previousIndex === 'number' ? previousIndex + 1 : 0;
|
||||
scopeNameIndexes.set(rs.name, index);
|
||||
return new Scope(this, index, rs.name, rs.variablesReference, rs.expensive, rs.namedVariables, rs.indexedVariables,
|
||||
// form the id based on the name and location so that it's the
|
||||
// same across multiple pauses to retain expansion state
|
||||
let id = 0;
|
||||
do {
|
||||
id = stringHash(`${rs.name}:${rs.line}:${rs.column}`, id);
|
||||
} while (usedIds.has(id));
|
||||
|
||||
usedIds.add(id);
|
||||
return new Scope(this, id, rs.name, rs.variablesReference, rs.expensive, rs.namedVariables, rs.indexedVariables,
|
||||
rs.line && rs.column && rs.endLine && rs.endColumn ? new Range(rs.line, rs.column, rs.endLine, rs.endColumn) : undefined);
|
||||
|
||||
});
|
||||
|
|
|
@ -16,13 +16,13 @@ import { append, $, finalHandler, join, addDisposableListener, EventType, setPar
|
|||
import { EditorPane } from 'vs/workbench/browser/parts/editor/editorPane';
|
||||
import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry';
|
||||
import { IInstantiationService, ServicesAccessor } from 'vs/platform/instantiation/common/instantiation';
|
||||
import { IExtensionIgnoredRecommendationsService, IExtensionRecommendationsService } from 'vs/workbench/services/extensionRecommendations/common/extensionRecommendations';
|
||||
import { IExtensionRecommendationsService } from 'vs/workbench/services/extensionRecommendations/common/extensionRecommendations';
|
||||
import { IExtensionManifest, IKeyBinding, IView, IViewContainer } from 'vs/platform/extensions/common/extensions';
|
||||
import { KeyMod, KeyCode } from 'vs/base/common/keyCodes';
|
||||
import { ResolvedKeybinding } from 'vs/base/common/keybindings';
|
||||
import { ExtensionsInput, IExtensionEditorOptions } from 'vs/workbench/contrib/extensions/common/extensionsInput';
|
||||
import { IExtensionsWorkbenchService, IExtensionsViewPaneContainer, VIEWLET_ID, IExtension, ExtensionContainers, ExtensionEditorTab, ExtensionState } from 'vs/workbench/contrib/extensions/common/extensions';
|
||||
import { RatingsWidget, InstallCountWidget, RemoteBadgeWidget, ExtensionWidget } from 'vs/workbench/contrib/extensions/browser/extensionsWidgets';
|
||||
import { IExtensionsWorkbenchService, IExtensionsViewPaneContainer, VIEWLET_ID, IExtension, ExtensionContainers, ExtensionEditorTab, ExtensionState, IExtensionContainer } from 'vs/workbench/contrib/extensions/common/extensions';
|
||||
import { RatingsWidget, InstallCountWidget, RemoteBadgeWidget, ExtensionWidget, ExtensionStatusWidget, ExtensionRecommendationWidget } from 'vs/workbench/contrib/extensions/browser/extensionsWidgets';
|
||||
import { IEditorOpenContext } from 'vs/workbench/common/editor';
|
||||
import { ActionBar } from 'vs/base/browser/ui/actionbar/actionbar';
|
||||
import {
|
||||
|
@ -66,8 +66,7 @@ import { Delegate } from 'vs/workbench/contrib/extensions/browser/extensionsList
|
|||
import { renderMarkdown } from 'vs/base/browser/markdownRenderer';
|
||||
import { attachKeybindingLabelStyler } from 'vs/platform/theme/common/styler';
|
||||
import { areSameExtensions } from 'vs/platform/extensionManagement/common/extensionManagementUtil';
|
||||
import { errorIcon, infoIcon, preReleaseIcon, starEmptyIcon, verifiedPublisherIcon as verifiedPublisherThemeIcon, warningIcon } from 'vs/workbench/contrib/extensions/browser/extensionsIcons';
|
||||
import { MarkdownString } from 'vs/base/common/htmlContent';
|
||||
import { errorIcon, infoIcon, preReleaseIcon, verifiedPublisherIcon as verifiedPublisherThemeIcon, warningIcon } from 'vs/workbench/contrib/extensions/browser/extensionsIcons';
|
||||
import { IPaneCompositePartService } from 'vs/workbench/services/panecomposite/browser/panecomposite';
|
||||
import { ViewContainerLocation } from 'vs/workbench/common/views';
|
||||
import { IExtensionGalleryService, IGalleryExtension } from 'vs/platform/extensionManagement/common/extensionManagement';
|
||||
|
@ -147,8 +146,6 @@ interface IExtensionEditorTemplate {
|
|||
description: HTMLElement;
|
||||
actionsAndStatusContainer: HTMLElement;
|
||||
extensionActionBar: ActionBar;
|
||||
status: HTMLElement;
|
||||
recommendation: HTMLElement;
|
||||
navbar: NavBar;
|
||||
content: HTMLElement;
|
||||
header: HTMLElement;
|
||||
|
@ -251,7 +248,6 @@ export class ExtensionEditor extends EditorPane {
|
|||
@INotificationService private readonly notificationService: INotificationService,
|
||||
@IOpenerService private readonly openerService: IOpenerService,
|
||||
@IExtensionRecommendationsService private readonly extensionRecommendationsService: IExtensionRecommendationsService,
|
||||
@IExtensionIgnoredRecommendationsService private readonly extensionIgnoredRecommendationsService: IExtensionIgnoredRecommendationsService,
|
||||
@IStorageService storageService: IStorageService,
|
||||
@IExtensionService private readonly extensionService: IExtensionService,
|
||||
@IWebviewService private readonly webviewService: IWebviewService,
|
||||
|
@ -310,7 +306,7 @@ export class ExtensionEditor extends EditorPane {
|
|||
rating.setAttribute('role', 'link'); // #132645
|
||||
const ratingsWidget = this.instantiationService.createInstance(RatingsWidget, rating, false);
|
||||
|
||||
const widgets = [
|
||||
const widgets: ExtensionWidget[] = [
|
||||
remoteBadge,
|
||||
versionWidget,
|
||||
preReleaseWidget,
|
||||
|
@ -375,14 +371,30 @@ export class ExtensionEditor extends EditorPane {
|
|||
extensionActionBar.setFocusable(true);
|
||||
}));
|
||||
|
||||
const extensionContainers: ExtensionContainers = this.instantiationService.createInstance(ExtensionContainers, [...actions, ...widgets]);
|
||||
for (const disposable of [...actions, ...widgets, extensionContainers]) {
|
||||
const otherExtensionContainers: IExtensionContainer[] = [];
|
||||
const extensionStatusAction = this.instantiationService.createInstance(ExtensionStatusAction);
|
||||
const extensionStatusWidget = this._register(this.instantiationService.createInstance(ExtensionStatusWidget, append(actionsAndStatusContainer, $('.status')), extensionStatusAction));
|
||||
|
||||
otherExtensionContainers.push(extensionStatusAction, new class extends ExtensionWidget {
|
||||
render() {
|
||||
actionsAndStatusContainer.classList.toggle('list-layout', this.extension?.state === ExtensionState.Installed);
|
||||
}
|
||||
}());
|
||||
|
||||
const recommendationWidget = this.instantiationService.createInstance(ExtensionRecommendationWidget, append(details, $('.recommendation')));
|
||||
widgets.push(recommendationWidget);
|
||||
|
||||
this._register(Event.any(extensionStatusWidget.onDidRender, recommendationWidget.onDidRender)(() => {
|
||||
if (this.dimension) {
|
||||
this.layout(this.dimension);
|
||||
}
|
||||
}));
|
||||
|
||||
const extensionContainers: ExtensionContainers = this.instantiationService.createInstance(ExtensionContainers, [...actions, ...widgets, ...otherExtensionContainers]);
|
||||
for (const disposable of [...actions, ...widgets, ...otherExtensionContainers, extensionContainers]) {
|
||||
this._register(disposable);
|
||||
}
|
||||
|
||||
const status = append(actionsAndStatusContainer, $('.status'));
|
||||
const recommendation = append(details, $('.recommendation'));
|
||||
|
||||
this._register(Event.chain(extensionActionBar.onDidRun)
|
||||
.map(({ error }) => error)
|
||||
.filter(error => !!error)
|
||||
|
@ -411,8 +423,6 @@ export class ExtensionEditor extends EditorPane {
|
|||
rating,
|
||||
actionsAndStatusContainer,
|
||||
extensionActionBar,
|
||||
status,
|
||||
recommendation,
|
||||
set extension(extension: IExtension) {
|
||||
extensionContainers.extension = extension;
|
||||
},
|
||||
|
@ -544,9 +554,6 @@ export class ExtensionEditor extends EditorPane {
|
|||
}));
|
||||
}
|
||||
|
||||
this.setStatus(extension, template);
|
||||
this.setRecommendationText(extension, template);
|
||||
|
||||
const manifest = await this.extensionManifest.get().promise;
|
||||
if (token.isCancellationRequested) {
|
||||
return;
|
||||
|
@ -620,72 +627,6 @@ export class ExtensionEditor extends EditorPane {
|
|||
template.navbar.onChange(e => this.onNavbarChange(extension, e, template), this, this.transientDisposables);
|
||||
}
|
||||
|
||||
private setStatus(extension: IExtension, template: IExtensionEditorTemplate): void {
|
||||
const disposables = this.transientDisposables.add(new DisposableStore());
|
||||
const extensionStatus = disposables.add(this.instantiationService.createInstance(ExtensionStatusAction));
|
||||
extensionStatus.extension = extension;
|
||||
const updateStatus = (layout: boolean) => {
|
||||
disposables.clear();
|
||||
reset(template.status);
|
||||
const status = extensionStatus.status;
|
||||
if (status) {
|
||||
if (status.icon) {
|
||||
const statusIconActionBar = disposables.add(new ActionBar(template.status, { animated: false }));
|
||||
statusIconActionBar.push(extensionStatus, { icon: true, label: false });
|
||||
}
|
||||
disposables.add(this.renderMarkdownText(status.message.value, append(template.status, $('.status-text'))));
|
||||
}
|
||||
if (layout && this.dimension) {
|
||||
this.layout(this.dimension);
|
||||
}
|
||||
};
|
||||
updateStatus(false);
|
||||
this.transientDisposables.add(extensionStatus.onDidChangeStatus(() => updateStatus(true)));
|
||||
|
||||
const updateActionLayout = () => template.actionsAndStatusContainer.classList.toggle('list-layout', extension.state === ExtensionState.Installed);
|
||||
updateActionLayout();
|
||||
this.transientDisposables.add(this.extensionsWorkbenchService.onChange(() => updateActionLayout()));
|
||||
}
|
||||
|
||||
private setRecommendationText(extension: IExtension, template: IExtensionEditorTemplate): void {
|
||||
const updateRecommendationText = (layout: boolean) => {
|
||||
reset(template.recommendation);
|
||||
const extRecommendations = this.extensionRecommendationsService.getAllRecommendationsWithReason();
|
||||
if (extRecommendations[extension.identifier.id.toLowerCase()]) {
|
||||
const reasonText = extRecommendations[extension.identifier.id.toLowerCase()].reasonText;
|
||||
if (reasonText) {
|
||||
append(template.recommendation, $(`div${ThemeIcon.asCSSSelector(starEmptyIcon)}`));
|
||||
append(template.recommendation, $(`div.recommendation-text`, undefined, reasonText));
|
||||
}
|
||||
} else if (this.extensionIgnoredRecommendationsService.globalIgnoredRecommendations.indexOf(extension.identifier.id.toLowerCase()) !== -1) {
|
||||
append(template.recommendation, $(`div.recommendation-text`, undefined, localize('recommendationHasBeenIgnored', "You have chosen not to receive recommendations for this extension.")));
|
||||
}
|
||||
if (layout && this.dimension) {
|
||||
this.layout(this.dimension);
|
||||
}
|
||||
};
|
||||
if (extension.deprecationInfo || extension.state === ExtensionState.Installed) {
|
||||
reset(template.recommendation);
|
||||
return;
|
||||
}
|
||||
updateRecommendationText(false);
|
||||
this.transientDisposables.add(this.extensionRecommendationsService.onDidChangeRecommendations(() => updateRecommendationText(true)));
|
||||
}
|
||||
|
||||
private renderMarkdownText(markdownText: string, parent: HTMLElement): IDisposable {
|
||||
const disposables = new DisposableStore();
|
||||
const rendered = disposables.add(renderMarkdown(new MarkdownString(markdownText, { isTrusted: true, supportThemeIcons: true }), {
|
||||
actionHandler: {
|
||||
callback: (content) => {
|
||||
this.openerService.open(content, { allowCommands: true }).catch(onUnexpectedError);
|
||||
},
|
||||
disposables: disposables
|
||||
}
|
||||
}));
|
||||
append(parent, rendered.element);
|
||||
return disposables;
|
||||
}
|
||||
|
||||
override clearInput(): void {
|
||||
this.contentDisposables.clear();
|
||||
this.transientDisposables.clear();
|
||||
|
|
|
@ -2944,6 +2944,7 @@ registerThemingParticipant((theme: IColorTheme, collector: ICssStyleCollector) =
|
|||
const errorColor = theme.getColor(editorErrorForeground);
|
||||
if (errorColor) {
|
||||
collector.addRule(`.monaco-action-bar .action-item .action-label.extension-action.extension-status-error { color: ${errorColor}; }`);
|
||||
collector.addRule(`.extension-editor .header .actions-status-container > .status ${ThemeIcon.asCSSSelector(errorIcon)} { color: ${errorColor}; }`);
|
||||
collector.addRule(`.extension-editor .body .subcontent .runtime-status ${ThemeIcon.asCSSSelector(errorIcon)} { color: ${errorColor}; }`);
|
||||
collector.addRule(`.monaco-hover.extension-hover .markdown-hover .hover-contents ${ThemeIcon.asCSSSelector(errorIcon)} { color: ${errorColor}; }`);
|
||||
}
|
||||
|
@ -2951,6 +2952,7 @@ registerThemingParticipant((theme: IColorTheme, collector: ICssStyleCollector) =
|
|||
const warningColor = theme.getColor(editorWarningForeground);
|
||||
if (warningColor) {
|
||||
collector.addRule(`.monaco-action-bar .action-item .action-label.extension-action.extension-status-warning { color: ${warningColor}; }`);
|
||||
collector.addRule(`.extension-editor .header .actions-status-container > .status ${ThemeIcon.asCSSSelector(warningIcon)} { color: ${warningColor}; }`);
|
||||
collector.addRule(`.extension-editor .body .subcontent .runtime-status ${ThemeIcon.asCSSSelector(warningIcon)} { color: ${warningColor}; }`);
|
||||
collector.addRule(`.monaco-hover.extension-hover .markdown-hover .hover-contents ${ThemeIcon.asCSSSelector(warningIcon)} { color: ${warningColor}; }`);
|
||||
}
|
||||
|
@ -2958,6 +2960,7 @@ registerThemingParticipant((theme: IColorTheme, collector: ICssStyleCollector) =
|
|||
const infoColor = theme.getColor(editorInfoForeground);
|
||||
if (infoColor) {
|
||||
collector.addRule(`.monaco-action-bar .action-item .action-label.extension-action.extension-status-info { color: ${infoColor}; }`);
|
||||
collector.addRule(`.extension-editor .header .actions-status-container > .status ${ThemeIcon.asCSSSelector(infoIcon)} { color: ${infoColor}; }`);
|
||||
collector.addRule(`.extension-editor .body .subcontent .runtime-status ${ThemeIcon.asCSSSelector(infoIcon)} { color: ${infoColor}; }`);
|
||||
collector.addRule(`.monaco-hover.extension-hover .markdown-hover .hover-contents ${ThemeIcon.asCSSSelector(infoIcon)} { color: ${infoColor}; }`);
|
||||
}
|
||||
|
|
|
@ -7,16 +7,16 @@ import 'vs/css!./media/extensionsWidgets';
|
|||
import * as semver from 'vs/base/common/semver/semver';
|
||||
import { Disposable, toDisposable, DisposableStore, MutableDisposable, IDisposable } from 'vs/base/common/lifecycle';
|
||||
import { IExtension, IExtensionsWorkbenchService, IExtensionContainer, ExtensionState, ExtensionEditorTab } from 'vs/workbench/contrib/extensions/common/extensions';
|
||||
import { append, $ } from 'vs/base/browser/dom';
|
||||
import { append, $, reset } from 'vs/base/browser/dom';
|
||||
import * as platform from 'vs/base/common/platform';
|
||||
import { localize } from 'vs/nls';
|
||||
import { EnablementState, IExtensionManagementServerService } from 'vs/workbench/services/extensionManagement/common/extensionManagement';
|
||||
import { IExtensionRecommendationsService } from 'vs/workbench/services/extensionRecommendations/common/extensionRecommendations';
|
||||
import { IExtensionIgnoredRecommendationsService, IExtensionRecommendationsService } from 'vs/workbench/services/extensionRecommendations/common/extensionRecommendations';
|
||||
import { ILabelService } from 'vs/platform/label/common/label';
|
||||
import { extensionButtonProminentBackground, extensionButtonProminentForeground, ExtensionStatusAction, ReloadAction } from 'vs/workbench/contrib/extensions/browser/extensionsActions';
|
||||
import { IThemeService, ThemeIcon, registerThemingParticipant } from 'vs/platform/theme/common/themeService';
|
||||
import { EXTENSION_BADGE_REMOTE_BACKGROUND, EXTENSION_BADGE_REMOTE_FOREGROUND } from 'vs/workbench/common/theme';
|
||||
import { Event } from 'vs/base/common/event';
|
||||
import { Emitter, Event } from 'vs/base/common/event';
|
||||
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
|
||||
import { CountBadge } from 'vs/base/browser/ui/countBadge/countBadge';
|
||||
import { IConfigurationService } from 'vs/platform/configuration/common/configuration';
|
||||
|
@ -32,6 +32,9 @@ import { areSameExtensions } from 'vs/platform/extensionManagement/common/extens
|
|||
import Severity from 'vs/base/common/severity';
|
||||
import { setupCustomHover } from 'vs/base/browser/ui/iconLabel/iconLabelHover';
|
||||
import { Color } from 'vs/base/common/color';
|
||||
import { renderMarkdown } from 'vs/base/browser/markdownRenderer';
|
||||
import { IOpenerService } from 'vs/platform/opener/common/opener';
|
||||
import { onUnexpectedError } from 'vs/base/common/errors';
|
||||
|
||||
export abstract class ExtensionWidget extends Disposable implements IExtensionContainer {
|
||||
private _extension: IExtension | null = null;
|
||||
|
@ -576,6 +579,93 @@ export class ExtensionHoverWidget extends ExtensionWidget {
|
|||
|
||||
}
|
||||
|
||||
export class ExtensionStatusWidget extends ExtensionWidget {
|
||||
|
||||
private readonly renderDisposables = this._register(new DisposableStore());
|
||||
|
||||
private readonly _onDidRender = this._register(new Emitter<void>());
|
||||
readonly onDidRender: Event<void> = this._onDidRender.event;
|
||||
|
||||
constructor(
|
||||
private readonly container: HTMLElement,
|
||||
private readonly extensionStatusAction: ExtensionStatusAction,
|
||||
@IOpenerService private readonly openerService: IOpenerService,
|
||||
) {
|
||||
super();
|
||||
this.render();
|
||||
this._register(extensionStatusAction.onDidChangeStatus(() => this.render()));
|
||||
}
|
||||
|
||||
render(): void {
|
||||
reset(this.container);
|
||||
const extensionStatus = this.extensionStatusAction.status;
|
||||
if (extensionStatus) {
|
||||
const markdown = new MarkdownString('', { isTrusted: true, supportThemeIcons: true });
|
||||
if (extensionStatus.icon) {
|
||||
markdown.appendMarkdown(`$(${extensionStatus.icon.id}) `);
|
||||
}
|
||||
markdown.appendMarkdown(extensionStatus.message.value);
|
||||
const rendered = this.renderDisposables.add(renderMarkdown(markdown, {
|
||||
actionHandler: {
|
||||
callback: (content) => {
|
||||
this.openerService.open(content, { allowCommands: true }).catch(onUnexpectedError);
|
||||
},
|
||||
disposables: this.renderDisposables
|
||||
}
|
||||
}));
|
||||
append(this.container, rendered.element);
|
||||
}
|
||||
this._onDidRender.fire();
|
||||
}
|
||||
}
|
||||
|
||||
export class ExtensionRecommendationWidget extends ExtensionWidget {
|
||||
|
||||
private readonly _onDidRender = this._register(new Emitter<void>());
|
||||
readonly onDidRender: Event<void> = this._onDidRender.event;
|
||||
|
||||
constructor(
|
||||
private readonly container: HTMLElement,
|
||||
@IExtensionRecommendationsService private readonly extensionRecommendationsService: IExtensionRecommendationsService,
|
||||
@IExtensionIgnoredRecommendationsService private readonly extensionIgnoredRecommendationsService: IExtensionIgnoredRecommendationsService,
|
||||
) {
|
||||
super();
|
||||
this.render();
|
||||
this._register(this.extensionRecommendationsService.onDidChangeRecommendations(() => this.render()));
|
||||
}
|
||||
|
||||
render(): void {
|
||||
reset(this.container);
|
||||
const recommendationStatus = this.getRecommendationStatus();
|
||||
if (recommendationStatus) {
|
||||
if (recommendationStatus.icon) {
|
||||
append(this.container, $(`div${ThemeIcon.asCSSSelector(recommendationStatus.icon)}`));
|
||||
}
|
||||
append(this.container, $(`div.recommendation-text`, undefined, recommendationStatus.message));
|
||||
}
|
||||
this._onDidRender.fire();
|
||||
}
|
||||
|
||||
private getRecommendationStatus(): { icon: ThemeIcon | undefined; message: string } | undefined {
|
||||
if (!this.extension
|
||||
|| this.extension.deprecationInfo
|
||||
|| this.extension.state === ExtensionState.Installed
|
||||
) {
|
||||
return undefined;
|
||||
}
|
||||
const extRecommendations = this.extensionRecommendationsService.getAllRecommendationsWithReason();
|
||||
if (extRecommendations[this.extension.identifier.id.toLowerCase()]) {
|
||||
const reasonText = extRecommendations[this.extension.identifier.id.toLowerCase()].reasonText;
|
||||
if (reasonText) {
|
||||
return { icon: starEmptyIcon, message: reasonText };
|
||||
}
|
||||
} else if (this.extensionIgnoredRecommendationsService.globalIgnoredRecommendations.indexOf(this.extension.identifier.id.toLowerCase()) !== -1) {
|
||||
return { icon: undefined, message: localize('recommendationHasBeenIgnored', "You have chosen not to receive recommendations for this extension.") };
|
||||
}
|
||||
return undefined;
|
||||
}
|
||||
}
|
||||
|
||||
// Rating icon
|
||||
export const extensionRatingIconColor = registerColor('extensionIcon.starForeground', { light: '#DF6100', dark: '#FF8E00', hcDark: '#FF8E00', hcLight: textLinkForeground }, localize('extensionIconStarForeground', "The icon color for extension ratings."), true);
|
||||
export const extensionVerifiedPublisherIconColor = registerColor('extensionIcon.verifiedForeground', { dark: textLinkForeground, light: textLinkForeground, hcDark: textLinkForeground, hcLight: textLinkForeground }, localize('extensionIconVerifiedForeground', "The icon color for extension verified publisher."), true);
|
||||
|
|
|
@ -249,49 +249,36 @@
|
|||
.extension-editor > .header > .details > .actions-status-container > .status {
|
||||
line-height: 22px;
|
||||
font-size: 90%;
|
||||
display: flex;
|
||||
margin-top: 3px;
|
||||
}
|
||||
|
||||
.extension-editor > .header > .details > .actions-status-container.list-layout > .status {
|
||||
margin-top: 5px;
|
||||
}
|
||||
|
||||
.extension-editor > .header > .details > .actions-status-container > .status > .monaco-action-bar {
|
||||
height: 22px;
|
||||
margin-right: 2px;
|
||||
}
|
||||
|
||||
.extension-editor > .header > .details > .actions-status-container > .status > .monaco-action-bar .extension-action {
|
||||
margin-top: 3px;
|
||||
}
|
||||
|
||||
.extension-editor > .header > .details > .actions-status-container.list-layout > .status > .monaco-action-bar .extension-action {
|
||||
margin-top: 0px;
|
||||
}
|
||||
|
||||
.extension-editor > .header > .details > .actions-status-container:not(.list-layout) > .status > .status-text {
|
||||
margin-top: 2px;
|
||||
.extension-editor > .header > .details > .actions-status-container > .status .codicon {
|
||||
vertical-align: text-bottom;
|
||||
}
|
||||
|
||||
.extension-editor > .header > .details > .pre-release-text p,
|
||||
.extension-editor > .header > .details > .actions-status-container > .status > .status-text p {
|
||||
.extension-editor > .header > .details > .actions-status-container > .status p {
|
||||
margin-top: 0px;
|
||||
margin-bottom: 0px;
|
||||
}
|
||||
|
||||
.extension-editor > .header > .details > .pre-release-text a,
|
||||
.extension-editor > .header > .details > .actions-status-container > .status > .status-text a {
|
||||
.extension-editor > .header > .details > .actions-status-container > .status a {
|
||||
color: var(--vscode-textLink-foreground)
|
||||
}
|
||||
|
||||
.extension-editor > .header > .details > .pre-release-text a:hover,
|
||||
.extension-editor > .header > .details > .actions-status-container > .status > .status-text a:hover {
|
||||
.extension-editor > .header > .details > .actions-status-container > .status a:hover {
|
||||
text-decoration: underline;
|
||||
color: var(--vscode-textLink-activeForeground)
|
||||
}
|
||||
|
||||
.extension-editor > .header > .details > .pre-release-text a:active,
|
||||
.extension-editor > .header > .details > .actions-status-container > .status > .status-text a:active {
|
||||
.extension-editor > .header > .details > .actions-status-container > .status a:active {
|
||||
color: var(--vscode-textLink-activeForeground)
|
||||
}
|
||||
|
||||
|
|
|
@ -9,7 +9,7 @@ import { IPager } from 'vs/base/common/paging';
|
|||
import { IQueryOptions, ILocalExtension, IGalleryExtension, IExtensionIdentifier, InstallOptions, InstallVSIXOptions, IExtensionInfo, IExtensionQueryOptions, IDeprecationInfo } from 'vs/platform/extensionManagement/common/extensionManagement';
|
||||
import { EnablementState, IExtensionManagementServer } from 'vs/workbench/services/extensionManagement/common/extensionManagement';
|
||||
import { CancellationToken } from 'vs/base/common/cancellation';
|
||||
import { Disposable } from 'vs/base/common/lifecycle';
|
||||
import { Disposable, IDisposable } from 'vs/base/common/lifecycle';
|
||||
import { areSameExtensions } from 'vs/platform/extensionManagement/common/extensionManagementUtil';
|
||||
import { IExtensionManifest, ExtensionType } from 'vs/platform/extensions/common/extensions';
|
||||
import { URI } from 'vs/base/common/uri';
|
||||
|
@ -136,7 +136,7 @@ export interface IExtensionsConfiguration {
|
|||
closeExtensionDetailsOnViewChange: boolean;
|
||||
}
|
||||
|
||||
export interface IExtensionContainer {
|
||||
export interface IExtensionContainer extends IDisposable {
|
||||
extension: IExtension | null;
|
||||
updateWhenCounterExtensionChanges?: boolean;
|
||||
update(): void;
|
||||
|
|
|
@ -65,10 +65,10 @@ export class ExplorerDecorationsProvider implements IDecorationsProvider {
|
|||
return this._onDidChange.event;
|
||||
}
|
||||
|
||||
provideDecorations(resource: URI): IDecorationData | undefined {
|
||||
async provideDecorations(resource: URI): Promise<IDecorationData | undefined> {
|
||||
const fileStat = this.explorerService.findClosest(resource);
|
||||
if (!fileStat) {
|
||||
return undefined;
|
||||
throw new Error('ExplorerItem not found');
|
||||
}
|
||||
|
||||
return provideDecorations(fileStat);
|
||||
|
|
|
@ -4,7 +4,6 @@
|
|||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import { language } from 'vs/base/common/platform';
|
||||
import { registerSingleton } from 'vs/platform/instantiation/common/extensions';
|
||||
import { ILanguagePackItem } from 'vs/platform/languagePacks/common/languagePacks';
|
||||
import { ILocaleService } from 'vs/workbench/contrib/localization/common/locale';
|
||||
|
||||
|
@ -32,5 +31,3 @@ export class WebLocaleService implements ILocaleService {
|
|||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
registerSingleton(ILocaleService, WebLocaleService, true);
|
||||
|
|
|
@ -4,7 +4,12 @@
|
|||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import { registerAction2 } from 'vs/platform/actions/common/actions';
|
||||
import { registerSingleton } from 'vs/platform/instantiation/common/extensions';
|
||||
import { WebLocaleService } from 'vs/workbench/contrib/localization/browser/localeService';
|
||||
import { ClearDisplayLanguageAction, ConfigureDisplayLanguageAction } from 'vs/workbench/contrib/localization/browser/localizationsActions';
|
||||
import { ILocaleService } from 'vs/workbench/contrib/localization/common/locale';
|
||||
|
||||
registerSingleton(ILocaleService, WebLocaleService, true);
|
||||
|
||||
// Register action to configure locale and related settings
|
||||
registerAction2(ConfigureDisplayLanguageAction);
|
||||
|
|
|
@ -45,7 +45,7 @@ export class ConfigureDisplayLanguageAction extends Action2 {
|
|||
qp.placeholder = localize('chooseLocale', "Select Display Language");
|
||||
|
||||
if (installedLanguages?.length) {
|
||||
const items: Array<ILanguagePackItem | IQuickPickSeparator> = [{ type: 'separator', label: localize('installed', "Installed languages") }];
|
||||
const items: Array<ILanguagePackItem | IQuickPickSeparator> = [{ type: 'separator', label: localize('installed', "Installed") }];
|
||||
qp.items = items.concat(installedLanguages);
|
||||
}
|
||||
|
||||
|
@ -62,7 +62,7 @@ export class ConfigureDisplayLanguageAction extends Action2 {
|
|||
if (newLanguages.length) {
|
||||
qp.items = [
|
||||
...qp.items,
|
||||
{ type: 'separator', label: localize('available', "Available languages") },
|
||||
{ type: 'separator', label: localize('available', "Available") },
|
||||
...newLanguages
|
||||
];
|
||||
}
|
||||
|
|
|
@ -5,7 +5,6 @@
|
|||
|
||||
import { language } from 'vs/base/common/platform';
|
||||
import { IEnvironmentService } from 'vs/platform/environment/common/environment';
|
||||
import { registerSingleton } from 'vs/platform/instantiation/common/extensions';
|
||||
import { INotificationService } from 'vs/platform/notification/common/notification';
|
||||
import { IJSONEditingService } from 'vs/workbench/services/configuration/common/jsonEditing';
|
||||
import { ILocaleService } from 'vs/workbench/contrib/localization/common/locale';
|
||||
|
@ -14,6 +13,8 @@ import { IPaneCompositePartService } from 'vs/workbench/services/panecomposite/b
|
|||
import { IExtensionsViewPaneContainer, VIEWLET_ID as EXTENSIONS_VIEWLET_ID } from 'vs/workbench/contrib/extensions/common/extensions';
|
||||
import { ViewContainerLocation } from 'vs/workbench/common/views';
|
||||
import { IExtensionManagementService } from 'vs/platform/extensionManagement/common/extensionManagement';
|
||||
import { IProgressService, ProgressLocation } from 'vs/platform/progress/common/progress';
|
||||
import { localize } from 'vs/nls';
|
||||
|
||||
export class NativeLocaleService implements ILocaleService {
|
||||
_serviceBrand: undefined;
|
||||
|
@ -25,6 +26,7 @@ export class NativeLocaleService implements ILocaleService {
|
|||
@ILanguagePackService private readonly languagePackService: ILanguagePackService,
|
||||
@IPaneCompositePartService private readonly paneCompositePartService: IPaneCompositePartService,
|
||||
@IExtensionManagementService private readonly extensionManagementService: IExtensionManagementService,
|
||||
@IProgressService private readonly progressService: IProgressService
|
||||
) { }
|
||||
|
||||
private async writeLocaleValue(locale: string | undefined): Promise<void> {
|
||||
|
@ -42,16 +44,26 @@ export class NativeLocaleService implements ILocaleService {
|
|||
// Only Desktop has the concept of installing language packs so we only do this for Desktop
|
||||
// and only if the language pack is not installed
|
||||
if (!installedLanguages.some(installedLanguage => installedLanguage.id === languagePackItem.id)) {
|
||||
// Show the view so the user can see the language pack to be installed
|
||||
const viewlet = await this.paneCompositePartService.openPaneComposite(EXTENSIONS_VIEWLET_ID, ViewContainerLocation.Sidebar);
|
||||
(viewlet?.getViewPaneContainer() as IExtensionsViewPaneContainer).search(`@id:${languagePackItem.extensionId}`);
|
||||
|
||||
// Only actually install a language pack from Microsoft
|
||||
if (languagePackItem.galleryExtension?.publisher.toLowerCase() !== 'ms-ceintl') {
|
||||
// Show the view so the user can see the language pack that they should install
|
||||
// as of now, there are no 3rd party language packs available on the Marketplace.
|
||||
const viewlet = await this.paneCompositePartService.openPaneComposite(EXTENSIONS_VIEWLET_ID, ViewContainerLocation.Sidebar);
|
||||
(viewlet?.getViewPaneContainer() as IExtensionsViewPaneContainer).search(`@id:${languagePackItem.extensionId}`);
|
||||
return false;
|
||||
}
|
||||
|
||||
await this.extensionManagementService.installFromGallery(languagePackItem.galleryExtension);
|
||||
await this.progressService.withProgress(
|
||||
{
|
||||
location: ProgressLocation.Notification,
|
||||
title: localize('installing', "Installing {0} language support...", languagePackItem.label),
|
||||
},
|
||||
progress => this.extensionManagementService.installFromGallery(languagePackItem.galleryExtension!, {
|
||||
// Setting this to false is how you get the extension to be synced with Settings Sync (if enabled).
|
||||
isMachineScoped: false,
|
||||
})
|
||||
);
|
||||
}
|
||||
|
||||
await this.writeLocaleValue(locale);
|
||||
|
@ -75,5 +87,3 @@ export class NativeLocaleService implements ILocaleService {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
registerSingleton(ILocaleService, NativeLocaleService, true);
|
||||
|
|
|
@ -25,6 +25,11 @@ import { IPaneCompositePartService } from 'vs/workbench/services/panecomposite/b
|
|||
import { ViewContainerLocation } from 'vs/workbench/common/views';
|
||||
import { registerAction2 } from 'vs/platform/actions/common/actions';
|
||||
import { ClearDisplayLanguageAction, ConfigureDisplayLanguageAction } from 'vs/workbench/contrib/localization/browser/localizationsActions';
|
||||
import { registerSingleton } from 'vs/platform/instantiation/common/extensions';
|
||||
import { ILocaleService } from 'vs/workbench/contrib/localization/common/locale';
|
||||
import { NativeLocaleService } from 'vs/workbench/contrib/localization/electron-sandbox/localeService';
|
||||
|
||||
registerSingleton(ILocaleService, NativeLocaleService, true);
|
||||
|
||||
// Register action to configure locale and related settings
|
||||
registerAction2(ConfigureDisplayLanguageAction);
|
||||
|
|
|
@ -11,7 +11,7 @@ import { LineRange } from 'vs/workbench/contrib/mergeEditor/browser/model';
|
|||
|
||||
export class EditorGutter<
|
||||
T extends IGutterItemInfo = IGutterItemInfo
|
||||
> extends Disposable {
|
||||
> extends Disposable {
|
||||
private readonly scrollTop = observableFromEvent(
|
||||
this._editor.onDidScrollChange,
|
||||
(e) => this._editor.getScrollTop()
|
||||
|
|
|
@ -285,15 +285,15 @@ export class NotebookClipboardContribution extends Disposable {
|
|||
}
|
||||
|
||||
if (PasteAction) {
|
||||
PasteAction.addImplementation(PRIORITY, 'notebook-clipboard', accessor => {
|
||||
this._register(PasteAction.addImplementation(PRIORITY, 'notebook-clipboard', accessor => {
|
||||
return this.runPasteAction(accessor);
|
||||
});
|
||||
}));
|
||||
}
|
||||
|
||||
if (CutAction) {
|
||||
CutAction.addImplementation(PRIORITY, 'notebook-clipboard', accessor => {
|
||||
this._register(CutAction.addImplementation(PRIORITY, 'notebook-clipboard', accessor => {
|
||||
return this.runCutAction(accessor);
|
||||
});
|
||||
}));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -131,21 +131,20 @@ const notebookRendererContribution: IJSONSchema = {
|
|||
{
|
||||
type: 'string',
|
||||
},
|
||||
// todo@connor4312 + @mjbvz: uncomment this once it's ready for external adoption
|
||||
// {
|
||||
// type: 'object',
|
||||
// required: ['extends', 'path'],
|
||||
// properties: {
|
||||
// extends: {
|
||||
// type: 'string',
|
||||
// description: nls.localize('contributes.notebook.renderer.entrypoint.extends', 'Existing renderer that this one extends.'),
|
||||
// },
|
||||
// path: {
|
||||
// type: 'string',
|
||||
// description: nls.localize('contributes.notebook.renderer.entrypoint', 'File to load in the webview to render the extension.'),
|
||||
// },
|
||||
// }
|
||||
// }
|
||||
{
|
||||
type: 'object',
|
||||
required: ['extends', 'path'],
|
||||
properties: {
|
||||
extends: {
|
||||
type: 'string',
|
||||
description: nls.localize('contributes.notebook.renderer.entrypoint.extends', 'Existing renderer that this one extends.'),
|
||||
},
|
||||
path: {
|
||||
type: 'string',
|
||||
description: nls.localize('contributes.notebook.renderer.entrypoint', 'File to load in the webview to render the extension.'),
|
||||
},
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
[NotebookRendererContribution.hardDependencies]: {
|
||||
|
|
|
@ -75,7 +75,7 @@ export const RENDERER_EQUIVALENT_EXTENSIONS: ReadonlyMap<string, ReadonlySet<str
|
|||
|
||||
export const RENDERER_NOT_AVAILABLE = '_notAvailable';
|
||||
|
||||
export type NotebookRendererEntrypoint = string | { extends: string; path: string };
|
||||
export type NotebookRendererEntrypoint = string | { readonly extends: string; readonly path: string };
|
||||
|
||||
export enum NotebookRunState {
|
||||
Running = 1,
|
||||
|
|
|
@ -109,15 +109,23 @@
|
|||
/* padding must be on action-label because it has the bottom-border, because that's where the .checked class is */
|
||||
}
|
||||
|
||||
.settings-editor > .settings-header > .settings-header-controls .settings-tabs-widget > .monaco-action-bar .action-item.focused {
|
||||
outline-offset: -1.5px;
|
||||
}
|
||||
|
||||
.settings-editor > .settings-header > .settings-header-controls .settings-tabs-widget > .monaco-action-bar .action-item .action-label {
|
||||
text-transform: none;
|
||||
font-size: 13px;
|
||||
padding-bottom: 7px;
|
||||
padding-bottom: 6.5px;
|
||||
padding-top: 7px;
|
||||
padding-left: 8px;
|
||||
padding-right: 8px;
|
||||
}
|
||||
|
||||
.settings-editor > .settings-header > .settings-header-controls .settings-tabs-widget > .monaco-action-bar .action-item .action-label .dropdown-icon {
|
||||
padding-top: 2px;
|
||||
}
|
||||
|
||||
.settings-editor > .settings-header > .settings-header-controls .settings-tabs-widget > .monaco-action-bar .action-item .action-label:not(.checked):not(:focus) {
|
||||
/* Add an extra pixel due to it not getting the outline */
|
||||
padding-bottom: 8px;
|
||||
|
|
|
@ -37,7 +37,7 @@ export function isSCMResource(element: any): element is ISCMResource {
|
|||
return !!(element as ISCMResource).sourceUri && isSCMResourceGroup((element as ISCMResource).resourceGroup);
|
||||
}
|
||||
|
||||
const compareActions = (a: IAction, b: IAction) => a.id === b.id;
|
||||
const compareActions = (a: IAction, b: IAction) => a.id === b.id && a.enabled === b.enabled;
|
||||
|
||||
export function connectPrimaryMenu(menu: IMenu, callback: (primary: IAction[], secondary: IAction[]) => void, primaryGroup?: string): IDisposable {
|
||||
let cachedDisposable: IDisposable = Disposable.None;
|
||||
|
|
|
@ -1480,7 +1480,7 @@ namespace ConfiguringTask {
|
|||
for (const required of typeDeclaration.required) {
|
||||
const value = result.configures[required];
|
||||
if (value) {
|
||||
label = label + ' ' + value;
|
||||
label = label + ': ' + value;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -71,6 +71,14 @@ __vsc_command_complete() {
|
|||
__vsc_update_cwd
|
||||
}
|
||||
|
||||
if [[ -o NOUNSET ]]; then
|
||||
if [ -z "${RPROMPT-}" ]; then
|
||||
RPROMPT=""
|
||||
fi
|
||||
if [ -z "${PREFIX-}" ]; then
|
||||
PREFIX=""
|
||||
fi
|
||||
fi
|
||||
__vsc_update_prompt() {
|
||||
__vsc_prior_prompt="$PS1"
|
||||
__vsc_in_command_execution=""
|
||||
|
|
|
@ -929,10 +929,12 @@ export class TerminalService implements ITerminalService {
|
|||
// Await the initialization of available profiles as long as this is not a pty terminal or a
|
||||
// local terminal in a remote workspace as profile won't be used in those cases and these
|
||||
// terminals need to be launched before remote connections are established.
|
||||
const isPtyTerminal = options?.config && 'customPtyImplementation' in options.config;
|
||||
const isLocalInRemoteTerminal = this._remoteAgentService.getConnection() && URI.isUri(options?.cwd) && options?.cwd.scheme === Schemas.vscodeFileResource;
|
||||
if (!isPtyTerminal && !isLocalInRemoteTerminal) {
|
||||
await this._terminalProfileService.profilesReady;
|
||||
if (this._terminalProfileService.availableProfiles.length === 0) {
|
||||
const isPtyTerminal = options?.config && 'customPtyImplementation' in options.config;
|
||||
const isLocalInRemoteTerminal = this._remoteAgentService.getConnection() && URI.isUri(options?.cwd) && options?.cwd.scheme === Schemas.vscodeFileResource;
|
||||
if (!isPtyTerminal && !isLocalInRemoteTerminal) {
|
||||
await this._terminalProfileService.profilesReady;
|
||||
}
|
||||
}
|
||||
|
||||
const config = options?.config || this._terminalProfileService.availableProfiles?.find(p => p.profileName === this._terminalProfileService.getDefaultProfileName());
|
||||
|
|
|
@ -118,8 +118,11 @@ export class DecorationAddon extends Disposable implements ITerminalAddon {
|
|||
}
|
||||
|
||||
public clearDecorations(): void {
|
||||
this._placeholderDecoration?.dispose();
|
||||
this._placeholderDecoration?.marker.dispose();
|
||||
if (this._placeholderDecoration) {
|
||||
this._placeholderDecoration.marker.dispose();
|
||||
this._placeholderDecoration.dispose();
|
||||
this._placeholderDecoration = undefined;
|
||||
}
|
||||
for (const value of this._decorations.values()) {
|
||||
value.decoration.dispose();
|
||||
dispose(value.disposables);
|
||||
|
|
|
@ -398,7 +398,8 @@ export class DecorationsService implements IDecorationsService {
|
|||
|
||||
private _keepItem(map: DecorationEntry, provider: IDecorationsProvider, uri: URI, data: IDecorationData | undefined): IDecorationData | null {
|
||||
const deco = data ? data : null;
|
||||
const old = map.set(provider, deco);
|
||||
const old = map.get(provider);
|
||||
map.set(provider, deco);
|
||||
if (deco || old) {
|
||||
// only fire event when something changed
|
||||
this._onDidChangeDecorationsDelayed.fire(uri);
|
||||
|
|
|
@ -30,7 +30,7 @@ import { flatten } from 'vs/base/common/arrays';
|
|||
import { INativeHostService } from 'vs/platform/native/electron-sandbox/native';
|
||||
import { IRemoteExplorerService } from 'vs/workbench/services/remote/common/remoteExplorerService';
|
||||
import { Action2, registerAction2 } from 'vs/platform/actions/common/actions';
|
||||
import { getRemoteName } from 'vs/platform/remote/common/remoteHosts';
|
||||
import { getRemoteName, parseAuthorityWithPort } from 'vs/platform/remote/common/remoteHosts';
|
||||
import { IRemoteAgentEnvironment } from 'vs/platform/remote/common/remoteAgentEnvironment';
|
||||
import { IWebWorkerExtensionHostDataProvider, IWebWorkerExtensionHostInitData, WebWorkerExtensionHost } from 'vs/workbench/services/extensions/browser/webWorkerExtensionHost';
|
||||
import { IWorkspaceContextService } from 'vs/platform/workspace/common/workspace';
|
||||
|
@ -349,12 +349,12 @@ export abstract class ElectronExtensionService extends AbstractExtensionService
|
|||
const authorityPlusIndex = remoteAuthority.indexOf('+');
|
||||
if (authorityPlusIndex === -1) {
|
||||
// This authority does not need to be resolved, simply parse the port number
|
||||
const lastColon = remoteAuthority.lastIndexOf(':');
|
||||
const { host, port } = parseAuthorityWithPort(remoteAuthority);
|
||||
return {
|
||||
authority: {
|
||||
authority: remoteAuthority,
|
||||
host: remoteAuthority.substring(0, lastColon),
|
||||
port: parseInt(remoteAuthority.substring(lastColon + 1), 10),
|
||||
host,
|
||||
port,
|
||||
connectionToken: undefined
|
||||
}
|
||||
};
|
||||
|
|
|
@ -83,7 +83,6 @@ import 'vs/workbench/services/files/electron-sandbox/elevatedFileService';
|
|||
import 'vs/workbench/services/search/electron-sandbox/searchService';
|
||||
import 'vs/workbench/services/workingCopy/electron-sandbox/workingCopyHistoryService';
|
||||
import 'vs/workbench/services/userDataSync/browser/userDataSyncEnablementService';
|
||||
import 'vs/workbench/contrib/localization/electron-sandbox/localeService';
|
||||
|
||||
import { registerSingleton } from 'vs/platform/instantiation/common/extensions';
|
||||
import { IUserDataInitializationService, UserDataInitializationService } from 'vs/workbench/services/userData/browser/userDataInit';
|
||||
|
|
|
@ -62,7 +62,6 @@ import 'vs/workbench/services/files/browser/elevatedFileService';
|
|||
import 'vs/workbench/services/workingCopy/browser/workingCopyHistoryService';
|
||||
import 'vs/workbench/services/userDataSync/browser/webUserDataSyncEnablementService';
|
||||
import 'vs/workbench/services/configurationResolver/browser/configurationResolverService';
|
||||
import 'vs/workbench/contrib/localization/browser/localeService';
|
||||
|
||||
import { registerSingleton } from 'vs/platform/instantiation/common/extensions';
|
||||
import { IAccessibilityService } from 'vs/platform/accessibility/common/accessibility';
|
||||
|
|
|
@ -19,11 +19,11 @@ declare module 'vscode' {
|
|||
* a {@link DataTransfer} and is passed back to the provider in {@link provideDocumentPasteEdits}.
|
||||
*
|
||||
* @param document Document where the copy took place.
|
||||
* @param range Range being copied in the `document`.
|
||||
* @param ranges Ranges being copied in the `document`.
|
||||
* @param dataTransfer The data transfer associated with the copy. You can store additional values on this for later use in {@link provideDocumentPasteEdits}.
|
||||
* @param token A cancellation token.
|
||||
*/
|
||||
prepareDocumentPaste?(document: TextDocument, range: Range, dataTransfer: DataTransfer, token: CancellationToken): void | Thenable<void>;
|
||||
prepareDocumentPaste?(document: TextDocument, ranges: readonly Range[], dataTransfer: DataTransfer, token: CancellationToken): void | Thenable<void>;
|
||||
|
||||
/**
|
||||
* Invoked before the user pastes into a document.
|
||||
|
@ -31,16 +31,40 @@ declare module 'vscode' {
|
|||
* In this method, extensions can return a workspace edit that replaces the standard pasting behavior.
|
||||
*
|
||||
* @param document Document being pasted into
|
||||
* @param range Currently selected range in the document.
|
||||
* @param ranges Currently selected ranges in the document.
|
||||
* @param dataTransfer The data transfer associated with the paste.
|
||||
* @param token A cancellation token.
|
||||
*
|
||||
* @return Optional workspace edit that applies the paste. Return undefined to use standard pasting.
|
||||
*/
|
||||
provideDocumentPasteEdits(document: TextDocument, range: Range, dataTransfer: DataTransfer, token: CancellationToken): ProviderResult<WorkspaceEdit | SnippetTextEdit>;
|
||||
provideDocumentPasteEdits(document: TextDocument, ranges: readonly Range[], dataTransfer: DataTransfer, token: CancellationToken): ProviderResult<DocumentPasteEdit>;
|
||||
}
|
||||
|
||||
/**
|
||||
* An operation applied on paste
|
||||
*/
|
||||
interface DocumentPasteEdit {
|
||||
/**
|
||||
* The text or snippet to insert at the pasted locations.
|
||||
*/
|
||||
readonly insertText: string | SnippetString;
|
||||
|
||||
/**
|
||||
* An optional additional edit to apply on paste.
|
||||
*/
|
||||
readonly additionalEdit?: WorkspaceEdit;
|
||||
}
|
||||
|
||||
interface DocumentPasteProviderMetadata {
|
||||
/**
|
||||
* Mime types that `provideDocumentPasteEdits` should be invoked for.
|
||||
*
|
||||
* Use the special `files` mimetype to indicate the provider should be invoked if any files are present in the `DataTransfer`.
|
||||
*/
|
||||
readonly pasteMimeTypes: readonly string[];
|
||||
}
|
||||
|
||||
namespace languages {
|
||||
export function registerDocumentPasteEditProvider(selector: DocumentSelector, provider: DocumentPasteEditProvider): Disposable;
|
||||
export function registerDocumentPasteEditProvider(selector: DocumentSelector, provider: DocumentPasteEditProvider, metadata: DocumentPasteProviderMetadata): Disposable;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -7,12 +7,6 @@ declare module 'vscode' {
|
|||
|
||||
// https://github.com/microsoft/vscode/issues/142990
|
||||
|
||||
export class SnippetTextEdit {
|
||||
snippet: SnippetString;
|
||||
range: Range;
|
||||
constructor(range: Range, snippet: SnippetString);
|
||||
}
|
||||
|
||||
/**
|
||||
* Provider which handles dropping of resources into a text editor.
|
||||
*
|
||||
|
@ -27,10 +21,25 @@ declare module 'vscode' {
|
|||
* @param dataTransfer A {@link DataTransfer} object that holds data about what is being dragged and dropped.
|
||||
* @param token A cancellation token.
|
||||
*
|
||||
* @return A {@link SnippetTextEdit} or a thenable that resolves to such. The lack of a result can be
|
||||
* @return A {@link DocumentDropEdit} or a thenable that resolves to such. The lack of a result can be
|
||||
* signaled by returning `undefined` or `null`.
|
||||
*/
|
||||
provideDocumentOnDropEdits(document: TextDocument, position: Position, dataTransfer: DataTransfer, token: CancellationToken): ProviderResult<SnippetTextEdit>;
|
||||
provideDocumentOnDropEdits(document: TextDocument, position: Position, dataTransfer: DataTransfer, token: CancellationToken): ProviderResult<DocumentDropEdit>;
|
||||
}
|
||||
|
||||
/**
|
||||
* An edit operation applied on drop.
|
||||
*/
|
||||
export interface DocumentDropEdit {
|
||||
/**
|
||||
* The text or snippet to insert at the drop location.
|
||||
*/
|
||||
readonly insertText: string | SnippetString;
|
||||
|
||||
/**
|
||||
* An optional additional edit to apply on drop.
|
||||
*/
|
||||
readonly additionalEdit?: WorkspaceEdit;
|
||||
}
|
||||
|
||||
export namespace languages {
|
||||
|
|
|
@ -11390,10 +11390,10 @@ typescript@^2.6.2:
|
|||
resolved "https://registry.yarnpkg.com/typescript/-/typescript-2.6.2.tgz#3c5b6fd7f6de0914269027f03c0946758f7673a4"
|
||||
integrity sha1-PFtv1/beCRQmkCfwPAlGdY92c6Q=
|
||||
|
||||
typescript@^4.8.0-dev.20220518:
|
||||
version "4.8.0-dev.20220518"
|
||||
resolved "https://registry.yarnpkg.com/typescript/-/typescript-4.8.0-dev.20220518.tgz#3082c89c764daece904480552b9f2c3f5ce79c56"
|
||||
integrity sha512-yczRLiowXD4THxpe2DrClYXsmIRt9VPDft1dat4Le50mQwuUcmvdqD43o4hmlbNP7HpyeEYX51KXozGq1s7zlw==
|
||||
typescript@^4.8.0-dev.20220608:
|
||||
version "4.8.0-dev.20220608"
|
||||
resolved "https://registry.yarnpkg.com/typescript/-/typescript-4.8.0-dev.20220608.tgz#6da2ea3c79307b1dfc1cb3692b142cc13f974a98"
|
||||
integrity sha512-cayjhBae7omJ5MYxt4fO2PNW7kjYNCRqOOQbafxuzP0SWpqznzPROuNQqiBK1KJfgnRxBWeyqGBP52mdZDYZVw==
|
||||
|
||||
typical@^4.0.0:
|
||||
version "4.0.0"
|
||||
|
|
Loading…
Reference in a new issue