Merge branch 'master' into joh/celldocs

This commit is contained in:
Johannes Rieken 2020-08-11 12:23:11 +02:00
commit 0a03053724
59 changed files with 411 additions and 702 deletions

View file

@ -1,7 +1,7 @@
name: "Deep Classifier: Runner"
on:
schedule:
- cron: 0/30 * * * *
- cron: 0 * * * *
repository_dispatch:
types: [trigger-deep-classifier-runner]
@ -24,7 +24,7 @@ jobs:
uses: ./actions/classifier-deep/apply/fetch-sources
with:
# slightly overlapping to protect against issues slipping through the cracks if a run is delayed
from: 40
from: 80
until: 5
configPath: classifier
blobContainerName: vscode-issue-classifier

View file

@ -45,7 +45,7 @@
"minimist": "^1.2.3",
"request": "^2.85.0",
"terser": "4.3.8",
"typescript": "^4.0.0-dev.20200803",
"typescript": "^4.0.1-rc",
"vsce": "1.48.0",
"vscode-telemetry-extractor": "^1.6.0",
"xml2js": "^0.4.17"

View file

@ -2535,10 +2535,10 @@ typescript@^3.0.1:
resolved "https://registry.yarnpkg.com/typescript/-/typescript-3.5.3.tgz#c830f657f93f1ea846819e929092f5fe5983e977"
integrity sha512-ACzBtm/PhXBDId6a6sDJfroT2pOWt/oOnk4/dElG5G33ZL776N3Y6/6bKZJBFpd+b05F3Ct9qDjMeJmRWtE2/g==
typescript@^4.0.0-dev.20200803:
version "4.0.0-dev.20200803"
resolved "https://registry.yarnpkg.com/typescript/-/typescript-4.0.0-dev.20200803.tgz#ea8b0e9fb2ee3085598ff200c8568f04f4cbb2ba"
integrity sha512-f/jDkFqCs0gbUd5MCUijO9u3AOMx1x1HdRDDHSidlc6uPVEkRduxjeTFhIXbGutO7ivzv+aC2sxH+1FQwsyBcg==
typescript@^4.0.1-rc:
version "4.0.1-rc"
resolved "https://registry.yarnpkg.com/typescript/-/typescript-4.0.1-rc.tgz#8adc78223eae56fe71d906a5fa90c3543b07a677"
integrity sha512-TCkspT3dSKOykbzS3/WSK7pqU2h1d/lEO6i45Afm5Y3XNAEAo8YXTG3kHOQk/wFq/5uPyO1+X8rb/Q+g7UsxJw==
typical@^4.0.0:
version "4.0.0"

View file

@ -71,7 +71,7 @@ suite('HTML Folding', async () => {
/*13*/'</head>',
/*14*/'</html>',
];
await assertRanges(input, [r(0, 13), r(1, 12), r(2, 6), r(3, 6), r(8, 11), r(9, 11)]);
await assertRanges(input, [r(0, 13), r(1, 12), r(2, 6), r(3, 6), r(8, 11), r(9, 11), r(9, 11)]);
});
test('Embedded JavaScript - incomplete', async () => {

View file

@ -166,14 +166,9 @@
"when": "view == npm && viewItem == script",
"group": "inline"
},
{
"command": "npm.runScript",
"when": "view == npm && viewItem == debugScript",
"group": "inline"
},
{
"command": "npm.debugScript",
"when": "view == npm && viewItem == debugScript",
"when": "view == npm && viewItem == script",
"group": "inline"
},
{

View file

@ -3,18 +3,19 @@
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import { JSONVisitor, visit } from 'jsonc-parser';
import * as path from 'path';
import {
Event, EventEmitter, ExtensionContext, Task2 as Task,
TextDocument, ThemeIcon, TreeDataProvider, TreeItem, TreeItemCollapsibleState, Uri,
WorkspaceFolder, commands, window, workspace, tasks, Selection, TaskGroup
commands, Event, EventEmitter, ExtensionContext,
Selection, Task2 as Task,
TaskGroup, tasks, TextDocument, ThemeIcon, TreeDataProvider, TreeItem, TreeItemCollapsibleState, Uri,
window, workspace, WorkspaceFolder
} from 'vscode';
import { visit, JSONVisitor } from 'jsonc-parser';
import {
NpmTaskDefinition, getPackageJsonUriFromTask, getScripts,
isWorkspaceFolder, getTaskName, createTask, extractDebugArgFromScript, startDebugging, isAutoDetectionEnabled
} from './tasks';
import * as nls from 'vscode-nls';
import {
createTask, getTaskName, isAutoDetectionEnabled, isWorkspaceFolder, NpmTaskDefinition,
startDebugging
} from './tasks';
const localize = nls.loadMessageBundle();
@ -90,9 +91,6 @@ class NpmScript extends TreeItem {
}
};
this.contextValue = 'script';
if (task.group && task.group === TaskGroup.Rebuild) {
this.contextValue = 'debugScript';
}
this.package = packageJson;
this.task = task;
this.command = commandList[command];
@ -139,27 +137,8 @@ export class NpmScriptsTreeDataProvider implements TreeDataProvider<TreeItem> {
tasks.executeTask(script.task);
}
private extractDebugArg(scripts: any, task: Task): [string, number] | undefined {
return extractDebugArgFromScript(scripts[task.name]);
}
private async debugScript(script: NpmScript) {
let task = script.task;
let uri = getPackageJsonUriFromTask(task);
let scripts = await getScripts(uri!);
let debugArg = this.extractDebugArg(scripts, task);
if (!debugArg) {
let message = localize('noDebugOptions', 'Could not launch "{0}" for debugging because the scripts lacks a node debug option, e.g. "--inspect-brk".', task.name);
let learnMore = localize('learnMore', 'Learn More');
let ok = localize('ok', 'OK');
let result = await window.showErrorMessage(message, { modal: true }, ok, learnMore);
if (result === learnMore) {
commands.executeCommand('vscode.open', Uri.parse('https://code.visualstudio.com/docs/nodejs/nodejs-debugging#_launch-configuration-support-for-npm-and-other-tools'));
}
return;
}
startDebugging(task.name, debugArg[0], debugArg[1], script.getFolder());
startDebugging(script.task.name, script.getFolder());
}
private findScript(document: TextDocument, script?: NpmScript): number {

View file

@ -8,7 +8,7 @@ import {
workspace, tasks, Range, HoverProvider, Hover, Position, MarkdownString, Uri
} from 'vscode';
import {
createTask, startDebugging, findAllScriptRanges, extractDebugArgFromScript
createTask, startDebugging, findAllScriptRanges
} from './tasks';
import * as nls from 'vscode-nls';
@ -54,11 +54,7 @@ export class NpmScriptHoverProvider implements HoverProvider {
let contents: MarkdownString = new MarkdownString();
contents.isTrusted = true;
contents.appendMarkdown(this.createRunScriptMarkdown(key, document.uri));
let debugArgs = extractDebugArgFromScript(value[2]);
if (debugArgs) {
contents.appendMarkdown(this.createDebugScriptMarkdown(key, document.uri, debugArgs[0], debugArgs[1]));
}
contents.appendMarkdown(this.createDebugScriptMarkdown(key, document.uri));
hover = new Hover(contents);
}
});
@ -78,12 +74,10 @@ export class NpmScriptHoverProvider implements HoverProvider {
);
}
private createDebugScriptMarkdown(script: string, documentUri: Uri, protocol: string, port: number): string {
let args = {
private createDebugScriptMarkdown(script: string, documentUri: Uri): string {
const args = {
documentUri: documentUri,
script: script,
protocol: protocol,
port: port
};
return this.createMarkdownLink(
localize('debugScript', 'Debug Script'),
@ -116,11 +110,9 @@ export class NpmScriptHoverProvider implements HoverProvider {
public debugScriptFromHover(args: any) {
let script = args.script;
let documentUri = args.documentUri;
let protocol = args.protocol;
let port = args.port;
let folder = workspace.getWorkspaceFolder(documentUri);
if (folder) {
startDebugging(script, protocol, port, folder);
startDebugging(script, folder);
}
}
}

View file

@ -249,6 +249,8 @@ async function provideNpmScriptsForFolder(packageJsonUri: Uri): Promise<Task[]>
if (prePostScripts.has(each)) {
task.group = TaskGroup.Clean; // hack: use Clean group to tag pre/post scripts
}
// todo@connor4312: all scripts are now debuggable, what is a 'debug script'?
if (isDebugScript(scripts![each])) {
task.group = TaskGroup.Rebuild; // hack: use Rebuild group to tag debug scripts
}
@ -355,44 +357,16 @@ export function runScript(script: string, document: TextDocument) {
}
}
export function extractDebugArgFromScript(scriptValue: string): [string, number] | undefined {
// matches --debug, --debug=1234, --debug-brk, debug-brk=1234, --inspect,
// --inspect=1234, --inspect-brk, --inspect-brk=1234,
// --inspect=localhost:1245, --inspect=127.0.0.1:1234, --inspect=[aa:1:0:0:0]:1234, --inspect=:1234
let match = scriptValue.match(/--(inspect|debug)(-brk)?(=((\[[0-9a-fA-F:]*\]|[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+|[a-zA-Z0-9\.]*):)?(\d+))?/);
if (match) {
if (match[6]) {
return [match[1], parseInt(match[6])];
}
if (match[1] === 'inspect') {
return [match[1], 9229];
}
if (match[1] === 'debug') {
return [match[1], 5858];
}
}
return undefined;
}
export function startDebugging(scriptName: string, protocol: string, port: number, folder: WorkspaceFolder) {
let p = 'inspector';
if (protocol === 'debug') {
p = 'legacy';
}
let packageManager = getPackageManager(folder);
export function startDebugging(scriptName: string, folder: WorkspaceFolder) {
const config: DebugConfiguration = {
type: 'node',
type: 'pwa-node',
request: 'launch',
name: `Debug ${scriptName}`,
runtimeExecutable: packageManager,
runtimeExecutable: getPackageManager(folder),
runtimeArgs: [
'run',
scriptName,
],
port: port,
protocol: p
};
if (folder) {

View file

@ -3,7 +3,7 @@
"version": "0.0.1",
"description": "Dependencies shared by all extensions",
"dependencies": {
"typescript": "3.9.7"
"typescript": "^4.0.1-rc"
},
"scripts": {
"postinstall": "node ./postinstall"

View file

@ -9,14 +9,14 @@
"typescript.disableAutomaticTypeAcquisition": "Disables automatic type acquisition. Automatic type acquisition fetches `@types` packages from npm to improve IntelliSense for external libraries.",
"typescript.enablePromptUseWorkspaceTsdk": "Enables prompting of users to use the TypeScript version configured in the workspace for Intellisense.",
"typescript.tsserver.log": "Enables logging of the TS server to a file. This log can be used to diagnose TS Server issues. The log may contain file paths, source code, and other potentially sensitive information from your project.",
"typescript.tsserver.pluginPaths": "Additional paths to discover TypeScript Language Service plugins. Requires using TypeScript 2.3.0 or newer in the workspace.",
"typescript.tsserver.pluginPaths": "Additional paths to discover TypeScript Language Service plugins.",
"typescript.tsserver.pluginPaths.item": "Either an absolute or relative path. Relative path will be resolved against workspace folder(s).",
"typescript.tsserver.trace": "Enables tracing of messages sent to the TS server. This trace can be used to diagnose TS Server issues. The trace may contain file paths, source code, and other potentially sensitive information from your project.",
"typescript.validate.enable": "Enable/disable TypeScript validation.",
"typescript.format.enable": "Enable/disable default TypeScript formatter.",
"javascript.format.enable": "Enable/disable default JavaScript formatter.",
"format.insertSpaceAfterCommaDelimiter": "Defines space handling after a comma delimiter.",
"format.insertSpaceAfterConstructor": "Defines space handling after the constructor keyword. Requires using TypeScript 2.3.0 or newer in the workspace.",
"format.insertSpaceAfterConstructor": "Defines space handling after the constructor keyword.",
"format.insertSpaceAfterSemicolonInForStatements": "Defines space handling after a semicolon in a for statement.",
"format.insertSpaceBeforeAndAfterBinaryOperators": "Defines space handling after a binary operator.",
"format.insertSpaceAfterKeywordsInControlFlowStatements": "Defines space handling after keywords in a control flow statement.",
@ -24,10 +24,10 @@
"format.insertSpaceBeforeFunctionParenthesis": "Defines space handling before function argument parentheses.",
"format.insertSpaceAfterOpeningAndBeforeClosingNonemptyParenthesis": "Defines space handling after opening and before closing non-empty parenthesis.",
"format.insertSpaceAfterOpeningAndBeforeClosingNonemptyBrackets": "Defines space handling after opening and before closing non-empty brackets.",
"format.insertSpaceAfterOpeningAndBeforeClosingNonemptyBraces": "Defines space handling after opening and before closing non-empty braces. Requires using TypeScript 2.3.0 or newer in the workspace.",
"format.insertSpaceAfterOpeningAndBeforeClosingNonemptyBraces": "Defines space handling after opening and before closing non-empty braces.",
"format.insertSpaceAfterOpeningAndBeforeClosingTemplateStringBraces": "Defines space handling after opening and before closing template string braces.",
"format.insertSpaceAfterOpeningAndBeforeClosingJsxExpressionBraces": "Defines space handling after opening and before closing JSX expression braces.",
"format.insertSpaceAfterTypeAssertion": "Defines space handling after type assertions in TypeScript. Requires using TypeScript 2.4 or newer in the workspace.",
"format.insertSpaceAfterTypeAssertion": "Defines space handling after type assertions in TypeScript.",
"format.placeOpenBraceOnNewLineForFunctions": "Defines whether an open brace is put onto a new line for functions or not.",
"format.placeOpenBraceOnNewLineForControlBlocks": "Defines whether an open brace is put onto a new line for control blocks or not.",
"format.semicolons": "Defines handling of optional semicolons. Requires using TypeScript 3.7 or newer in the workspace.",
@ -45,8 +45,8 @@
"typescript.restartTsServer": "Restart TS server",
"typescript.selectTypeScriptVersion.title": "Select TypeScript Version...",
"typescript.reportStyleChecksAsWarnings": "Report style checks as warnings.",
"javascript.implicitProjectConfig.checkJs": "Enable/disable semantic checking of JavaScript files. Existing jsconfig.json or tsconfig.json files override this setting. Requires using TypeScript 2.3.1 or newer in the workspace.",
"typescript.npm": "Specifies the path to the npm executable used for Automatic Type Acquisition. Requires using TypeScript 2.3.4 or newer in the workspace.",
"javascript.implicitProjectConfig.checkJs": "Enable/disable semantic checking of JavaScript files. Existing jsconfig.json or tsconfig.json files override this setting.",
"typescript.npm": "Specifies the path to the npm executable used for Automatic Type Acquisition.",
"typescript.check.npmIsInstalled": "Check if npm is installed for Automatic Type Acquisition.",
"configuration.suggest.names": "Enable/disable including unique names from the file in JavaScript suggestions. Note that name suggestions are always disabled in JavaScript code that is semantically checked using `@ts-check` or `checkJs`.",
"typescript.tsc.autoDetect": "Controls auto detection of tsc tasks.",
@ -60,13 +60,13 @@
"configuration.tsserver.useSeparateSyntaxServer": "Enable/disable spawning a separate TypeScript server that can more quickly respond to syntax related operations, such as calculating folding or computing document symbols. Requires using TypeScript 3.4.0 or newer in the workspace.",
"configuration.tsserver.maxTsServerMemory": "Set the maximum amount of memory (in MB) to allocate to the TypeScript server process",
"configuration.tsserver.experimental.enableProjectDiagnostics": "(Experimental) Enables project wide error reporting.",
"typescript.locale": "Sets the locale used to report JavaScript and TypeScript errors. Requires using TypeScript 2.6.0 or newer in the workspace. Default of `null` uses VS Code's locale.",
"javascript.implicitProjectConfig.experimentalDecorators": "Enable/disable `experimentalDecorators` for JavaScript files that are not part of a project. Existing jsconfig.json or tsconfig.json files override this setting. Requires using TypeScript 2.3.1 or newer in the workspace.",
"configuration.suggest.autoImports": "Enable/disable auto import suggestions. Requires using TypeScript 2.6.1 or newer in the workspace.",
"typescript.locale": "Sets the locale used to report JavaScript and TypeScript errors. Default of `null` uses VS Code's locale.",
"javascript.implicitProjectConfig.experimentalDecorators": "Enable/disable `experimentalDecorators` for JavaScript files that are not part of a project. Existing jsconfig.json or tsconfig.json files override this setting.",
"configuration.suggest.autoImports": "Enable/disable auto import suggestions.",
"taskDefinition.tsconfig.description": "The tsconfig file that defines the TS build.",
"javascript.suggestionActions.enabled": "Enable/disable suggestion diagnostics for JavaScript files in the editor. Requires using TypeScript 2.8 or newer in the workspace.",
"typescript.suggestionActions.enabled": "Enable/disable suggestion diagnostics for TypeScript files in the editor. Requires using TypeScript 2.8 or newer in the workspace.",
"typescript.preferences.quoteStyle": "Preferred quote style to use for quick fixes: `single` quotes, `double` quotes, or `auto` infer quote type from existing imports. Requires using TypeScript 2.9 or newer in the workspace.",
"javascript.suggestionActions.enabled": "Enable/disable suggestion diagnostics for JavaScript files in the editor.",
"typescript.suggestionActions.enabled": "Enable/disable suggestion diagnostics for TypeScript files in the editor.",
"typescript.preferences.quoteStyle": "Preferred quote style to use for quick fixes: `single` quotes, `double` quotes, or `auto` infer quote type from existing imports.",
"typescript.preferences.importModuleSpecifier": "Preferred path style for auto imports.",
"typescript.preferences.importModuleSpecifier.auto": "Automatically select import path style. Prefers using a relative import if `baseUrl` is configured and the relative path has fewer segments than the non-relative import.",
"typescript.preferences.importModuleSpecifier.relative": "Relative to the file location.",
@ -80,11 +80,11 @@
"typescript.preferences.includePackageJsonAutoImports.auto": "Search dependencies based on estimated performance impact.",
"typescript.preferences.includePackageJsonAutoImports.on": "Always search dependencies.",
"typescript.preferences.includePackageJsonAutoImports.off": "Never search dependencies.",
"typescript.updateImportsOnFileMove.enabled": "Enable/disable automatic updating of import paths when you rename or move a file in VS Code. Requires using TypeScript 2.9 or newer in the workspace.",
"typescript.updateImportsOnFileMove.enabled": "Enable/disable automatic updating of import paths when you rename or move a file in VS Code.",
"typescript.updateImportsOnFileMove.enabled.prompt": "Prompt on each rename.",
"typescript.updateImportsOnFileMove.enabled.always": "Always update paths automatically.",
"typescript.updateImportsOnFileMove.enabled.never": "Never rename paths and don't prompt.",
"typescript.autoClosingTags": "Enable/disable automatic closing of JSX tags. Requires using TypeScript 3.0 or newer in the workspace.",
"typescript.autoClosingTags": "Enable/disable automatic closing of JSX tags.",
"typescript.suggest.enabled": "Enabled/disable autocomplete suggestions.",
"configuration.surveys.enabled": "Enabled/disable occasional surveys that help us improve VS Code's JavaScript and TypeScript support.",
"configuration.suggest.completeJSDocs": "Enable/disable suggestion to complete JSDoc comments.",

View file

@ -345,7 +345,6 @@ class CompletionAcceptedCommand implements Command {
}
*/
this.telemetryReporter.logTelemetry('completions.accept', {
// @ts-expect-error - remove after TS 4.0 protocol update
isPackageJsonImport: item.tsEntry.isPackageJsonImport ? 'true' : undefined,
});
}
@ -540,7 +539,6 @@ class TypeScriptCompletionItemProvider implements vscode.CompletionItemProvider<
for (let entry of entries) {
if (!shouldExcludeCompletionEntry(entry, completionConfiguration)) {
items.push(new MyCompletionItem(position, document, entry, completionContext, metadata));
// @ts-expect-error - remove after TS 4.0 protocol update
includesPackageJsonImport = !!entry.isPackageJsonImport;
}
}
@ -643,7 +641,11 @@ class TypeScriptCompletionItemProvider implements vscode.CompletionItemProvider<
const { snippet, parameterCount } = snippetForFunctionCall(item, detail.displayParts);
item.insertText = snippet;
if (parameterCount > 0) {
commands.push({ title: 'triggerParameterHints', command: 'editor.action.triggerParameterHints' });
//Fix for https://github.com/microsoft/vscode/issues/104059
//Don't show parameter hints if "editor.parameterHints.enabled": false
if (vscode.workspace.getConfiguration('editor.parameterHints').get('enabled')) {
commands.push({ title: 'triggerParameterHints', command: 'editor.action.triggerParameterHints' });
}
}
}
}

View file

@ -39,10 +39,10 @@ export default class TypeScriptDefinitionProvider extends DefinitionProviderBase
return response.body.definitions
.map((location): vscode.DefinitionLink => {
const target = typeConverters.Location.fromTextSpan(this.client.toResource(location.file), location);
if ((location as any).contextStart) {
if (location.contextStart && location.contextEnd) {
return {
originSelectionRange: span,
targetRange: typeConverters.Range.fromLocations((location as any).contextStart, (location as any).contextEnd),
targetRange: typeConverters.Range.fromLocations(location.contextStart, location.contextEnd),
targetUri: target.uri,
targetSelectionRange: target.range,
};

View file

@ -164,11 +164,9 @@ export class TypeScriptServerSpawner {
let tsServerLogFile: string | undefined;
if (kind === TsServerProcessKind.Syntax) {
if (semver.gte(API.v400rc.fullVersionString, apiVersion.fullVersionString)) {
args.push('--serverMode');
args.push('partialSemantic');
}
else {
if (semver.gte(API.v401rc.fullVersionString, apiVersion.fullVersionString)) {
args.push('--serverMode', 'partialSemantic');
} else {
args.push('--syntaxOnly');
}
}

View file

@ -532,7 +532,6 @@ export default class TypeScriptServiceClient extends Disposable implements IType
preferences: {
providePrefixAndSuffixTextForRename: true,
allowRenameOfImportPath: true,
// @ts-expect-error, remove after 4.0 protocol update
includePackageJsonAutoImports: this._configuration.includePackageJsonAutoImports,
},
watchOptions

View file

@ -34,7 +34,7 @@ export default class API {
public static readonly v380 = API.fromSimpleString('3.8.0');
public static readonly v381 = API.fromSimpleString('3.8.1');
public static readonly v390 = API.fromSimpleString('3.9.0');
public static readonly v400rc = API.fromSimpleString('4.0.0-rc');
public static readonly v401rc = API.fromSimpleString('4.0.1-rc');
public static readonly v400 = API.fromSimpleString('4.0.0');
public static fromVersionString(versionString: string): API {

View file

@ -66,7 +66,7 @@ export class TypeScriptServiceConfiguration {
public readonly maxTsServerMemory: number;
public readonly enablePromptUseWorkspaceTsdk: boolean;
public readonly watchOptions: protocol.WatchOptions | undefined;
public readonly includePackageJsonAutoImports: string | undefined;
public readonly includePackageJsonAutoImports: 'auto' | 'on' | 'off' | undefined;
public static loadFromWorkspace(): TypeScriptServiceConfiguration {
return new TypeScriptServiceConfiguration();
@ -181,8 +181,8 @@ export class TypeScriptServiceConfiguration {
return configuration.get<protocol.WatchOptions>('typescript.tsserver.watchOptions');
}
private static readIncludePackageJsonAutoImports(configuration: vscode.WorkspaceConfiguration): string | undefined {
return configuration.get<string>('typescript.preferences.includePackageJsonAutoImports');
private static readIncludePackageJsonAutoImports(configuration: vscode.WorkspaceConfiguration): 'auto' | 'on' | 'off' | undefined {
return configuration.get<'auto' | 'on' | 'off'>('typescript.preferences.includePackageJsonAutoImports');
}
private static readMaxTsServerMemory(configuration: vscode.WorkspaceConfiguration): number {

View file

@ -2,7 +2,7 @@
# yarn lockfile v1
typescript@3.9.7:
version "3.9.7"
resolved "https://registry.yarnpkg.com/typescript/-/typescript-3.9.7.tgz#98d600a5ebdc38f40cb277522f12dc800e9e25fa"
integrity sha512-BLbiRkiBzAwsjut4x/dsibSTB6yWpwT5qWmC2OfuCg3GgVQCSgMs4vEctYPhsaGtd0AeuuHMkjZ2h2WG8MSzRw==
typescript@^4.0.1-rc:
version "4.0.1-rc"
resolved "https://registry.yarnpkg.com/typescript/-/typescript-4.0.1-rc.tgz#8adc78223eae56fe71d906a5fa90c3543b07a677"
integrity sha512-TCkspT3dSKOykbzS3/WSK7pqU2h1d/lEO6i45Afm5Y3XNAEAo8YXTG3kHOQk/wFq/5uPyO1+X8rb/Q+g7UsxJw==

View file

@ -164,7 +164,7 @@
"source-map": "^0.4.4",
"style-loader": "^1.0.0",
"ts-loader": "^4.4.2",
"typescript": "^4.0.0-dev.20200803",
"typescript": "^4.0.1-rc",
"typescript-formatter": "7.1.0",
"underscore": "^1.8.2",
"vinyl": "^2.0.0",
@ -191,4 +191,4 @@
"windows-mutex": "0.3.0",
"windows-process-tree": "0.2.4"
}
}
}

View file

@ -791,7 +791,12 @@ class SubmenuMenuActionViewItem extends BaseMenuActionViewItem {
private cleanupExistingSubmenu(force: boolean): void {
if (this.parentData.submenu && (force || (this.parentData.submenu !== this.mysubmenu))) {
this.parentData.submenu.dispose();
// disposal may throw if the submenu has already been removed
try {
this.parentData.submenu.dispose();
} catch { }
this.parentData.submenu = undefined;
this.updateAriaExpanded('false');
if (this.submenuContainer) {

View file

@ -215,8 +215,7 @@ export class SelectBoxList extends Disposable implements ISelectBoxDelegate, ILi
// Intercept keyboard handling
// React on KEY_UP since the actionBar also reacts on KEY_UP so that appropriate events get canceled
this._register(dom.addDisposableListener(this.selectElement, dom.EventType.KEY_UP, (e: KeyboardEvent) => {
this._register(dom.addDisposableListener(this.selectElement, dom.EventType.KEY_DOWN, (e: KeyboardEvent) => {
const event = new StandardKeyboardEvent(e);
let showDropDown = false;
@ -233,7 +232,7 @@ export class SelectBoxList extends Disposable implements ISelectBoxDelegate, ILi
if (showDropDown) {
this.showSelectDropDown();
dom.EventHelper.stop(e, true);
dom.EventHelper.stop(e);
}
}));
}

View file

@ -1282,6 +1282,10 @@ class EditorEmptySelectionClipboard extends EditorBooleanOption<EditorOption.emp
* Configuration options for editor find widget
*/
export interface IEditorFindOptions {
/**
* Controls whether the cursor should move to find matches while typing.
*/
cursorMoveOnType?: boolean;
/**
* Controls if we seed search string in the Find Widget with editor selection.
*/
@ -1311,6 +1315,7 @@ class EditorFind extends BaseEditorOption<EditorOption.find, EditorFindOptions>
constructor() {
const defaults: EditorFindOptions = {
cursorMoveOnType: true,
seedSearchStringFromSelection: true,
autoFindInSelection: 'never',
globalFindClipboard: false,
@ -1320,6 +1325,11 @@ class EditorFind extends BaseEditorOption<EditorOption.find, EditorFindOptions>
super(
EditorOption.find, 'find', defaults,
{
'editor.find.cursorMoveOnType': {
type: 'boolean',
default: defaults.cursorMoveOnType,
description: nls.localize('find.cursorMoveOnType', "Controls whether the cursor should jump to find matches while typing.")
},
'editor.find.seedSearchStringFromSelection': {
type: 'boolean',
default: defaults.seedSearchStringFromSelection,
@ -1363,6 +1373,7 @@ class EditorFind extends BaseEditorOption<EditorOption.find, EditorFindOptions>
}
const input = _input as IEditorFindOptions;
return {
cursorMoveOnType: EditorBooleanOption.boolean(input.cursorMoveOnType, this.defaultValue.cursorMoveOnType),
seedSearchStringFromSelection: EditorBooleanOption.boolean(input.seedSearchStringFromSelection, this.defaultValue.seedSearchStringFromSelection),
autoFindInSelection: typeof _input.autoFindInSelection === 'boolean'
? (_input.autoFindInSelection ? 'always' : 'never')

View file

@ -205,7 +205,7 @@ export class FindModelBoundToEditorModel {
undefined
);
if (moveCursor) {
if (moveCursor && this._editor.getOption(EditorOption.find).cursorMoveOnType) {
this._moveToNextMatch(this._decorations.getStartPosition());
}
}

View file

@ -25,7 +25,7 @@ import { KeybindingWeight } from 'vs/platform/keybinding/common/keybindingsRegis
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
import { onUnexpectedError } from 'vs/base/common/errors';
import { EditorOption } from 'vs/editor/common/config/editorOptions';
import { Progress } from 'vs/platform/progress/common/progress';
import { Progress, IEditorProgressService } from 'vs/platform/progress/common/progress';
class FormatOnType implements IEditorContribution {
@ -231,7 +231,11 @@ class FormatDocumentAction extends EditorAction {
async run(accessor: ServicesAccessor, editor: ICodeEditor): Promise<void> {
if (editor.hasModel()) {
const instaService = accessor.get(IInstantiationService);
await instaService.invokeFunction(formatDocumentWithSelectedProvider, editor, FormattingMode.Explicit, Progress.None, CancellationToken.None);
const progressService = accessor.get(IEditorProgressService);
await progressService.showWhile(
instaService.invokeFunction(formatDocumentWithSelectedProvider, editor, FormattingMode.Explicit, Progress.None, CancellationToken.None),
250
);
}
}
}
@ -267,7 +271,12 @@ class FormatSelectionAction extends EditorAction {
if (range.isEmpty()) {
range = new Range(range.startLineNumber, 1, range.startLineNumber, model.getLineMaxColumn(range.startLineNumber));
}
await instaService.invokeFunction(formatDocumentRangeWithSelectedProvider, editor, range, FormattingMode.Explicit, CancellationToken.None);
const progressService = accessor.get(IEditorProgressService);
await progressService.showWhile(
instaService.invokeFunction(formatDocumentRangeWithSelectedProvider, editor, range, FormattingMode.Explicit, CancellationToken.None),
250
);
}
}

View file

@ -11,7 +11,7 @@ import { SnippetParser, Variable, VariableResolver } from 'vs/editor/contrib/sni
import { TextModel } from 'vs/editor/common/model/textModel';
import { Workspace, toWorkspaceFolders, IWorkspace, IWorkspaceContextService, toWorkspaceFolder } from 'vs/platform/workspace/common/workspace';
import { ILabelService } from 'vs/platform/label/common/label';
import { mock } from 'vs/editor/contrib/suggest/test/suggestModel.test';
import { mock } from 'vs/base/test/common/mock';
import { createTextModel } from 'vs/editor/test/common/editorTestUtils';
suite('Snippet Variables Resolver', function () {

View file

@ -229,7 +229,7 @@ export class SuggestModel implements IDisposable {
if (supports) {
// keep existing items that where not computed by the
// supports/providers that want to trigger now
const items: CompletionItem[] | undefined = this._completionModel ? this._completionModel.adopt(supports) : undefined;
const items = this._completionModel?.adopt(supports);
this.trigger({ auto: true, shy: false, triggerCharacter: lastChar }, Boolean(this._completionModel), supports, items);
}
};
@ -556,6 +556,12 @@ export class SuggestModel implements IDisposable {
return;
}
if (ctx.leadingWord.word.length !== 0 && ctx.leadingWord.startColumn > this._context.leadingWord.startColumn) {
// started a new word while IntelliSense shows -> retrigger
this.trigger({ auto: this._context.auto, shy: false }, true);
return;
}
if (ctx.column > this._context.column && this._completionModel.incomplete.size > 0 && ctx.leadingWord.word.length !== 0) {
// typed -> moved cursor RIGHT & incomple model & still on a word -> retrigger
const { incomplete } = this._completionModel;

View file

@ -17,7 +17,7 @@ import { ISuggestMemoryService } from 'vs/editor/contrib/suggest/suggestMemory';
import { DisposableStore } from 'vs/base/common/lifecycle';
import { URI } from 'vs/base/common/uri';
import { IEditorWorkerService } from 'vs/editor/common/services/editorWorkerService';
import { mock } from 'vs/editor/contrib/suggest/test/suggestModel.test';
import { mock } from 'vs/base/test/common/mock';
import { Selection } from 'vs/editor/common/core/selection';
import { CompletionProviderRegistry, CompletionItemKind, CompletionItemInsertTextRule } from 'vs/editor/common/modes';
import { Event } from 'vs/base/common/event';

View file

@ -34,14 +34,7 @@ import { IKeybindingService } from 'vs/platform/keybinding/common/keybinding';
import { MockKeybindingService } from 'vs/platform/keybinding/test/common/mockKeybindingService';
import { createTextModel } from 'vs/editor/test/common/editorTestUtils';
import { IClipboardService } from 'vs/platform/clipboard/common/clipboardService';
export interface Ctor<T> {
new(): T;
}
export function mock<T>(): Ctor<T> {
return function () { } as any;
}
import { mock } from 'vs/base/test/common/mock';
function createMockEditor(model: TextModel): ITestCodeEditor {
@ -798,4 +791,68 @@ suite('SuggestModel - TriggerAndCancelOracle', function () {
});
});
test('Trigger (full) completions when (incomplete) completions are already active #99504', function () {
let countA = 0;
let countB = 0;
disposables.push(CompletionProviderRegistry.register({ scheme: 'test' }, {
provideCompletionItems(doc, pos) {
countA += 1;
return {
incomplete: false, // doesn't matter if incomplete or not
suggestions: [{
kind: CompletionItemKind.Class,
label: 'Z aaa',
insertText: 'Z aaa',
range: new Range(1, 1, pos.lineNumber, pos.column)
}],
};
}
}));
disposables.push(CompletionProviderRegistry.register({ scheme: 'test' }, {
provideCompletionItems(doc, pos) {
countB += 1;
return {
incomplete: false,
suggestions: [{
kind: CompletionItemKind.Folder,
label: 'aaa',
insertText: 'aaa',
range: getDefaultSuggestRange(doc, pos)
}],
};
},
}));
return withOracle(async (model, editor) => {
await assertEvent(model.onDidSuggest, () => {
editor.setValue('');
editor.setSelection(new Selection(1, 1, 1, 1));
editor.trigger('keyboard', Handler.Type, { text: 'Z' });
}, event => {
assert.equal(event.auto, true);
assert.equal(event.completionModel.items.length, 1);
assert.equal(event.completionModel.items[0].textLabel, 'Z aaa');
});
await assertEvent(model.onDidSuggest, () => {
// started another word: Z a|
// item should be: Z aaa, aaa
editor.trigger('keyboard', Handler.Type, { text: ' a' });
}, event => {
assert.equal(event.auto, true);
assert.equal(event.completionModel.items.length, 2);
assert.equal(event.completionModel.items[0].textLabel, 'Z aaa');
assert.equal(event.completionModel.items[1].textLabel, 'aaa');
assert.equal(countA, 2); // should we keep the suggestions from the "active" provider?
assert.equal(countB, 2);
});
});
});
});

View file

@ -5,7 +5,7 @@
import * as assert from 'assert';
import { EditorSimpleWorker } from 'vs/editor/common/services/editorSimpleWorker';
import { mock } from 'vs/editor/contrib/suggest/test/suggestModel.test';
import { mock } from 'vs/base/test/common/mock';
import { EditorWorkerHost, EditorWorkerServiceImpl } from 'vs/editor/common/services/editorWorkerServiceImpl';
import { IModelService } from 'vs/editor/common/services/modelService';
import { createTextModel } from 'vs/editor/test/common/editorTestUtils';

4
src/vs/monaco.d.ts vendored
View file

@ -3286,6 +3286,10 @@ declare namespace monaco.editor {
* Configuration options for editor find widget
*/
export interface IEditorFindOptions {
/**
* Controls whether the cursor should move to find matches while typing.
*/
cursorMoveOnType?: boolean;
/**
* Controls if we seed search string in the Find Widget with editor selection.
*/

67
src/vs/vscode.d.ts vendored
View file

@ -5420,6 +5420,66 @@ declare module 'vscode' {
dispose(): void;
}
/**
* Provides information on a line in a terminal in order to provide links for it.
*/
export interface TerminalLinkContext {
/**
* This is the text from the unwrapped line in the terminal.
*/
line: string;
/**
* The terminal the link belongs to.
*/
terminal: Terminal;
}
/**
* A provider that enables detection and handling of links within terminals.
*/
export interface TerminalLinkProvider<T extends TerminalLink = TerminalLink> {
/**
* Provide terminal links for the given context. Note that this can be called multiple times
* even before previous calls resolve, make sure to not share global objects (eg. `RegExp`)
* that could have problems when asynchronous usage may overlap.
* @param context Information about what links are being provided for.
* @param token A cancellation token.
* @return A list of terminal links for the given line.
*/
provideTerminalLinks(context: TerminalLinkContext, token: CancellationToken): ProviderResult<T[]>
/**
* Handle an activated terminal link.
* @param link The link to handle.
*/
handleTerminalLink(link: T): ProviderResult<void>;
}
/**
* A link on a terminal line.
*/
export interface TerminalLink {
/**
* The start index of the link on [TerminalLinkContext.line](#TerminalLinkContext.line].
*/
startIndex: number;
/**
* The length of the link on [TerminalLinkContext.line](#TerminalLinkContext.line]
*/
length: number;
/**
* The tooltip text when you hover over this link.
*
* If a tooltip is provided, is will be displayed in a string that includes instructions on
* how to trigger the link, such as `{0} (ctrl + click)`. The specific instructions vary
* depending on OS, user settings, and localization.
*/
tooltip?: string;
}
/**
* In a remote window the extension kind describes if an extension
* runs where the UI (window) runs or if an extension runs remotely.
@ -8184,6 +8244,13 @@ declare module 'vscode' {
readonly supportsMultipleEditorsPerDocument?: boolean;
}): Disposable;
/**
* Register provider that enables the detection and handling of links within the terminal.
* @param provider The provider that provides the terminal links.
* @return Disposable that unregisters the provider.
*/
export function registerTerminalLinkProvider(provider: TerminalLinkProvider): Disposable;
/**
* The currently active color theme as configured in the settings. The active
* theme can be changed via the `workbench.colorTheme` setting.

View file

@ -927,93 +927,6 @@ declare module 'vscode' {
//#endregion
//#region Terminal link handlers https://github.com/microsoft/vscode/issues/91606
export namespace window {
/**
* Register a [TerminalLinkHandler](#TerminalLinkHandler) that can be used to intercept and
* handle links that are activated within terminals.
* @param handler The link handler being registered.
* @return A disposable that unregisters the link handler.
*/
export function registerTerminalLinkHandler(handler: TerminalLinkHandler): Disposable;
}
/**
* Describes how to handle terminal links.
*/
export interface TerminalLinkHandler {
/**
* Handles a link that is activated within the terminal.
*
* @param terminal The terminal the link was activated on.
* @param link The text of the link activated.
* @return Whether the link was handled, if the link was handled this link will not be
* considered by any other extension or by the default built-in link handler.
*/
handleLink(terminal: Terminal, link: string): ProviderResult<boolean>;
}
//#endregion
//#region Terminal link provider https://github.com/microsoft/vscode/issues/91606
export namespace window {
export function registerTerminalLinkProvider(provider: TerminalLinkProvider): Disposable;
}
export interface TerminalLinkContext {
/**
* This is the text from the unwrapped line in the terminal.
*/
line: string;
/**
* The terminal the link belongs to.
*/
terminal: Terminal;
}
export interface TerminalLinkProvider<T extends TerminalLink = TerminalLink> {
/**
* Provide terminal links for the given context. Note that this can be called multiple times
* even before previous calls resolve, make sure to not share global objects (eg. `RegExp`)
* that could have problems when asynchronous usage may overlap.
* @param context Information about what links are being provided for.
* @param token A cancellation token.
* @return A list of terminal links for the given line.
*/
provideTerminalLinks(context: TerminalLinkContext, token: CancellationToken): ProviderResult<T[]>
/**
* Handle an activated terminal link.
*/
handleTerminalLink(link: T): ProviderResult<void>;
}
export interface TerminalLink {
/**
* The start index of the link on [TerminalLinkContext.line](#TerminalLinkContext.line].
*/
startIndex: number;
/**
* The length of the link on [TerminalLinkContext.line](#TerminalLinkContext.line]
*/
length: number;
/**
* The tooltip text when you hover over this link.
*
* If a tooltip is provided, is will be displayed in a string that includes instructions on
* how to trigger the link, such as `{0} (ctrl + click)`. The specific instructions vary
* depending on OS, user settings, and localization.
*/
tooltip?: string;
}
//#endregion
//#region @jrieken -> exclusive document filters
export interface DocumentFilter {

View file

@ -21,6 +21,7 @@ import { ExtensionIdentifier } from 'vs/platform/extensions/common/extensions';
import { IUndoRedoService } from 'vs/platform/undoRedo/common/undoRedo';
import { ITextModelService } from 'vs/editor/common/services/resolverService';
import { Emitter } from 'vs/base/common/event';
import { ILogService } from 'vs/platform/log/common/log';
export class MainThreadNotebookDocument extends Disposable {
private _textModel: NotebookTextModel;
@ -181,7 +182,8 @@ export class MainThreadNotebooks extends Disposable implements MainThreadNoteboo
@INotebookService private _notebookService: INotebookService,
@IConfigurationService private readonly configurationService: IConfigurationService,
@IEditorService private readonly editorService: IEditorService,
@IAccessibilityService private readonly accessibilityService: IAccessibilityService
@IAccessibilityService private readonly accessibilityService: IAccessibilityService,
@ILogService private readonly logService: ILogService
) {
super();
@ -472,10 +474,10 @@ export class MainThreadNotebooks extends Disposable implements MainThreadNoteboo
await this._proxy.$resolveNotebookEditor(viewType, uri, editorId);
},
executeNotebookByAttachedKernel: async (viewType: string, uri: URI) => {
return this.executeNotebookByAttachedKernel(viewType, uri);
return this.executeNotebookByAttachedKernel(viewType, uri, undefined);
},
cancelNotebookByAttachedKernel: async (viewType: string, uri: URI) => {
return this.cancelNotebookByAttachedKernel(viewType, uri);
return this.cancelNotebookByAttachedKernel(viewType, uri, undefined);
},
onDidReceiveMessage: (editorId: string, rendererType: string | undefined, message: unknown) => {
this._proxy.$onDidReceiveMessage(editorId, rendererType, message);
@ -484,10 +486,10 @@ export class MainThreadNotebooks extends Disposable implements MainThreadNoteboo
return this.removeNotebookTextModel(uri);
},
executeNotebookCell: async (uri: URI, handle: number) => {
return this._proxy.$executeNotebookByAttachedKernel(_viewType, uri, handle);
return this.executeNotebookByAttachedKernel(_viewType, uri, handle);
},
cancelNotebookCell: async (uri: URI, handle: number) => {
return this._proxy.$cancelNotebookByAttachedKernel(_viewType, uri, handle);
return this.cancelNotebookByAttachedKernel(_viewType, uri, handle);
},
save: async (uri: URI, token: CancellationToken) => {
return this._proxy.$saveNotebook(_viewType, uri, token);
@ -517,7 +519,7 @@ export class MainThreadNotebooks extends Disposable implements MainThreadNoteboo
}
async $registerNotebookKernel(extension: NotebookExtensionDescription, id: string, label: string, selectors: (string | IRelativePattern)[], preloads: UriComponents[]): Promise<void> {
const kernel = new MainThreadNotebookKernel(this._proxy, id, label, selectors, extension.id, URI.revive(extension.location), preloads.map(preload => URI.revive(preload)));
const kernel = new MainThreadNotebookKernel(this._proxy, id, label, selectors, extension.id, URI.revive(extension.location), preloads.map(preload => URI.revive(preload)), this.logService);
this._notebookKernels.set(id, kernel);
this._notebookService.registerNotebookKernel(kernel);
return;
@ -550,9 +552,11 @@ export class MainThreadNotebooks extends Disposable implements MainThreadNoteboo
return that._proxy.$resolveNotebookKernel(handle, editorId, uri, kernelId, token);
},
executeNotebook: (uri: URI, kernelId: string, cellHandle: number | undefined) => {
this.logService.debug('MainthreadNotebooks.registerNotebookKernelProvider#executeNotebook', uri.path, kernelId, cellHandle);
return that._proxy.$executeNotebookKernelFromProvider(handle, uri, kernelId, cellHandle);
},
cancelNotebook: (uri: URI, kernelId: string, cellHandle: number | undefined) => {
this.logService.debug('MainthreadNotebooks.registerNotebookKernelProvider#cancelNotebook', uri.path, kernelId, cellHandle);
return that._proxy.$cancelNotebookKernelFromProvider(handle, uri, kernelId, cellHandle);
},
});
@ -582,21 +586,25 @@ export class MainThreadNotebooks extends Disposable implements MainThreadNoteboo
}
async $updateNotebookLanguages(viewType: string, resource: UriComponents, languages: string[]): Promise<void> {
this.logService.debug('MainThreadNotebooks#updateNotebookLanguages', resource.path, languages);
const textModel = this._notebookService.getNotebookTextModel(URI.from(resource));
textModel?.updateLanguages(languages);
}
async $updateNotebookMetadata(viewType: string, resource: UriComponents, metadata: NotebookDocumentMetadata): Promise<void> {
this.logService.debug('MainThreadNotebooks#updateNotebookMetadata', resource.path, metadata);
const textModel = this._notebookService.getNotebookTextModel(URI.from(resource));
textModel?.updateNotebookMetadata(metadata);
}
async $updateNotebookCellMetadata(viewType: string, resource: UriComponents, handle: number, metadata: NotebookCellMetadata): Promise<void> {
this.logService.debug('MainThreadNotebooks#updateNotebookCellMetadata', resource.path, handle, metadata);
const textModel = this._notebookService.getNotebookTextModel(URI.from(resource));
textModel?.updateNotebookCellMetadata(handle, metadata);
}
async $spliceNotebookCellOutputs(viewType: string, resource: UriComponents, cellHandle: number, splices: NotebookCellOutputsSplice[], renderers: number[]): Promise<void> {
this.logService.debug('MainThreadNotebooks#spliceNotebookCellOutputs', resource.path, cellHandle);
const textModel = this._notebookService.getNotebookTextModel(URI.from(resource));
if (textModel) {
@ -605,12 +613,14 @@ export class MainThreadNotebooks extends Disposable implements MainThreadNoteboo
}
}
async executeNotebookByAttachedKernel(viewType: string, uri: URI): Promise<void> {
return this._proxy.$executeNotebookByAttachedKernel(viewType, uri, undefined);
async executeNotebookByAttachedKernel(viewType: string, uri: URI, handle: number | undefined): Promise<void> {
this.logService.debug('MainthreadNotebooks#executeNotebookByAttachedKernel', uri.path, handle);
return this._proxy.$executeNotebookByAttachedKernel(viewType, uri, handle);
}
async cancelNotebookByAttachedKernel(viewType: string, uri: URI): Promise<void> {
return this._proxy.$cancelNotebookByAttachedKernel(viewType, uri, undefined);
async cancelNotebookByAttachedKernel(viewType: string, uri: URI, handle: number | undefined): Promise<void> {
this.logService.debug('MainthreadNotebooks#cancelNotebookByAttachedKernel', uri.path, handle);
return this._proxy.$cancelNotebookByAttachedKernel(viewType, uri, handle);
}
async $postMessage(editorId: string, forRendererId: string | undefined, value: any): Promise<boolean> {
@ -649,11 +659,13 @@ export class MainThreadNotebookKernel implements INotebookKernelInfo {
readonly selectors: (string | IRelativePattern)[],
readonly extension: ExtensionIdentifier,
readonly extensionLocation: URI,
readonly preloads: URI[]
readonly preloads: URI[],
readonly logService: ILogService
) {
}
async executeNotebook(viewType: string, uri: URI, handle: number | undefined): Promise<void> {
this.logService.debug('MainThreadNotebookKernel#executeNotebook', uri.path, handle);
return this._proxy.$executeNotebook2(this.id, viewType, uri, handle);
}
}

View file

@ -9,7 +9,7 @@ import { ExtHostContext, ExtHostTerminalServiceShape, MainThreadTerminalServiceS
import { extHostNamedCustomer } from 'vs/workbench/api/common/extHostCustomers';
import { URI } from 'vs/base/common/uri';
import { StopWatch } from 'vs/base/common/stopwatch';
import { ITerminalInstanceService, ITerminalService, ITerminalInstance, ITerminalBeforeHandleLinkEvent, ITerminalExternalLinkProvider, ITerminalLink } from 'vs/workbench/contrib/terminal/browser/terminal';
import { ITerminalInstanceService, ITerminalService, ITerminalInstance, ITerminalExternalLinkProvider, ITerminalLink } from 'vs/workbench/contrib/terminal/browser/terminal';
import { IRemoteAgentService } from 'vs/workbench/services/remote/common/remoteAgentService';
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
import { TerminalDataBufferer } from 'vs/workbench/contrib/terminal/common/terminalDataBuffering';
@ -25,7 +25,6 @@ export class MainThreadTerminalService implements MainThreadTerminalServiceShape
private readonly _toDispose = new DisposableStore();
private readonly _terminalProcessProxies = new Map<number, ITerminalProcessExtHostProxy>();
private _dataEventTracker: TerminalDataEventTracker | undefined;
private _linkHandler: IDisposable | undefined;
/**
* A single shared terminal link provider for the exthost. When an ext registers a link
* provider, this is registered with the terminal on the renderer side and all links are
@ -95,7 +94,6 @@ export class MainThreadTerminalService implements MainThreadTerminalServiceShape
public dispose(): void {
this._toDispose.dispose();
this._linkHandler?.dispose();
this._linkProvider?.dispose();
// TODO@Daniel: Should all the previously created terminals be disposed
@ -166,16 +164,6 @@ export class MainThreadTerminalService implements MainThreadTerminalServiceShape
}
}
public $startHandlingLinks(): void {
this._linkHandler?.dispose();
this._linkHandler = this._terminalService.addLinkHandler(this._remoteAuthority || '', e => this._handleLink(e));
}
public $stopHandlingLinks(): void {
this._linkHandler?.dispose();
this._linkHandler = undefined;
}
public $startLinkProvider(): void {
this._linkProvider?.dispose();
this._linkProvider = this._terminalService.registerLinkProvider(new ExtensionTerminalLinkProvider(this._proxy));
@ -186,13 +174,6 @@ export class MainThreadTerminalService implements MainThreadTerminalServiceShape
this._linkProvider = undefined;
}
private async _handleLink(e: ITerminalBeforeHandleLinkEvent): Promise<boolean> {
if (!e.terminal) {
return false;
}
return this._proxy.$handleLink(e.terminal.id, e.link);
}
private _onActiveTerminalChanged(terminalId: number | null): void {
this._proxy.$acceptActiveTerminalChanged(terminalId);
}

View file

@ -137,7 +137,7 @@ export function createApiFactoryAndRegisterActors(accessor: ServicesAccessor): I
const extHostComment = rpcProtocol.set(ExtHostContext.ExtHostComments, new ExtHostComments(rpcProtocol, extHostCommands, extHostDocuments));
const extHostProgress = rpcProtocol.set(ExtHostContext.ExtHostProgress, new ExtHostProgress(rpcProtocol.getProxy(MainContext.MainThreadProgress)));
const extHostLabelService = rpcProtocol.set(ExtHostContext.ExtHosLabelService, new ExtHostLabelService(rpcProtocol));
const extHostNotebook = rpcProtocol.set(ExtHostContext.ExtHostNotebook, initData.uiKind === UIKind.Web ? new ExtHostNotebookController(rpcProtocol, extHostCommands, extHostDocumentsAndEditors, initData.environment) : new ExtHostNotebookController(rpcProtocol, extHostCommands, extHostDocumentsAndEditors, initData.environment, extensionStoragePaths));
const extHostNotebook = rpcProtocol.set(ExtHostContext.ExtHostNotebook, initData.uiKind === UIKind.Web ? new ExtHostNotebookController(rpcProtocol, extHostCommands, extHostDocumentsAndEditors, initData.environment, extHostLogService) : new ExtHostNotebookController(rpcProtocol, extHostCommands, extHostDocumentsAndEditors, initData.environment, extHostLogService, extensionStoragePaths));
const extHostTheming = rpcProtocol.set(ExtHostContext.ExtHostTheming, new ExtHostTheming(rpcProtocol));
const extHostAuthentication = rpcProtocol.set(ExtHostContext.ExtHostAuthentication, new ExtHostAuthentication(rpcProtocol));
const extHostTimeline = rpcProtocol.set(ExtHostContext.ExtHostTimeline, new ExtHostTimeline(rpcProtocol, extHostCommands));
@ -579,12 +579,7 @@ export function createApiFactoryAndRegisterActors(accessor: ServicesAccessor): I
}
return extHostTerminalService.createTerminal(nameOrOptions, shellPath, shellArgs);
},
registerTerminalLinkHandler(handler: vscode.TerminalLinkHandler): vscode.Disposable {
checkProposedApiEnabled(extension);
return extHostTerminalService.registerLinkHandler(handler);
},
registerTerminalLinkProvider(handler: vscode.TerminalLinkProvider): vscode.Disposable {
checkProposedApiEnabled(extension);
return extHostTerminalService.registerLinkProvider(handler);
},
registerTreeDataProvider(viewId: string, treeDataProvider: vscode.TreeDataProvider<any>): vscode.Disposable {

View file

@ -448,8 +448,6 @@ export interface MainThreadTerminalServiceShape extends IDisposable {
$show(terminalId: number, preserveFocus: boolean): void;
$startSendingDataEvents(): void;
$stopSendingDataEvents(): void;
$startHandlingLinks(): void;
$stopHandlingLinks(): void;
$startLinkProvider(): void;
$stopLinkProvider(): void;
$setEnvironmentVariableCollection(extensionIdentifier: string, persistent: boolean, collection: ISerializableEnvironmentVariableCollection | undefined): void;
@ -1434,7 +1432,6 @@ export interface ExtHostTerminalServiceShape {
$acceptWorkspacePermissionsChanged(isAllowed: boolean): void;
$getAvailableShells(): Promise<IShellDefinitionDto[]>;
$getDefaultShellAndArgs(useAutomationShell: boolean): Promise<IShellAndArgsDto>;
$handleLink(id: number, link: string): Promise<boolean>;
$provideLinks(id: number, line: string): Promise<ITerminalLinkDto[]>;
$activateLink(id: number, linkId: number): void;
$initEnvironmentVariableCollections(collections: [string, ISerializableEnvironmentVariableCollection][]): void;

View file

@ -15,6 +15,7 @@ import { URI, UriComponents } from 'vs/base/common/uri';
import * as UUID from 'vs/base/common/uuid';
import { IExtensionDescription } from 'vs/platform/extensions/common/extensions';
import { CellKind, ExtHostNotebookShape, IMainContext, IModelAddedData, INotebookDocumentsAndEditorsDelta, INotebookEditorPropertiesChangeData, MainContext, MainThreadNotebookShape, NotebookCellOutputsSplice } from 'vs/workbench/api/common/extHost.protocol';
import { ILogService } from 'vs/platform/log/common/log';
import { ExtHostCommands } from 'vs/workbench/api/common/extHostCommands';
import { ExtHostDocumentsAndEditors } from 'vs/workbench/api/common/extHostDocumentsAndEditors';
import { IExtensionStoragePaths } from 'vs/workbench/api/common/extHostStoragePaths';
@ -930,6 +931,7 @@ export class ExtHostNotebookController implements ExtHostNotebookShape, ExtHostN
commands: ExtHostCommands,
private _documentsAndEditors: ExtHostDocumentsAndEditors,
private readonly _webviewInitData: WebviewInitData,
private readonly logService: ILogService,
private readonly _extensionStoragePaths?: IExtensionStoragePaths,
) {
this._proxy = mainContext.getProxy(MainContext.MainThreadNotebook);
@ -1432,6 +1434,7 @@ export class ExtHostNotebookController implements ExtHostNotebookShape, ExtHostN
}
$acceptModelChanged(uriComponents: UriComponents, event: NotebookCellsChangedEvent): void {
const document = this._documents.get(URI.revive(uriComponents).toString());
if (document) {
@ -1448,6 +1451,7 @@ export class ExtHostNotebookController implements ExtHostNotebookShape, ExtHostN
}
$acceptEditorPropertiesChanged(uriComponents: UriComponents, data: INotebookEditorPropertiesChangeData): void {
this.logService.debug('ExtHostNotebook#$acceptEditorPropertiesChanged', uriComponents.path, data);
const editor = this._getEditorFromURI(uriComponents);
if (!editor) {

View file

@ -41,7 +41,6 @@ export interface IExtHostTerminalService extends ExtHostTerminalServiceShape {
attachPtyToTerminal(id: number, pty: vscode.Pseudoterminal): void;
getDefaultShell(useAutomationShell: boolean, configProvider: ExtHostConfigProvider): string;
getDefaultShellArgs(useAutomationShell: boolean, configProvider: ExtHostConfigProvider): string[] | string;
registerLinkHandler(handler: vscode.TerminalLinkHandler): vscode.Disposable;
registerLinkProvider(provider: vscode.TerminalLinkProvider): vscode.Disposable;
getEnvironmentVariableCollection(extension: IExtensionDescription, persistent?: boolean): vscode.EnvironmentVariableCollection;
}
@ -318,7 +317,6 @@ export abstract class BaseExtHostTerminalService implements IExtHostTerminalServ
protected _environmentVariableCollections: Map<string, EnvironmentVariableCollection> = new Map();
private readonly _bufferer: TerminalDataBufferer;
private readonly _linkHandlers: Set<vscode.TerminalLinkHandler> = new Set();
private readonly _linkProviders: Set<vscode.TerminalLinkProvider> = new Set();
private readonly _terminalLinkCache: Map<number, Map<number, ICachedLinkEntry>> = new Map();
private readonly _terminalLinkCancellationSource: Map<number, CancellationTokenSource> = new Map();
@ -559,19 +557,6 @@ export abstract class BaseExtHostTerminalService implements IExtHostTerminalServ
return id;
}
public registerLinkHandler(handler: vscode.TerminalLinkHandler): vscode.Disposable {
this._linkHandlers.add(handler);
if (this._linkHandlers.size === 1 && this._linkProviders.size === 0) {
this._proxy.$startHandlingLinks();
}
return new VSCodeDisposable(() => {
this._linkHandlers.delete(handler);
if (this._linkHandlers.size === 0 && this._linkProviders.size === 0) {
this._proxy.$stopHandlingLinks();
}
});
}
public registerLinkProvider(provider: vscode.TerminalLinkProvider): vscode.Disposable {
this._linkProviders.add(provider);
if (this._linkProviders.size === 1) {
@ -585,25 +570,6 @@ export abstract class BaseExtHostTerminalService implements IExtHostTerminalServ
});
}
public async $handleLink(id: number, link: string): Promise<boolean> {
const terminal = this._getTerminalById(id);
if (!terminal) {
return false;
}
// Call each handler synchronously so multiple handlers aren't triggered at once
const it = this._linkHandlers.values();
let next = it.next();
while (!next.done) {
const handled = await next.value.handleLink(terminal, link);
if (handled) {
return true;
}
next = it.next();
}
return false;
}
public async $provideLinks(terminalId: number, line: string): Promise<ITerminalLinkDto[]> {
const terminal = this._getTerminalById(terminalId);
if (!terminal) {

View file

@ -1527,7 +1527,16 @@ registerAction2(class extends Action2 {
const activeEditorContext = this.getActiveEditorContext(accessor);
if (activeEditorContext) {
activeEditorContext.notebookEditor.viewModel!.inspectLayout();
const viewModel = activeEditorContext.notebookEditor.viewModel!;
console.log('--- notebook ---');
console.log(viewModel.layoutInfo);
console.log('--- cells ---');
for (let i = 0; i < viewModel.length; i++) {
const cell = viewModel.viewCells[i] as CellViewModel;
console.log(`--- cell: ${cell.handle} ---`);
console.log(cell.layoutInfo);
}
}
}
});

View file

@ -259,7 +259,7 @@ export interface INotebookEditor extends IEditor {
/**
* Move a cell to a specific position
*/
moveCellToIdx(cell: ICellViewModel, index: number): Promise<ICellViewModel | null>;
moveCellsToIdx(index: number, length: number, toIdx: number): Promise<ICellViewModel | null>;
/**
* Focus the container of a cell (the monaco editor inside is not focused).

View file

@ -1263,7 +1263,7 @@ export class NotebookEditorWidget extends Disposable implements INotebookEditor
}
const newIdx = index + 2; // This is the adjustment for the index before the cell has been "removed" from its original index
return this._moveCellToIndex(index, newIdx);
return this._moveCellToIndex(index, 1, newIdx);
}
async moveCellUp(cell: ICellViewModel): Promise<ICellViewModel | null> {
@ -1277,7 +1277,7 @@ export class NotebookEditorWidget extends Disposable implements INotebookEditor
}
const newIdx = index - 1;
return this._moveCellToIndex(index, newIdx);
return this._moveCellToIndex(index, 1, newIdx);
}
async moveCell(cell: ICellViewModel, relativeToCell: ICellViewModel, direction: 'above' | 'below'): Promise<ICellViewModel | null> {
@ -1293,34 +1293,33 @@ export class NotebookEditorWidget extends Disposable implements INotebookEditor
const relativeToIndex = this._notebookViewModel!.getCellIndex(relativeToCell);
const newIdx = direction === 'above' ? relativeToIndex : relativeToIndex + 1;
return this._moveCellToIndex(originalIdx, newIdx);
return this._moveCellToIndex(originalIdx, 1, newIdx);
}
async moveCellToIdx(cell: ICellViewModel, index: number): Promise<ICellViewModel | null> {
async moveCellsToIdx(index: number, length: number, toIdx: number): Promise<ICellViewModel | null> {
if (!this._notebookViewModel!.metadata.editable) {
return null;
}
const originalIdx = this._notebookViewModel!.getCellIndex(cell);
return this._moveCellToIndex(originalIdx, index);
return this._moveCellToIndex(index, length, toIdx);
}
/**
* @param index The current index of the cell
* @param newIdx The desired index, in an index scheme for the state of the tree before the current cell has been "removed".
* @param desiredIndex The desired index, in an index scheme for the state of the tree before the current cell has been "removed".
* @example to move the cell from index 0 down one spot, call with (0, 2)
*/
private async _moveCellToIndex(index: number, newIdx: number): Promise<ICellViewModel | null> {
if (index < newIdx) {
private async _moveCellToIndex(index: number, length: number, desiredIndex: number): Promise<ICellViewModel | null> {
if (index < desiredIndex) {
// The cell is moving "down", it will free up one index spot and consume a new one
newIdx--;
desiredIndex -= length;
}
if (index === newIdx) {
if (index === desiredIndex) {
return null;
}
if (!this._notebookViewModel!.moveCellToIdx(index, newIdx, true)) {
if (!this._notebookViewModel!.moveCellToIdx(index, length, desiredIndex, true)) {
throw new Error('Notebook Editor move cell, index out of range');
}
@ -1330,7 +1329,7 @@ export class NotebookEditorWidget extends Disposable implements INotebookEditor
r(null);
}
const viewCell = this._notebookViewModel!.viewCells[newIdx];
const viewCell = this._notebookViewModel!.viewCells[desiredIndex];
this._list?.revealElementInView(viewCell);
r(viewCell);
});

View file

@ -398,6 +398,10 @@ export class NotebookCellList extends WorkbenchList<CellViewModel> implements ID
const viewIndexInfo = this.hiddenRangesPrefixSum.getIndexOf(modelIndex);
if (viewIndexInfo.remainder !== 0) {
if (modelIndex >= this.hiddenRangesPrefixSum.getTotalValue()) {
// it's already after the last hidden range
return modelIndex - (this.hiddenRangesPrefixSum.getTotalValue() - this.hiddenRangesPrefixSum.getCount());
}
return undefined;
} else {
return viewIndexInfo.index;
@ -413,6 +417,12 @@ export class NotebookCellList extends WorkbenchList<CellViewModel> implements ID
const viewIndexInfo = this.hiddenRangesPrefixSum.getIndexOf(modelIndex);
if (viewIndexInfo.remainder !== 0) {
if (modelIndex >= this.hiddenRangesPrefixSum.getTotalValue()) {
return modelIndex - (this.hiddenRangesPrefixSum.getTotalValue() - this.hiddenRangesPrefixSum.getCount());
}
}
return viewIndexInfo.index;
}

View file

@ -472,10 +472,6 @@ export class MarkdownCellRenderer extends AbstractCellRenderer implements IListR
templateData.currentEditor = undefined;
templateData.editorPart!.style.display = 'none';
templateData.cellContainer.innerHTML = '';
const renderedHTML = element.getHTML();
if (renderedHTML) {
templateData.cellContainer.appendChild(renderedHTML);
}
if (height === undefined) {
return;
@ -676,6 +672,7 @@ export class CellDragAndDropController extends Disposable {
}
let draggedCells: ICellViewModel[] = [draggedCell];
let draggedCellRange: [number, number] = [this.notebookEditor.viewModel!.getCellIndex(draggedCell), 1];
if (draggedCell.cellKind === CellKind.Markdown) {
const currCellIndex = this.notebookEditor.viewModel!.getCellIndex(draggedCell);
@ -684,6 +681,7 @@ export class CellDragAndDropController extends Disposable {
if (nextVisibleCellIndex > currCellIndex + 1) {
// folding ;)
draggedCells = this.notebookEditor.viewModel!.viewCells.slice(currCellIndex, nextVisibleCellIndex);
draggedCellRange = [currCellIndex, nextVisibleCellIndex - currCellIndex];
}
}
@ -703,7 +701,15 @@ export class CellDragAndDropController extends Disposable {
if (isCopy) {
this.copyCells(draggedCells, event.draggedOverCell, dropDirection);
} else {
this.moveCells(draggedCells, event.draggedOverCell, dropDirection);
const viewModel = this.notebookEditor.viewModel!;
let originalToIdx = viewModel.getCellIndex(event.draggedOverCell);
if (dropDirection === 'below') {
const relativeToIndex = viewModel.getCellIndex(event.draggedOverCell);
const newIdx = viewModel.getNextVisibleCellIndex(relativeToIndex);
originalToIdx = newIdx;
}
this.notebookEditor.moveCellsToIdx(draggedCellRange[0], draggedCellRange[1], originalToIdx);
}
}
@ -749,25 +755,6 @@ export class CellDragAndDropController extends Disposable {
}));
}
private async moveCells(draggedCells: ICellViewModel[], ontoCell: ICellViewModel, direction: 'above' | 'below') {
this.notebookEditor.textModel!.pushStackElement('Move Cells');
if (direction === 'above') {
for (let i = 0; i < draggedCells.length; i++) {
const relativeToIndex = this.notebookEditor!.viewModel!.getCellIndex(ontoCell);
const newIdx = relativeToIndex;
await this.notebookEditor.moveCellToIdx(draggedCells[i], newIdx);
}
} else {
for (let i = draggedCells.length - 1; i >= 0; i--) {
const relativeToIndex = this.notebookEditor!.viewModel!.getCellIndex(ontoCell);
const newIdx = relativeToIndex + 1;
await this.notebookEditor.moveCellToIdx(draggedCells[i], newIdx);
}
}
this.notebookEditor.textModel!.pushStackElement('Move Cells');
}
private copyCells(draggedCells: ICellViewModel[], ontoCell: ICellViewModel, direction: 'above' | 'below') {
this.notebookEditor.textModel!.pushStackElement('Copy Cells');
let firstNewCell: ICellViewModel | undefined = undefined;

View file

@ -349,16 +349,6 @@ export class NotebookViewModel extends Disposable implements EditorFoldingStateD
});
}
inspectLayout() {
console.log('--- notebook ---\n');
console.log(this.layoutInfo);
console.log('--- cells ---');
this.viewCells.forEach(cell => {
console.log(`--- cell: ${cell.handle} ---\n`);
console.log((cell as (CodeCellViewModel | MarkdownCellViewModel)).layoutInfo);
});
}
setFocus(focused: boolean) {
this._focused = focused;
}
@ -657,13 +647,21 @@ export class NotebookViewModel extends Disposable implements EditorFoldingStateD
this._notebook.deleteCell2(index, synchronous, pushUndoStop, this.selectionHandles, endSelections);
}
moveCellToIdx(index: number, newIdx: number, synchronous: boolean, pushedToUndoStack: boolean = true): boolean {
/**
*
* @param index
* @param length
* @param newIdx in an index scheme for the state of the tree after the current cell has been "removed"
* @param synchronous
* @param pushedToUndoStack
*/
moveCellToIdx(index: number, length: number, newIdx: number, synchronous: boolean, pushedToUndoStack: boolean = true): boolean {
const viewCell = this.viewCells[index] as CellViewModel;
if (!viewCell) {
return false;
}
this._notebook.moveCellToIdx2(index, newIdx, synchronous, pushedToUndoStack, undefined, [viewCell.handle]);
this._notebook.moveCellToIdx2(index, length, newIdx, synchronous, pushedToUndoStack, undefined, [viewCell.handle]);
return true;
}

View file

@ -13,7 +13,7 @@ import { NotebookCellTextModel } from 'vs/workbench/contrib/notebook/common/mode
export interface ITextCellEditingDelegate {
insertCell?(index: number, cell: NotebookCellTextModel): void;
deleteCell?(index: number): void;
moveCell?(fromIndex: number, toIndex: number, beforeSelections: number[] | undefined, endSelections: number[] | undefined): void;
moveCell?(fromIndex: number, length: number, toIndex: number, beforeSelections: number[] | undefined, endSelections: number[] | undefined): void;
emitSelections(selections: number[]): void;
}
@ -100,6 +100,7 @@ export class MoveCellEdit implements IResourceUndoRedoElement {
constructor(
public resource: URI,
private fromIndex: number,
private length: number,
private toIndex: number,
private editingDelegate: ITextCellEditingDelegate,
private beforedSelections: number[] | undefined,
@ -112,7 +113,7 @@ export class MoveCellEdit implements IResourceUndoRedoElement {
throw new Error('Notebook Move Cell not implemented for Undo/Redo');
}
this.editingDelegate.moveCell(this.toIndex, this.fromIndex, this.endSelections, this.beforedSelections);
this.editingDelegate.moveCell(this.toIndex, this.length, this.fromIndex, this.endSelections, this.beforedSelections);
if (this.beforedSelections) {
this.editingDelegate.emitSelections(this.beforedSelections);
}
@ -123,7 +124,7 @@ export class MoveCellEdit implements IResourceUndoRedoElement {
throw new Error('Notebook Move Cell not implemented for Undo/Redo');
}
this.editingDelegate.moveCell(this.fromIndex, this.toIndex, this.beforedSelections, this.endSelections);
this.editingDelegate.moveCell(this.fromIndex, this.length, this.toIndex, this.beforedSelections, this.endSelections);
if (this.endSelections) {
this.editingDelegate.emitSelections(this.endSelections);
}

View file

@ -477,11 +477,11 @@ export class NotebookTextModel extends Disposable implements INotebookTextModel
}
}
moveCellToIdx(index: number, newIdx: number, emitToExtHost: boolean = true) {
moveCellToIdx(index: number, length: number, newIdx: number, emitToExtHost: boolean = true) {
this.assertIndex(index);
this.assertIndex(newIdx);
const cells = this.cells.splice(index, 1);
const cells = this.cells.splice(index, length);
this.cells.splice(newIdx, 0, ...cells);
this.setDirty(true);
this._onDidChangeContent.fire();
@ -618,22 +618,22 @@ export class NotebookTextModel extends Disposable implements INotebookTextModel
}
}
moveCellToIdx2(index: number, newIdx: number, synchronous: boolean, pushedToUndoStack: boolean, beforeSelections: number[] | undefined, endSelections: number[] | undefined): boolean {
const cell = this.cells[index];
moveCellToIdx2(index: number, length: number, newIdx: number, synchronous: boolean, pushedToUndoStack: boolean, beforeSelections: number[] | undefined, endSelections: number[] | undefined): boolean {
const cells = this.cells.slice(index, index + length);
if (pushedToUndoStack) {
this._operationManager.pushEditOperation(new MoveCellEdit(this.uri, index, newIdx, {
moveCell: (fromIndex: number, toIndex: number, beforeSelections: number[] | undefined, endSelections: number[] | undefined) => {
this.moveCellToIdx2(fromIndex, toIndex, true, false, beforeSelections, endSelections);
this._operationManager.pushEditOperation(new MoveCellEdit(this.uri, index, length, newIdx, {
moveCell: (fromIndex: number, length: number, toIndex: number, beforeSelections: number[] | undefined, endSelections: number[] | undefined) => {
this.moveCellToIdx2(fromIndex, length, toIndex, true, false, beforeSelections, endSelections);
},
emitSelections: this._emitSelectionsDelegate.bind(this)
}, beforeSelections, endSelections));
}
this.moveCellToIdx(index, newIdx);
this.moveCellToIdx(index, length, newIdx);
// todo, we can't emit this change as it will create a new view model and that will hold
// a new reference to the document, thus
this._onDidChangeCells.fire({ synchronous: synchronous, splices: [[index, 1, []]] });
this._onDidChangeCells.fire({ synchronous: synchronous, splices: [[newIdx, 0, [cell]]] });
this._onDidChangeCells.fire({ synchronous: synchronous, splices: [[index, length, []]] });
this._onDidChangeCells.fire({ synchronous: synchronous, splices: [[newIdx, 0, cells]] });
if (endSelections) {
this._emitSelections.fire(endSelections);
}

View file

@ -3,7 +3,6 @@
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import { isMacintosh } from 'vs/base/common/platform';
import { CopyAction, CutAction, PasteAction } from 'vs/editor/contrib/clipboard/clipboard';
import { ServicesAccessor } from 'vs/platform/instantiation/common/instantiation';
import { getActiveNotebookEditor } from 'vs/workbench/contrib/notebook/browser/contrib/coreActions';
@ -29,35 +28,34 @@ function getFocusedElectronBasedWebviewDelegate(accessor: ServicesAccessor): Ele
return;
}
if (isMacintosh) {
function withWebview(accessor: ServicesAccessor, f: (webviewe: ElectronWebviewBasedWebview) => void) {
const webview = getFocusedElectronBasedWebviewDelegate(accessor);
if (webview) {
f(webview);
return true;
}
return false;
function withWebview(accessor: ServicesAccessor, f: (webviewe: ElectronWebviewBasedWebview) => void) {
const webview = getFocusedElectronBasedWebviewDelegate(accessor);
if (webview) {
f(webview);
return true;
}
const PRIORITY = 100;
UndoCommand.addImplementation(PRIORITY, accessor => {
return withWebview(accessor, webview => webview.undo());
});
RedoCommand.addImplementation(PRIORITY, accessor => {
return withWebview(accessor, webview => webview.redo());
});
CopyAction?.addImplementation(PRIORITY, accessor => {
return withWebview(accessor, webview => webview.copy());
});
PasteAction?.addImplementation(PRIORITY, accessor => {
return withWebview(accessor, webview => webview.paste());
});
CutAction?.addImplementation(PRIORITY, accessor => {
return withWebview(accessor, webview => webview.cut());
});
return false;
}
const PRIORITY = 100;
UndoCommand.addImplementation(PRIORITY, accessor => {
return withWebview(accessor, webview => webview.undo());
});
RedoCommand.addImplementation(PRIORITY, accessor => {
return withWebview(accessor, webview => webview.redo());
});
CopyAction?.addImplementation(PRIORITY, accessor => {
return withWebview(accessor, webview => webview.copy());
});
PasteAction?.addImplementation(PRIORITY, accessor => {
return withWebview(accessor, webview => webview.paste());
});
CutAction?.addImplementation(PRIORITY, accessor => {
return withWebview(accessor, webview => webview.cut());
});

View file

@ -67,18 +67,18 @@ suite('NotebookViewModel', () => {
[['//c'], 'javascript', CellKind.Code, [], { editable: true }],
],
(editor, viewModel) => {
viewModel.moveCellToIdx(0, 0, false);
viewModel.moveCellToIdx(0, 1, 0, false);
// no-op
assert.equal(viewModel.viewCells[0].getText(), '//a');
assert.equal(viewModel.viewCells[1].getText(), '//b');
viewModel.moveCellToIdx(0, 1, false);
viewModel.moveCellToIdx(0, 1, 1, false);
// b, a, c
assert.equal(viewModel.viewCells[0].getText(), '//b');
assert.equal(viewModel.viewCells[1].getText(), '//a');
assert.equal(viewModel.viewCells[2].getText(), '//c');
viewModel.moveCellToIdx(0, 2, false);
viewModel.moveCellToIdx(0, 1, 2, false);
// a, c, b
assert.equal(viewModel.viewCells[0].getText(), '//a');
assert.equal(viewModel.viewCells[1].getText(), '//c');
@ -98,12 +98,12 @@ suite('NotebookViewModel', () => {
[['//c'], 'javascript', CellKind.Code, [], { editable: true }],
],
(editor, viewModel) => {
viewModel.moveCellToIdx(1, 0, false);
viewModel.moveCellToIdx(1, 1, 0, false);
// b, a, c
assert.equal(viewModel.viewCells[0].getText(), '//b');
assert.equal(viewModel.viewCells[1].getText(), '//a');
viewModel.moveCellToIdx(2, 0, false);
viewModel.moveCellToIdx(2, 1, 0, false);
// c, b, a
assert.equal(viewModel.viewCells[0].getText(), '//c');
assert.equal(viewModel.viewCells[1].getText(), '//b');

View file

@ -177,7 +177,7 @@ export class TestNotebookEditor implements INotebookEditor {
throw new Error('Method not implemented.');
}
moveCellToIdx(cell: ICellViewModel, index: number): Promise<ICellViewModel | null> {
async moveCellsToIdx(index: number, length: number, toIdx: number): Promise<ICellViewModel | null> {
throw new Error('Method not implemented.');
}

View file

@ -82,6 +82,7 @@ export class SearchEditor extends BaseTextEditor {
private messageDisposables: IDisposable[] = [];
private container: HTMLElement;
private searchModel: SearchModel;
private ongoingOperations: number = 0;
constructor(
@ITelemetryService telemetryService: ITelemetryService,
@ -493,7 +494,14 @@ export class SearchEditor extends BaseTextEditor {
}
this.searchOperation.start(500);
await this.searchModel.search(query).finally(() => this.searchOperation.stop());
this.ongoingOperations++;
const exit = await this.searchModel.search(query).finally(() => {
this.ongoingOperations--;
if (this.ongoingOperations === 0) {
this.searchOperation.stop();
}
});
const input = this.getInput();
if (!input ||
input !== startInput ||
@ -505,7 +513,7 @@ export class SearchEditor extends BaseTextEditor {
const controller = ReferencesController.get(this.searchResultEditor);
controller.closeWidget(false);
const labelFormatter = (uri: URI): string => this.labelService.getUriLabel(uri, { relative: true });
const results = serializeSearchResultForEditor(this.searchModel.searchResult, config.includes, config.excludes, config.contextLines, labelFormatter, sortOrder);
const results = serializeSearchResultForEditor(this.searchModel.searchResult, config.includes, config.excludes, config.contextLines, labelFormatter, sortOrder, exit?.limitHit);
const { body } = await input.getModels();
this.modelService.updateModel(body, results.text);
input.config = config;

View file

@ -208,7 +208,7 @@ export const extractSearchQueryFromLines = (lines: string[]): SearchConfiguratio
};
export const serializeSearchResultForEditor =
(searchResult: SearchResult, rawIncludePattern: string, rawExcludePattern: string, contextLines: number, labelFormatter: (x: URI) => string, sortOrder: SearchSortOrder): { matchRanges: Range[], text: string, config: Partial<SearchConfiguration> } => {
(searchResult: SearchResult, rawIncludePattern: string, rawExcludePattern: string, contextLines: number, labelFormatter: (x: URI) => string, sortOrder: SearchSortOrder, limitHit?: boolean): { matchRanges: Range[], text: string, config: Partial<SearchConfiguration> } => {
if (!searchResult.query) { throw Error('Internal Error: Expected query, got null'); }
const config = contentPatternToSearchConfiguration(searchResult.query, rawIncludePattern, rawExcludePattern, contextLines);
@ -219,7 +219,11 @@ export const serializeSearchResultForEditor =
searchResult.count()
? `${resultcount} - ${filecount}`
: localize('noResults', "No Results"),
''];
];
if (limitHit) {
info.push(localize('searchMaxResultsWarning', "The result set only contains a subset of all matches. Please be more specific in your search to narrow down the results."));
}
info.push('');
const matchComparer = (a: FileMatch | FolderMatch, b: FileMatch | FolderMatch) => searchMatchComparer(a, b, sortOrder);

View file

@ -21,10 +21,16 @@ export function convertLinkRangeToBuffer(lines: IBufferLine[], bufferWidth: numb
// Shift start range right for each wide character before the link
let startOffset = 0;
const startWrappedLineCount = Math.ceil(range.startColumn / bufferWidth);
for (let y = 0; y < startWrappedLineCount; y++) {
for (let y = 0; y < Math.min(startWrappedLineCount); y++) {
const lineLength = Math.min(bufferWidth, range.startColumn - y * bufferWidth);
let lineOffset = 0;
const line = lines[y];
// Sanity check for line, apparently this can happen but it's not clear under what
// circumstances this happens. Continue on, skipping the remainder of start offset if this
// happens to minimize impact.
if (!line) {
break;
}
for (let x = 0; x < Math.min(bufferWidth, lineLength + lineOffset); x++) {
const cell = line.getCell(x)!;
const width = cell.getWidth();

View file

@ -16,11 +16,9 @@ import { IFileService } from 'vs/platform/files/common/files';
import { Terminal, IViewportRange, ILinkProvider } from 'xterm';
import { REMOTE_HOST_SCHEME } from 'vs/platform/remote/common/remoteHosts';
import { posix, win32 } from 'vs/base/common/path';
import { ITerminalBeforeHandleLinkEvent, LINK_INTERCEPT_THRESHOLD, ITerminalExternalLinkProvider, ITerminalInstance } from 'vs/workbench/contrib/terminal/browser/terminal';
import { ITerminalExternalLinkProvider, ITerminalInstance } from 'vs/workbench/contrib/terminal/browser/terminal';
import { OperatingSystem, isMacintosh, OS } from 'vs/base/common/platform';
import { IMarkdownString, MarkdownString } from 'vs/base/common/htmlContent';
import { Emitter, Event } from 'vs/base/common/event';
import { ILogService } from 'vs/platform/log/common/log';
import { TerminalProtocolLinkProvider } from 'vs/workbench/contrib/terminal/browser/links/terminalProtocolLinkProvider';
import { TerminalValidatedLocalLinkProvider, lineAndColumnClause, unixLocalLinkClause, winLocalLinkClause, winDrivePrefix, winLineAndColumnMatchIndex, unixLineAndColumnMatchIndex, lineAndColumnClauseGroupCount } from 'vs/workbench/contrib/terminal/browser/links/terminalValidatedLocalLinkProvider';
import { TerminalWordLinkProvider } from 'vs/workbench/contrib/terminal/browser/links/terminalWordLinkProvider';
@ -44,24 +42,9 @@ interface IPath {
export class TerminalLinkManager extends DisposableStore {
private _widgetManager: TerminalWidgetManager | undefined;
private _processCwd: string | undefined;
private _hasBeforeHandleLinkListeners = false;
private _standardLinkProviders: ILinkProvider[] = [];
private _standardLinkProvidersDisposables: IDisposable[] = [];
protected static _LINK_INTERCEPT_THRESHOLD = LINK_INTERCEPT_THRESHOLD;
public static readonly LINK_INTERCEPT_THRESHOLD = TerminalLinkManager._LINK_INTERCEPT_THRESHOLD;
private readonly _onBeforeHandleLink = this.add(new Emitter<ITerminalBeforeHandleLinkEvent>({
onFirstListenerAdd: () => this._hasBeforeHandleLinkListeners = true,
onLastListenerRemove: () => this._hasBeforeHandleLinkListeners = false
}));
/**
* Allows intercepting links and handling them outside of the default link handler. When fired
* the listener has a set amount of time to handle the link or the default handler will fire.
* This was designed to only be handled by a single listener.
*/
public get onBeforeHandleLink(): Event<ITerminalBeforeHandleLinkEvent> { return this._onBeforeHandleLink.event; }
constructor(
private _xterm: Terminal,
private readonly _processManager: ITerminalProcessManager,
@ -69,14 +52,13 @@ export class TerminalLinkManager extends DisposableStore {
@IEditorService private readonly _editorService: IEditorService,
@IConfigurationService private readonly _configurationService: IConfigurationService,
@IFileService private readonly _fileService: IFileService,
@ILogService private readonly _logService: ILogService,
@IInstantiationService private readonly _instantiationService: IInstantiationService
) {
super();
// Protocol links
const wrappedActivateCallback = this._wrapLinkHandler((_, link) => this._handleProtocolLink(link));
const protocolProvider = this._instantiationService.createInstance(TerminalProtocolLinkProvider, this._xterm, wrappedActivateCallback, this._tooltipCallback2.bind(this));
const protocolProvider = this._instantiationService.createInstance(TerminalProtocolLinkProvider, this._xterm, wrappedActivateCallback, this._tooltipCallback.bind(this));
this._standardLinkProviders.push(protocolProvider);
// Validated local links
@ -87,19 +69,19 @@ export class TerminalLinkManager extends DisposableStore {
this._processManager.os || OS,
wrappedTextLinkActivateCallback,
this._wrapLinkHandler.bind(this),
this._tooltipCallback2.bind(this),
this._tooltipCallback.bind(this),
async (link, cb) => cb(await this._resolvePath(link)));
this._standardLinkProviders.push(validatedProvider);
}
// Word links
const wordProvider = this._instantiationService.createInstance(TerminalWordLinkProvider, this._xterm, this._wrapLinkHandler.bind(this), this._tooltipCallback2.bind(this));
const wordProvider = this._instantiationService.createInstance(TerminalWordLinkProvider, this._xterm, this._wrapLinkHandler.bind(this), this._tooltipCallback.bind(this));
this._standardLinkProviders.push(wordProvider);
this._registerStandardLinkProviders();
}
private _tooltipCallback2(link: TerminalLink, viewportRange: IViewportRange, modifierDownCallback?: () => void, modifierUpCallback?: () => void) {
private _tooltipCallback(link: TerminalLink, viewportRange: IViewportRange, modifierDownCallback?: () => void, modifierUpCallback?: () => void) {
if (!this._widgetManager) {
return;
}
@ -156,7 +138,7 @@ export class TerminalLinkManager extends DisposableStore {
}
public registerExternalLinkProvider(instance: ITerminalInstance, linkProvider: ITerminalExternalLinkProvider): IDisposable {
const wrappedLinkProvider = this._instantiationService.createInstance(TerminalExternalLinkProviderAdapter, this._xterm, instance, linkProvider, this._wrapLinkHandler.bind(this), this._tooltipCallback2.bind(this));
const wrappedLinkProvider = this._instantiationService.createInstance(TerminalExternalLinkProviderAdapter, this._xterm, instance, linkProvider, this._wrapLinkHandler.bind(this), this._tooltipCallback.bind(this));
const newLinkProvider = this._xterm.registerLinkProvider(wrappedLinkProvider);
// Re-register the standard link providers so they are a lower priority that the new one
this._registerStandardLinkProviders();
@ -173,38 +155,11 @@ export class TerminalLinkManager extends DisposableStore {
return;
}
// Allow the link to be intercepted if there are listeners
if (this._hasBeforeHandleLinkListeners) {
const wasHandled = await this._triggerBeforeHandleLinkListeners(link);
if (!wasHandled) {
handler(event, link);
}
return;
}
// Just call the handler if there is no before listener
handler(event, link);
};
}
private async _triggerBeforeHandleLinkListeners(link: string): Promise<boolean> {
return new Promise<boolean>(r => {
const timeoutId = setTimeout(() => {
canceled = true;
this._logService.error(`An extension intecepted a terminal link but it timed out after ${TerminalLinkManager.LINK_INTERCEPT_THRESHOLD / 1000} seconds`);
r(false);
}, TerminalLinkManager.LINK_INTERCEPT_THRESHOLD);
let canceled = false;
const resolve = (handled: boolean) => {
if (!canceled) {
clearTimeout(timeoutId);
r(handled);
}
};
this._onBeforeHandleLink.fire({ link, resolve });
});
}
protected get _localLinkRegex(): RegExp {
if (!this._processManager) {
throw new Error('Process manager is required');
@ -369,7 +324,6 @@ export class TerminalLinkManager extends DisposableStore {
* @param link Url link which may contain line and column number.
*/
public extractLineColumnInfo(link: string): LineColumnInfo {
const matches: string[] | null = this._localLinkRegex.exec(link);
const lineColumnInfo: LineColumnInfo = {
lineNumber: 1,

View file

@ -136,14 +136,6 @@ export interface ITerminalService {
findNext(): void;
findPrevious(): void;
/**
* Link handlers can be registered here to allow intercepting links clicked in the terminal.
* When a link is clicked, the link will be considered handled when the first interceptor
* resolves with true. It will be considered not handled when _all_ link handlers resolve with
* false, or 3 seconds have elapsed.
*/
addLinkHandler(key: string, callback: TerminalLinkHandlerCallback): IDisposable;
/**
* Registers a link provider that enables integrators to add links to the terminal.
* @param linkProvider When registered, the link provider is asked whenever a cell is hovered
@ -215,8 +207,6 @@ export enum WindowsShellType {
}
export type TerminalShellType = WindowsShellType | undefined;
export const LINK_INTERCEPT_THRESHOLD = 3000;
export interface ITerminalBeforeHandleLinkEvent {
terminal?: ITerminalInstance;
/** The text of the link */
@ -225,8 +215,6 @@ export interface ITerminalBeforeHandleLinkEvent {
resolve(wasHandled: boolean): void;
}
export type TerminalLinkHandlerCallback = (e: ITerminalBeforeHandleLinkEvent) => Promise<boolean>;
export interface ITerminalInstance {
/**
* The ID of the terminal instance, this is an arbitrary number only used to identify the
@ -289,11 +277,6 @@ export interface ITerminalInstance {
*/
onExit: Event<number | undefined>;
/**
* Attach a listener to intercept and handle link clicks in the terminal.
*/
onBeforeHandleLink: Event<ITerminalBeforeHandleLinkEvent>;
readonly exitCode: number | undefined;
readonly areLinksReady: boolean;

View file

@ -30,7 +30,7 @@ import { ansiColorIdentifiers, TERMINAL_BACKGROUND_COLOR, TERMINAL_CURSOR_BACKGR
import { TerminalConfigHelper } from 'vs/workbench/contrib/terminal/browser/terminalConfigHelper';
import { TerminalLinkManager } from 'vs/workbench/contrib/terminal/browser/links/terminalLinkManager';
import { IAccessibilityService } from 'vs/platform/accessibility/common/accessibility';
import { ITerminalInstanceService, ITerminalInstance, TerminalShellType, WindowsShellType, ITerminalBeforeHandleLinkEvent, ITerminalExternalLinkProvider } from 'vs/workbench/contrib/terminal/browser/terminal';
import { ITerminalInstanceService, ITerminalInstance, TerminalShellType, WindowsShellType, ITerminalExternalLinkProvider } from 'vs/workbench/contrib/terminal/browser/terminal';
import { TerminalProcessManager } from 'vs/workbench/contrib/terminal/browser/terminalProcessManager';
import { Terminal as XTermTerminal, IBuffer, ITerminalAddon } from 'xterm';
import { SearchAddon, ISearchOptions } from 'xterm-addon-search';
@ -164,8 +164,6 @@ export class TerminalInstance extends Disposable implements ITerminalInstance {
public get onMaximumDimensionsChanged(): Event<void> { return this._onMaximumDimensionsChanged.event; }
private readonly _onFocus = new Emitter<ITerminalInstance>();
public get onFocus(): Event<ITerminalInstance> { return this._onFocus.event; }
private readonly _onBeforeHandleLink = new Emitter<ITerminalBeforeHandleLinkEvent>();
public get onBeforeHandleLink(): Event<ITerminalBeforeHandleLinkEvent> { return this._onBeforeHandleLink.event; }
public constructor(
private readonly _terminalFocusContextKey: IContextKey<boolean>,
@ -419,10 +417,6 @@ export class TerminalInstance extends Disposable implements ITerminalInstance {
});
}
this._linkManager = this._instantiationService.createInstance(TerminalLinkManager, xterm, this._processManager!);
this._linkManager.onBeforeHandleLink(e => {
e.terminal = this;
this._onBeforeHandleLink.fire(e);
});
this._areLinksReady = true;
this._onLinksReady.fire(this);
});

View file

@ -14,7 +14,7 @@ import { TerminalTab } from 'vs/workbench/contrib/terminal/browser/terminalTab';
import { IInstantiationService, optional } from 'vs/platform/instantiation/common/instantiation';
import { IExtensionService } from 'vs/workbench/services/extensions/common/extensions';
import { TerminalInstance } from 'vs/workbench/contrib/terminal/browser/terminalInstance';
import { ITerminalService, ITerminalInstance, ITerminalTab, TerminalShellType, WindowsShellType, TerminalLinkHandlerCallback, LINK_INTERCEPT_THRESHOLD, ITerminalExternalLinkProvider } from 'vs/workbench/contrib/terminal/browser/terminal';
import { ITerminalService, ITerminalInstance, ITerminalTab, TerminalShellType, WindowsShellType, ITerminalExternalLinkProvider } from 'vs/workbench/contrib/terminal/browser/terminal';
import { IRemoteAgentService } from 'vs/workbench/services/remote/common/remoteAgentService';
import { TerminalConfigHelper } from 'vs/workbench/contrib/terminal/browser/terminalConfigHelper';
import { IQuickInputService, IQuickPickItem, IPickOptions } from 'vs/platform/quickinput/common/quickInput';
@ -50,7 +50,6 @@ export class TerminalService implements ITerminalService {
private _findState: FindReplaceState;
private _extHostsReady: { [authority: string]: IExtHostReadyEntry | undefined } = {};
private _activeTabIndex: number;
private _linkHandlers: { [key: string]: TerminalLinkHandlerCallback } = {};
private _linkProviders: Set<ITerminalExternalLinkProvider> = new Set();
private _linkProviderDisposables: Map<ITerminalExternalLinkProvider, IDisposable[]> = new Map();
@ -428,50 +427,6 @@ export class TerminalService implements ITerminalService {
instance.addDisposable(instance.onDimensionsChanged(() => this._onInstanceDimensionsChanged.fire(instance)));
instance.addDisposable(instance.onMaximumDimensionsChanged(() => this._onInstanceMaximumDimensionsChanged.fire(instance)));
instance.addDisposable(instance.onFocus(this._onActiveInstanceChanged.fire, this._onActiveInstanceChanged));
instance.addDisposable(instance.onBeforeHandleLink(async e => {
// No link handlers have been registered
const keys = Object.keys(this._linkHandlers);
if (keys.length === 0) {
e.resolve(false);
return;
}
// Fire each link interceptor and wait for either a true, all false or the cancel time
let resolved = false;
const promises: Promise<boolean>[] = [];
const timeout = setTimeout(() => {
resolved = true;
e.resolve(false);
}, LINK_INTERCEPT_THRESHOLD);
for (let i = 0; i < keys.length; i++) {
const p = this._linkHandlers[keys[i]](e);
p.then(handled => {
if (!resolved && handled) {
resolved = true;
clearTimeout(timeout);
e.resolve(true);
}
});
promises.push(p);
}
await Promise.all(promises);
if (!resolved) {
resolved = true;
clearTimeout(timeout);
e.resolve(false);
}
}));
}
public addLinkHandler(key: string, callback: TerminalLinkHandlerCallback): IDisposable {
this._linkHandlers[key] = callback;
return {
dispose: () => {
if (this._linkHandlers[key] === callback) {
delete this._linkHandlers[key];
}
}
};
}
public registerLinkProvider(linkProvider: ITerminalExternalLinkProvider): IDisposable {

View file

@ -23,6 +23,7 @@ export class TerminalWidgetManager implements IDisposable {
}
dispose(): void {
this.hideHovers();
if (this._container && this._container.parentElement) {
this._container.parentElement.removeChild(this._container);
this._container = undefined;

View file

@ -1,163 +0,0 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import * as assert from 'assert';
import { OperatingSystem } from 'vs/base/common/platform';
import { TerminalLinkManager, XtermLinkMatcherHandler } from 'vs/workbench/contrib/terminal/browser/links/terminalLinkManager';
import { Terminal as XtermTerminal } from 'xterm';
import { ITerminalInstanceService } from 'vs/workbench/contrib/terminal/browser/terminal';
import { Event } from 'vs/base/common/event';
import { TestInstantiationService } from 'vs/platform/instantiation/test/common/instantiationServiceMock';
import { TestPathService, TestEnvironmentService } from 'vs/workbench/test/browser/workbenchTestServices';
import { IPathService } from 'vs/workbench/services/path/common/pathService';
import { IEnvironmentService } from 'vs/platform/environment/common/environment';
import { TestConfigurationService } from 'vs/platform/configuration/test/common/testConfigurationService';
import { IConfigurationService } from 'vs/platform/configuration/common/configuration';
class TestTerminalLinkManager extends TerminalLinkManager {
public get localLinkRegex(): RegExp {
return this._localLinkRegex;
}
public preprocessPath(link: string): string | null {
return this._preprocessPath(link);
}
protected _isLinkActivationModifierDown(event: MouseEvent): boolean {
return true;
}
public wrapLinkHandler(handler: (link: string) => void): XtermLinkMatcherHandler {
TerminalLinkManager._LINK_INTERCEPT_THRESHOLD = 0;
return this._wrapLinkHandler((_, link) => handler(link));
}
}
class MockTerminalInstanceService implements ITerminalInstanceService {
onRequestDefaultShellAndArgs?: Event<any> | undefined;
getDefaultShellAndArgs(): Promise<{ shell: string; args: string | string[] | undefined; }> {
throw new Error('Method not implemented.');
}
declare readonly _serviceBrand: undefined;
getXtermConstructor(): Promise<any> {
throw new Error('Method not implemented.');
}
getXtermSearchConstructor(): Promise<any> {
throw new Error('Method not implemented.');
}
getXtermUnicode11Constructor(): Promise<any> {
throw new Error('Method not implemented.');
}
getXtermWebglConstructor(): Promise<any> {
throw new Error('Method not implemented.');
}
createWindowsShellHelper(): any {
throw new Error('Method not implemented.');
}
createTerminalProcess(): any {
throw new Error('Method not implemented.');
}
getMainProcessParentEnv(): any {
throw new Error('Method not implemented.');
}
}
suite('Workbench - TerminalLinkManager', () => {
let instantiationService: TestInstantiationService;
setup(async () => {
const configurationService = new TestConfigurationService();
await configurationService.setUserConfiguration('terminal', { integrated: { enableFileLinks: true } });
instantiationService = new TestInstantiationService();
instantiationService.stub(IEnvironmentService, TestEnvironmentService);
instantiationService.stub(IPathService, new TestPathService());
instantiationService.stub(ITerminalInstanceService, new MockTerminalInstanceService());
instantiationService.stub(IConfigurationService, configurationService);
});
suite('preprocessPath', () => {
test('Windows', () => {
const linkHandler: TestTerminalLinkManager = instantiationService.createInstance(TestTerminalLinkManager, new XtermTerminal() as any, {
os: OperatingSystem.Windows,
userHome: 'C:\\Users\\Me'
} as any);
linkHandler.processCwd = 'C:\\base';
assert.equal(linkHandler.preprocessPath('./src/file1'), 'C:\\base\\src\\file1');
assert.equal(linkHandler.preprocessPath('src\\file2'), 'C:\\base\\src\\file2');
assert.equal(linkHandler.preprocessPath('~/src/file3'), 'C:\\Users\\Me\\src\\file3');
assert.equal(linkHandler.preprocessPath('~\\src\\file4'), 'C:\\Users\\Me\\src\\file4');
assert.equal(linkHandler.preprocessPath('C:\\absolute\\path\\file5'), 'C:\\absolute\\path\\file5');
assert.equal(linkHandler.preprocessPath('\\\\?\\C:\\absolute\\path\\extended\\file6'), 'C:\\absolute\\path\\extended\\file6');
});
test('Windows - spaces', () => {
const linkHandler: TestTerminalLinkManager = instantiationService.createInstance(TestTerminalLinkManager, new XtermTerminal() as any, {
os: OperatingSystem.Windows,
userHome: 'C:\\Users\\M e'
} as any);
linkHandler.processCwd = 'C:\\base dir';
assert.equal(linkHandler.preprocessPath('./src/file1'), 'C:\\base dir\\src\\file1');
assert.equal(linkHandler.preprocessPath('src\\file2'), 'C:\\base dir\\src\\file2');
assert.equal(linkHandler.preprocessPath('~/src/file3'), 'C:\\Users\\M e\\src\\file3');
assert.equal(linkHandler.preprocessPath('~\\src\\file4'), 'C:\\Users\\M e\\src\\file4');
assert.equal(linkHandler.preprocessPath('C:\\abso lute\\path\\file5'), 'C:\\abso lute\\path\\file5');
});
test('Linux', () => {
const linkHandler: TestTerminalLinkManager = instantiationService.createInstance(TestTerminalLinkManager, new XtermTerminal() as any, {
os: OperatingSystem.Linux,
userHome: '/home/me'
} as any);
linkHandler.processCwd = '/base';
assert.equal(linkHandler.preprocessPath('./src/file1'), '/base/src/file1');
assert.equal(linkHandler.preprocessPath('src/file2'), '/base/src/file2');
assert.equal(linkHandler.preprocessPath('~/src/file3'), '/home/me/src/file3');
assert.equal(linkHandler.preprocessPath('/absolute/path/file4'), '/absolute/path/file4');
});
test('No Workspace', () => {
const linkHandler: TestTerminalLinkManager = instantiationService.createInstance(TestTerminalLinkManager, new XtermTerminal() as any, {
os: OperatingSystem.Linux,
userHome: '/home/me'
} as any);
assert.equal(linkHandler.preprocessPath('./src/file1'), null);
assert.equal(linkHandler.preprocessPath('src/file2'), null);
assert.equal(linkHandler.preprocessPath('~/src/file3'), '/home/me/src/file3');
assert.equal(linkHandler.preprocessPath('/absolute/path/file4'), '/absolute/path/file4');
});
});
suite('wrapLinkHandler', () => {
const nullMouseEvent: any = Object.freeze({ preventDefault: () => { } });
test('should allow intercepting of links with onBeforeHandleLink', async () => {
const linkHandler: TestTerminalLinkManager = instantiationService.createInstance(TestTerminalLinkManager, new XtermTerminal() as any, {
os: OperatingSystem.Linux,
userHome: ''
} as any);
linkHandler.onBeforeHandleLink(e => {
if (e.link === 'https://www.microsoft.com') {
intercepted = true;
e.resolve(true);
}
e.resolve(false);
});
const wrappedHandler = linkHandler.wrapLinkHandler(() => defaultHandled = true);
let defaultHandled = false;
let intercepted = false;
await wrappedHandler(nullMouseEvent, 'https://www.visualstudio.com');
assert.equal(intercepted, false);
assert.equal(defaultHandled, true);
defaultHandled = false;
intercepted = false;
await wrappedHandler(nullMouseEvent, 'https://www.microsoft.com');
assert.equal(intercepted, true);
assert.equal(defaultHandled, false);
});
});
});

View file

@ -44,7 +44,7 @@ suite('NotebookConcatDocument', function () {
});
extHostDocumentsAndEditors = new ExtHostDocumentsAndEditors(rpcProtocol, new NullLogService());
extHostDocuments = new ExtHostDocuments(rpcProtocol, extHostDocumentsAndEditors);
extHostNotebooks = new ExtHostNotebookController(rpcProtocol, new ExtHostCommands(rpcProtocol, new NullLogService()), extHostDocumentsAndEditors, { isExtensionDevelopmentDebug: false, webviewCspSource: '', webviewResourceRoot: '' });
extHostNotebooks = new ExtHostNotebookController(rpcProtocol, new ExtHostCommands(rpcProtocol, new NullLogService()), extHostDocumentsAndEditors, { isExtensionDevelopmentDebug: false, webviewCspSource: '', webviewResourceRoot: '' }, new NullLogService());
let reg = extHostNotebooks.registerNotebookContentProvider(nullExtensionDescription, 'test', new class extends mock<vscode.NotebookContentProvider>() {
// async openNotebook() { }
});

View file

@ -9369,10 +9369,10 @@ typescript@^2.6.2:
resolved "https://registry.yarnpkg.com/typescript/-/typescript-2.6.2.tgz#3c5b6fd7f6de0914269027f03c0946758f7673a4"
integrity sha1-PFtv1/beCRQmkCfwPAlGdY92c6Q=
typescript@^4.0.0-dev.20200803:
version "4.0.0-dev.20200803"
resolved "https://registry.yarnpkg.com/typescript/-/typescript-4.0.0-dev.20200803.tgz#ea8b0e9fb2ee3085598ff200c8568f04f4cbb2ba"
integrity sha512-f/jDkFqCs0gbUd5MCUijO9u3AOMx1x1HdRDDHSidlc6uPVEkRduxjeTFhIXbGutO7ivzv+aC2sxH+1FQwsyBcg==
typescript@^4.0.1-rc:
version "4.0.1-rc"
resolved "https://registry.yarnpkg.com/typescript/-/typescript-4.0.1-rc.tgz#8adc78223eae56fe71d906a5fa90c3543b07a677"
integrity sha512-TCkspT3dSKOykbzS3/WSK7pqU2h1d/lEO6i45Afm5Y3XNAEAo8YXTG3kHOQk/wFq/5uPyO1+X8rb/Q+g7UsxJw==
uc.micro@^1.0.1, uc.micro@^1.0.3:
version "1.0.3"