Merge branch 'main' into aiday/positioningInlineChat

This commit is contained in:
Aiday Marlen Kyzy
2023-06-13 11:27:01 +02:00
74 changed files with 2175 additions and 557 deletions
+1 -1
View File
@@ -1 +1 @@
2023-03-31T12:39:03.753Z
2023-06-12T12:55:48.130Z
+2
View File
@@ -37,6 +37,8 @@ fsevents/test/**
@vscode/windows-process-tree/binding.gyp
@vscode/windows-process-tree/build/**
@vscode/windows-process-tree/src/**
@vscode/windows-process-tree/tsconfig.json
@vscode/windows-process-tree/tslint.json
!@vscode/windows-process-tree/**/*.node
@vscode/windows-registry/binding.gyp
+6
View File
@@ -3,6 +3,12 @@
@vscode/windows-mutex/*.md
@vscode/windows-mutex/package.json
@vscode/windows-process-tree/lib/**
@vscode/windows-process-tree/**/*.node
@vscode/windows-process-tree/LICENSE
@vscode/windows-process-tree/package.json
@vscode/windows-process-tree/*.md
@vscode/windows-registry/dist/**
@vscode/windows-registry/**/*.node
@vscode/windows-registry/*.md
+6
View File
@@ -3,6 +3,12 @@
@vscode/windows-mutex/*.md
@vscode/windows-mutex/package.json
@vscode/windows-process-tree/lib/**
@vscode/windows-process-tree/**/*.node
@vscode/windows-process-tree/LICENSE
@vscode/windows-process-tree/package.json
@vscode/windows-process-tree/*.md
@vscode/windows-registry/dist/**
@vscode/windows-registry/**/*.node
@vscode/windows-registry/*.md
@@ -86,16 +86,10 @@ steps:
# TODO@joaomoreno TODO@deepak1556 this should be part of the base image
- ${{ if ne(parameters.VSCODE_QUALITY, 'oss') }}:
- script: |
if [ "$VSCODE_ARCH" = "x64" ]; then
OS=ubuntu
else
OS=debian
fi
sudo apt-get update && sudo apt-get install -y ca-certificates curl gnupg
sudo mkdir -m 0755 -p /etc/apt/keyrings
curl -fsSL https://download.docker.com/linux/$OS/gpg | sudo gpg --dearmor -o /etc/apt/keyrings/docker.gpg
echo "deb [arch="$(dpkg --print-architecture)" signed-by=/etc/apt/keyrings/docker.gpg] https://download.docker.com/linux/$OS "$(. /etc/os-release && echo "$VERSION_CODENAME")" stable" | sudo tee /etc/apt/sources.list.d/docker.list > /dev/null
curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo gpg --dearmor -o /etc/apt/keyrings/docker.gpg
echo "deb [arch="$(dpkg --print-architecture)" signed-by=/etc/apt/keyrings/docker.gpg] https://download.docker.com/linux/ubuntu "$(. /etc/os-release && echo "$VERSION_CODENAME")" stable" | sudo tee /etc/apt/sources.list.d/docker.list > /dev/null
sudo apt update && sudo apt install -y docker-ce-cli
displayName: Install Docker client
condition: and(succeeded(), ne(variables.NODE_MODULES_RESTORED, 'true'))
+2 -2
View File
@@ -144,11 +144,11 @@ resources:
endpoint: VSCodeHub
options: --user 0:0 --cap-add SYS_ADMIN
- container: vscode-arm64
image: vscodehub.azurecr.io/vscode-linux-build-agent:buster-arm64
image: vscodehub.azurecr.io/vscode-linux-build-agent:bionic-arm64
endpoint: VSCodeHub
options: --user 0:0 --cap-add SYS_ADMIN
- container: vscode-armhf
image: vscodehub.azurecr.io/vscode-linux-build-agent:buster-armhf
image: vscodehub.azurecr.io/vscode-linux-build-agent:bionic-armhf
endpoint: VSCodeHub
options: --user 0:0 --cap-add SYS_ADMIN
- container: snapcraft
File diff suppressed because one or more lines are too long
+8 -7
View File
@@ -17,7 +17,7 @@ import * as os from 'os';
import ts = require('typescript');
import * as File from 'vinyl';
import * as task from './task';
import { Mangler } from './mangleTypeScript';
import { Mangler } from './mangle/index';
import { RawSourceMap } from 'source-map';
const watch = require('./watch');
@@ -124,21 +124,22 @@ export function compileTask(src: string, out: string, build: boolean, options: {
// mangle: TypeScript to TypeScript
let mangleStream = es.through();
if (build && !options.disableMangle) {
let ts2tsMangler = new Mangler(compile.projectPath, (...data) => fancyLog(ansiColors.blue('[mangler]'), ...data));
let ts2tsMangler = new Mangler(compile.projectPath, (...data) => fancyLog(ansiColors.blue('[mangler]'), ...data), { mangleExports: true, manglePrivateFields: true });
const newContentsByFileName = ts2tsMangler.computeNewFileContents(new Set(['saveState']));
mangleStream = es.through(function write(data: File & { sourceMap?: RawSourceMap }) {
mangleStream = es.through(async function write(data: File & { sourceMap?: RawSourceMap }) {
type TypeScriptExt = typeof ts & { normalizePath(path: string): string };
const tsNormalPath = (<TypeScriptExt>ts).normalizePath(data.path);
const newContents = newContentsByFileName.get(tsNormalPath);
const newContents = (await newContentsByFileName).get(tsNormalPath);
if (newContents !== undefined) {
data.contents = Buffer.from(newContents.out);
data.sourceMap = newContents.sourceMap && JSON.parse(newContents.sourceMap);
}
this.push(data);
}, function end() {
this.push(null);
}, async function end() {
// free resources
newContentsByFileName.clear();
(await newContentsByFileName).clear();
this.push(null);
(<any>ts2tsMangler) = undefined;
});
}
+4
View File
@@ -521,6 +521,10 @@
{
"name": "vs/workbench/contrib/accessibility",
"project": "vscode-workbench"
},
{
"name": "vs/workbench/services/issue",
"project": "vscode-workbench"
}
]
}
File diff suppressed because one or more lines are too long
@@ -3,12 +3,15 @@
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import * as ts from 'typescript';
import * as path from 'path';
import * as fs from 'fs';
import * as path from 'path';
import { argv } from 'process';
import { Mapping, SourceMapGenerator } from 'source-map';
import * as ts from 'typescript';
import { pathToFileURL } from 'url';
import * as workerpool from 'workerpool';
import { StaticLanguageServiceHost } from './staticLanguageServiceHost';
const buildfile = require('../../../src/buildfile');
class ShortIdent {
@@ -17,21 +20,20 @@ class ShortIdent {
'import', 'in', 'instanceof', 'let', 'new', 'null', 'return', 'static', 'super', 'switch', 'this', 'throw',
'true', 'try', 'typeof', 'var', 'void', 'while', 'with', 'yield']);
private static _alphabet = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ'.split('');
private static _alphabet = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890$_'.split('');
private _value = 0;
private readonly _isNameTaken: (name: string) => boolean;
constructor(isNameTaken: (name: string) => boolean) {
this._isNameTaken = name => ShortIdent._keywords.has(name) || isNameTaken(name);
}
constructor(
private readonly prefix: string
) { }
next(): string {
const candidate = ShortIdent.convert(this._value);
next(isNameTaken?: (name: string) => boolean): string {
const candidate = this.prefix + ShortIdent.convert(this._value);
this._value++;
if (this._isNameTaken(candidate)) {
if (ShortIdent._keywords.has(candidate) || /^[_0-9]/.test(candidate) || isNameTaken?.(candidate)) {
// try again
return this.next();
return this.next(isNameTaken);
}
return candidate;
}
@@ -181,8 +183,7 @@ class ClassData {
data.replacements = new Map();
const identPool = new ShortIdent(name => {
const isNameTaken = (name: string) => {
// locally taken
if (data._isNameTaken(name)) {
return true;
@@ -212,11 +213,12 @@ class ClassData {
}
return false;
});
};
const identPool = new ShortIdent('');
for (const [name, info] of data.fields) {
if (ClassData._shouldMangle(info.type)) {
const shortName = identPool.next();
const shortName = identPool.next(isNameTaken);
data.replacements.set(name, shortName);
}
}
@@ -237,12 +239,11 @@ class ClassData {
}
}
}
if ((<any>this.node.getSourceFile()).identifiers instanceof Map) {
// taken by any other usage
if ((<any>this.node.getSourceFile()).identifiers.has(name)) {
return true;
}
if (isNameTakenInFile(this.node, name)) {
return true;
}
return false;
}
@@ -267,59 +268,122 @@ class ClassData {
}
}
class StaticLanguageServiceHost implements ts.LanguageServiceHost {
private readonly _cmdLine: ts.ParsedCommandLine;
private readonly _scriptSnapshots: Map<string, ts.IScriptSnapshot> = new Map();
constructor(readonly projectPath: string) {
const existingOptions: Partial<ts.CompilerOptions> = {};
const parsed = ts.readConfigFile(projectPath, ts.sys.readFile);
if (parsed.error) {
throw parsed.error;
}
this._cmdLine = ts.parseJsonConfigFileContent(parsed.config, ts.sys, path.dirname(projectPath), existingOptions);
if (this._cmdLine.errors.length > 0) {
throw parsed.error;
function isNameTakenInFile(node: ts.Node, name: string): boolean {
const identifiers = (<any>node.getSourceFile()).identifiers;
if (identifiers instanceof Map) {
if (identifiers.has(name)) {
return true;
}
}
getCompilationSettings(): ts.CompilerOptions {
return this._cmdLine.options;
return false;
}
const fileIdents = new class {
private readonly idents = new ShortIdent('$');
next() {
return this.idents.next();
}
getScriptFileNames(): string[] {
return this._cmdLine.fileNames;
};
const skippedExportMangledFiles = [
// Build
'css.build',
'nls.build',
// Monaco
'editorCommon',
'editorOptions',
'editorZoom',
'standaloneEditor',
'standaloneEnums',
'standaloneLanguages',
// Generated
'extensionsApiProposals',
// Module passed around as type
'pfs',
// entry points
...[
buildfile.entrypoint('vs/server/node/server.main', []),
buildfile.entrypoint('vs/workbench/workbench.desktop.main', []),
buildfile.base,
buildfile.workerExtensionHost,
buildfile.workerNotebook,
buildfile.workerLanguageDetection,
buildfile.workerLocalFileSearch,
buildfile.workerProfileAnalysis,
buildfile.workbenchDesktop,
buildfile.workbenchWeb,
buildfile.code
].flat().map(x => x.name),
];
const skippedExportMangledProjects = [
// Test projects
'vscode-api-tests',
// These projects use webpack to dynamically rewrite imports, which messes up our mangling
'configuration-editing',
'microsoft-authentication',
'github-authentication',
'html-language-features/server',
];
const skippedExportMangledSymbols = [
// Don't mangle extension entry points
'activate',
'deactivate',
];
class DeclarationData {
readonly replacementName: string;
constructor(
readonly fileName: string,
readonly node: ts.FunctionDeclaration | ts.ClassDeclaration | ts.EnumDeclaration | ts.VariableDeclaration,
private readonly service: ts.LanguageService,
) {
// Todo: generate replacement names based on usage count, with more used names getting shorter identifiers
this.replacementName = fileIdents.next();
}
getScriptVersion(_fileName: string): string {
return '1';
}
getProjectVersion(): string {
return '1';
}
getScriptSnapshot(fileName: string): ts.IScriptSnapshot | undefined {
let result: ts.IScriptSnapshot | undefined = this._scriptSnapshots.get(fileName);
if (result === undefined) {
const content = ts.sys.readFile(fileName);
if (content === undefined) {
return undefined;
get locations(): Iterable<{ fileName: string; offset: number }> {
if (ts.isVariableDeclaration(this.node)) {
// If the const aliases any types, we need to rename those too
const definitionResult = this.service.getDefinitionAndBoundSpan(this.fileName, this.node.name.getStart());
if (definitionResult?.definitions && definitionResult.definitions.length > 1) {
return definitionResult.definitions.map(x => ({ fileName: x.fileName, offset: x.textSpan.start }));
}
result = ts.ScriptSnapshot.fromString(content);
this._scriptSnapshots.set(fileName, result);
}
return result;
return [{
fileName: this.fileName,
offset: this.node.name!.getStart()
}];
}
getCurrentDirectory(): string {
return path.dirname(this.projectPath);
shouldMangle(newName: string): boolean {
const currentName = this.node.name!.getText();
if (currentName.startsWith('$') || skippedExportMangledSymbols.includes(currentName)) {
return false;
}
// New name is longer the existing one :'(
if (newName.length >= currentName.length) {
return false;
}
// Don't mangle functions we've explicitly opted out
if (this.node.getFullText().includes('@skipMangle')) {
return false;
}
return true;
}
getDefaultLibFileName(options: ts.CompilerOptions): string {
return ts.getDefaultLibFilePath(options);
}
directoryExists = ts.sys.directoryExists;
getDirectories = ts.sys.getDirectories;
fileExists = ts.sys.fileExists;
readFile = ts.sys.readFile;
readDirectory = ts.sys.readDirectory;
// this is necessary to make source references work.
realpath = ts.sys.realpath;
}
export interface MangleOutput {
@@ -339,26 +403,82 @@ export interface MangleOutput {
export class Mangler {
private readonly allClassDataByKey = new Map<string, ClassData>();
private readonly allExportedSymbols = new Set<DeclarationData>();
private readonly service: ts.LanguageService;
private readonly renameWorkerPool: workerpool.WorkerPool;
constructor(readonly projectPath: string, readonly log: typeof console.log = () => { }) {
constructor(
private readonly projectPath: string,
private readonly log: typeof console.log = () => { },
private readonly config: { readonly manglePrivateFields: boolean; readonly mangleExports: boolean },
) {
this.service = ts.createLanguageService(new StaticLanguageServiceHost(projectPath));
this.renameWorkerPool = workerpool.pool(path.join(__dirname, 'renameWorker.js'), {
maxWorkers: 2,
minWorkers: 'max'
});
}
computeNewFileContents(strictImplicitPublicHandling?: Set<string>): Map<string, MangleOutput> {
async computeNewFileContents(strictImplicitPublicHandling?: Set<string>): Promise<Map<string, MangleOutput>> {
// STEP: find all classes and their field info
// STEP:
// - Find all classes and their field info.
// - Find exported symbols.
const visit = (node: ts.Node): void => {
if (ts.isClassDeclaration(node) || ts.isClassExpression(node)) {
const anchor = node.name ?? node;
const key = `${node.getSourceFile().fileName}|${anchor.getStart()}`;
if (this.allClassDataByKey.has(key)) {
throw new Error('DUPE?');
if (this.config.manglePrivateFields) {
if (ts.isClassDeclaration(node) || ts.isClassExpression(node)) {
const anchor = node.name ?? node;
const key = `${node.getSourceFile().fileName}|${anchor.getStart()}`;
if (this.allClassDataByKey.has(key)) {
throw new Error('DUPE?');
}
this.allClassDataByKey.set(key, new ClassData(node.getSourceFile().fileName, node));
}
this.allClassDataByKey.set(key, new ClassData(node.getSourceFile().fileName, node));
}
if (this.config.mangleExports) {
// Find exported classes, functions, and vars
if (
(
// Exported class
ts.isClassDeclaration(node)
&& hasModifier(node, ts.SyntaxKind.ExportKeyword)
&& node.name
) || (
// Exported function
ts.isFunctionDeclaration(node)
&& ts.isSourceFile(node.parent)
&& hasModifier(node, ts.SyntaxKind.ExportKeyword)
&& node.name && node.body // On named function and not on the overload
) || (
// Exported variable
ts.isVariableDeclaration(node)
&& hasModifier(node.parent.parent, ts.SyntaxKind.ExportKeyword) // Variable statement is exported
&& ts.isSourceFile(node.parent.parent.parent)
)
// Disabled for now because we need to figure out how to handle
// enums that are used in monaco or extHost interfaces.
/* || (
// Exported enum
ts.isEnumDeclaration(node)
&& ts.isSourceFile(node.parent)
&& hasModifier(node, ts.SyntaxKind.ExportKeyword)
&& !hasModifier(node, ts.SyntaxKind.ConstKeyword) // Don't bother mangling const enums because these are inlined
&& node.name
*/
) {
if (isInAmbientContext(node)) {
return;
}
this.allExportedSymbols.add(new DeclarationData(node.getSourceFile().fileName, node, this.service));
}
}
ts.forEachChild(node, visit);
};
@@ -367,7 +487,7 @@ export class Mangler {
ts.forEachChild(file, visit);
}
}
this.log(`Done collecting classes: ${this.allClassDataByKey.size}`);
this.log(`Done collecting. Classes: ${this.allClassDataByKey.size}. Exported symbols: ${this.allExportedSymbols.size}`);
// STEP: connect sub and super-types
@@ -433,9 +553,11 @@ export class Mangler {
for (const data of this.allClassDataByKey.values()) {
ClassData.fillInReplacement(data);
}
this.log(`Done creating replacements`);
this.log(`Done creating class replacements`);
// STEP: prepare rename edits
this.log(`Starting prepare rename edits`);
type Edit = { newText: string; offset: number; length: number };
const editsByFile = new Map<string, Edit[]>();
@@ -447,9 +569,24 @@ export class Mangler {
edits.push(edit);
}
};
const appendRename = (newText: string, loc: ts.RenameLocation) => {
appendEdit(loc.fileName, {
newText: (loc.prefixText || '') + newText + (loc.suffixText || ''),
offset: loc.textSpan.start,
length: loc.textSpan.length
});
};
type RenameFn = (projectName: string, fileName: string, pos: number) => ts.RenameLocation[];
const renameResults: Array<Promise<{ readonly newName: string; readonly locations: readonly ts.RenameLocation[] }>> = [];
const queueRename = (fileName: string, pos: number, newName: string) => {
renameResults.push(Promise.resolve(this.renameWorkerPool.exec<RenameFn>('findRenameLocations', [this.projectPath, fileName, pos]))
.then((locations) => ({ newName, locations })));
};
for (const data of this.allClassDataByKey.values()) {
if (hasModifier(data.node, ts.SyntaxKind.DeclareKeyword)) {
continue;
}
@@ -469,18 +606,39 @@ export class Mangler {
parent = parent.parent;
}
const newText = data.lookupShortName(name);
const locations = this.service.findRenameLocations(data.fileName, info.pos, false, false, true) ?? [];
for (const loc of locations) {
appendEdit(loc.fileName, {
newText: (loc.prefixText || '') + newText + (loc.suffixText || ''),
offset: loc.textSpan.start,
length: loc.textSpan.length
});
}
const newName = data.lookupShortName(name);
queueRename(data.fileName, info.pos, newName);
}
}
for (const data of this.allExportedSymbols.values()) {
if (data.fileName.endsWith('.d.ts')
|| skippedExportMangledProjects.some(proj => data.fileName.includes(proj))
|| skippedExportMangledFiles.some(file => data.fileName.endsWith(file + '.ts'))
) {
continue;
}
if (!data.shouldMangle(data.replacementName)) {
continue;
}
const newText = data.replacementName;
for (const { fileName, offset } of data.locations) {
queueRename(fileName, offset, newText);
}
}
await Promise.all(renameResults).then((result) => {
for (const { newName, locations } of result) {
for (const loc of locations) {
appendRename(newName, loc);
}
}
});
await this.renameWorkerPool.terminate();
this.log(`Done preparing edits: ${editsByFile.size} files`);
// STEP: apply all rename edits (per file)
@@ -579,17 +737,32 @@ function hasModifier(node: ts.Node, kind: ts.SyntaxKind) {
return Boolean(modifiers?.find(mode => mode.kind === kind));
}
function isInAmbientContext(node: ts.Node): boolean {
for (let p = node.parent; p; p = p.parent) {
if (ts.isModuleDeclaration(p)) {
return true;
}
}
return false;
}
function normalize(path: string): string {
return path.replace(/\\/g, '/');
}
async function _run() {
const projectPath = path.join(__dirname, '../../src/tsconfig.json');
const projectBase = path.dirname(projectPath);
const root = path.join(__dirname, '..', '..', '..');
const projectBase = path.join(root, 'src');
const projectPath = path.join(projectBase, 'tsconfig.json');
const newProjectBase = path.join(path.dirname(projectBase), path.basename(projectBase) + '2');
for await (const [fileName, contents] of new Mangler(projectPath, console.log).computeNewFileContents(new Set(['saveState']))) {
fs.cpSync(projectBase, newProjectBase, { recursive: true });
const mangler = new Mangler(projectPath, console.log, {
mangleExports: true,
manglePrivateFields: true,
});
for (const [fileName, contents] of await mangler.computeNewFileContents(new Set(['saveState']))) {
const newFilePath = path.join(newProjectBase, path.relative(projectBase, fileName));
await fs.promises.mkdir(path.dirname(newFilePath), { recursive: true });
await fs.promises.writeFile(newFilePath, contents.out);
+20
View File
@@ -0,0 +1,20 @@
"use strict";
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
Object.defineProperty(exports, "__esModule", { value: true });
const ts = require("typescript");
const workerpool = require("workerpool");
const staticLanguageServiceHost_1 = require("./staticLanguageServiceHost");
let service; // = ts.createLanguageService(new StaticLanguageServiceHost(projectPath));
function findRenameLocations(projectPath, fileName, position) {
if (!service) {
service = ts.createLanguageService(new staticLanguageServiceHost_1.StaticLanguageServiceHost(projectPath));
}
return service.findRenameLocations(fileName, position, false, false, true) ?? [];
}
workerpool.worker({
findRenameLocations
});
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoicmVuYW1lV29ya2VyLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsicmVuYW1lV29ya2VyLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiI7QUFBQTs7O2dHQUdnRzs7QUFFaEcsaUNBQWlDO0FBQ2pDLHlDQUF5QztBQUN6QywyRUFBd0U7QUFFeEUsSUFBSSxPQUF1QyxDQUFDLENBQUEsMEVBQTBFO0FBRXRILFNBQVMsbUJBQW1CLENBQzNCLFdBQW1CLEVBQ25CLFFBQWdCLEVBQ2hCLFFBQWdCO0lBRWhCLElBQUksQ0FBQyxPQUFPLEVBQUU7UUFDYixPQUFPLEdBQUcsRUFBRSxDQUFDLHFCQUFxQixDQUFDLElBQUkscURBQXlCLENBQUMsV0FBVyxDQUFDLENBQUMsQ0FBQztLQUMvRTtJQUVELE9BQU8sT0FBTyxDQUFDLG1CQUFtQixDQUFDLFFBQVEsRUFBRSxRQUFRLEVBQUUsS0FBSyxFQUFFLEtBQUssRUFBRSxJQUFJLENBQUMsSUFBSSxFQUFFLENBQUM7QUFDbEYsQ0FBQztBQUVELFVBQVUsQ0FBQyxNQUFNLENBQUM7SUFDakIsbUJBQW1CO0NBQ25CLENBQUMsQ0FBQyJ9
+26
View File
@@ -0,0 +1,26 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import * as ts from 'typescript';
import * as workerpool from 'workerpool';
import { StaticLanguageServiceHost } from './staticLanguageServiceHost';
let service: ts.LanguageService | undefined;// = ts.createLanguageService(new StaticLanguageServiceHost(projectPath));
function findRenameLocations(
projectPath: string,
fileName: string,
position: number,
): readonly ts.RenameLocation[] {
if (!service) {
service = ts.createLanguageService(new StaticLanguageServiceHost(projectPath));
}
return service.findRenameLocations(fileName, position, false, false, true) ?? [];
}
workerpool.worker({
findRenameLocations
});
@@ -0,0 +1,65 @@
"use strict";
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
Object.defineProperty(exports, "__esModule", { value: true });
exports.StaticLanguageServiceHost = void 0;
const ts = require("typescript");
const path = require("path");
class StaticLanguageServiceHost {
projectPath;
_cmdLine;
_scriptSnapshots = new Map();
constructor(projectPath) {
this.projectPath = projectPath;
const existingOptions = {};
const parsed = ts.readConfigFile(projectPath, ts.sys.readFile);
if (parsed.error) {
throw parsed.error;
}
this._cmdLine = ts.parseJsonConfigFileContent(parsed.config, ts.sys, path.dirname(projectPath), existingOptions);
if (this._cmdLine.errors.length > 0) {
throw parsed.error;
}
}
getCompilationSettings() {
return this._cmdLine.options;
}
getScriptFileNames() {
return this._cmdLine.fileNames;
}
getScriptVersion(_fileName) {
return '1';
}
getProjectVersion() {
return '1';
}
getScriptSnapshot(fileName) {
let result = this._scriptSnapshots.get(fileName);
if (result === undefined) {
const content = ts.sys.readFile(fileName);
if (content === undefined) {
return undefined;
}
result = ts.ScriptSnapshot.fromString(content);
this._scriptSnapshots.set(fileName, result);
}
return result;
}
getCurrentDirectory() {
return path.dirname(this.projectPath);
}
getDefaultLibFileName(options) {
return ts.getDefaultLibFilePath(options);
}
directoryExists = ts.sys.directoryExists;
getDirectories = ts.sys.getDirectories;
fileExists = ts.sys.fileExists;
readFile = ts.sys.readFile;
readDirectory = ts.sys.readDirectory;
// this is necessary to make source references work.
realpath = ts.sys.realpath;
}
exports.StaticLanguageServiceHost = StaticLanguageServiceHost;
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoic3RhdGljTGFuZ3VhZ2VTZXJ2aWNlSG9zdC5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbInN0YXRpY0xhbmd1YWdlU2VydmljZUhvc3QudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IjtBQUFBOzs7Z0dBR2dHOzs7QUFFaEcsaUNBQWlDO0FBQ2pDLDZCQUE2QjtBQUU3QixNQUFhLHlCQUF5QjtJQUtoQjtJQUhKLFFBQVEsQ0FBdUI7SUFDL0IsZ0JBQWdCLEdBQW9DLElBQUksR0FBRyxFQUFFLENBQUM7SUFFL0UsWUFBcUIsV0FBbUI7UUFBbkIsZ0JBQVcsR0FBWCxXQUFXLENBQVE7UUFDdkMsTUFBTSxlQUFlLEdBQWdDLEVBQUUsQ0FBQztRQUN4RCxNQUFNLE1BQU0sR0FBRyxFQUFFLENBQUMsY0FBYyxDQUFDLFdBQVcsRUFBRSxFQUFFLENBQUMsR0FBRyxDQUFDLFFBQVEsQ0FBQyxDQUFDO1FBQy9ELElBQUksTUFBTSxDQUFDLEtBQUssRUFBRTtZQUNqQixNQUFNLE1BQU0sQ0FBQyxLQUFLLENBQUM7U0FDbkI7UUFDRCxJQUFJLENBQUMsUUFBUSxHQUFHLEVBQUUsQ0FBQywwQkFBMEIsQ0FBQyxNQUFNLENBQUMsTUFBTSxFQUFFLEVBQUUsQ0FBQyxHQUFHLEVBQUUsSUFBSSxDQUFDLE9BQU8sQ0FBQyxXQUFXLENBQUMsRUFBRSxlQUFlLENBQUMsQ0FBQztRQUNqSCxJQUFJLElBQUksQ0FBQyxRQUFRLENBQUMsTUFBTSxDQUFDLE1BQU0sR0FBRyxDQUFDLEVBQUU7WUFDcEMsTUFBTSxNQUFNLENBQUMsS0FBSyxDQUFDO1NBQ25CO0lBQ0YsQ0FBQztJQUNELHNCQUFzQjtRQUNyQixPQUFPLElBQUksQ0FBQyxRQUFRLENBQUMsT0FBTyxDQUFDO0lBQzlCLENBQUM7SUFDRCxrQkFBa0I7UUFDakIsT0FBTyxJQUFJLENBQUMsUUFBUSxDQUFDLFNBQVMsQ0FBQztJQUNoQyxDQUFDO0lBQ0QsZ0JBQWdCLENBQUMsU0FBaUI7UUFDakMsT0FBTyxHQUFHLENBQUM7SUFDWixDQUFDO0lBQ0QsaUJBQWlCO1FBQ2hCLE9BQU8sR0FBRyxDQUFDO0lBQ1osQ0FBQztJQUNELGlCQUFpQixDQUFDLFFBQWdCO1FBQ2pDLElBQUksTUFBTSxHQUFtQyxJQUFJLENBQUMsZ0JBQWdCLENBQUMsR0FBRyxDQUFDLFFBQVEsQ0FBQyxDQUFDO1FBQ2pGLElBQUksTUFBTSxLQUFLLFNBQVMsRUFBRTtZQUN6QixNQUFNLE9BQU8sR0FBRyxFQUFFLENBQUMsR0FBRyxDQUFDLFFBQVEsQ0FBQyxRQUFRLENBQUMsQ0FBQztZQUMxQyxJQUFJLE9BQU8sS0FBSyxTQUFTLEVBQUU7Z0JBQzFCLE9BQU8sU0FBUyxDQUFDO2FBQ2pCO1lBQ0QsTUFBTSxHQUFHLEVBQUUsQ0FBQyxjQUFjLENBQUMsVUFBVSxDQUFDLE9BQU8sQ0FBQyxDQUFDO1lBQy9DLElBQUksQ0FBQyxnQkFBZ0IsQ0FBQyxHQUFHLENBQUMsUUFBUSxFQUFFLE1BQU0sQ0FBQyxDQUFDO1NBQzVDO1FBQ0QsT0FBTyxNQUFNLENBQUM7SUFDZixDQUFDO0lBQ0QsbUJBQW1CO1FBQ2xCLE9BQU8sSUFBSSxDQUFDLE9BQU8sQ0FBQyxJQUFJLENBQUMsV0FBVyxDQUFDLENBQUM7SUFDdkMsQ0FBQztJQUNELHFCQUFxQixDQUFDLE9BQTJCO1FBQ2hELE9BQU8sRUFBRSxDQUFDLHFCQUFxQixDQUFDLE9BQU8sQ0FBQyxDQUFDO0lBQzFDLENBQUM7SUFDRCxlQUFlLEdBQUcsRUFBRSxDQUFDLEdBQUcsQ0FBQyxlQUFlLENBQUM7SUFDekMsY0FBYyxHQUFHLEVBQUUsQ0FBQyxHQUFHLENBQUMsY0FBYyxDQUFDO0lBQ3ZDLFVBQVUsR0FBRyxFQUFFLENBQUMsR0FBRyxDQUFDLFVBQVUsQ0FBQztJQUMvQixRQUFRLEdBQUcsRUFBRSxDQUFDLEdBQUcsQ0FBQyxRQUFRLENBQUM7SUFDM0IsYUFBYSxHQUFHLEVBQUUsQ0FBQyxHQUFHLENBQUMsYUFBYSxDQUFDO0lBQ3JDLG9EQUFvRDtJQUNwRCxRQUFRLEdBQUcsRUFBRSxDQUFDLEdBQUcsQ0FBQyxRQUFRLENBQUM7Q0FDM0I7QUFyREQsOERBcURDIn0=
@@ -0,0 +1,62 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import * as ts from 'typescript';
import * as path from 'path';
export class StaticLanguageServiceHost implements ts.LanguageServiceHost {
private readonly _cmdLine: ts.ParsedCommandLine;
private readonly _scriptSnapshots: Map<string, ts.IScriptSnapshot> = new Map();
constructor(readonly projectPath: string) {
const existingOptions: Partial<ts.CompilerOptions> = {};
const parsed = ts.readConfigFile(projectPath, ts.sys.readFile);
if (parsed.error) {
throw parsed.error;
}
this._cmdLine = ts.parseJsonConfigFileContent(parsed.config, ts.sys, path.dirname(projectPath), existingOptions);
if (this._cmdLine.errors.length > 0) {
throw parsed.error;
}
}
getCompilationSettings(): ts.CompilerOptions {
return this._cmdLine.options;
}
getScriptFileNames(): string[] {
return this._cmdLine.fileNames;
}
getScriptVersion(_fileName: string): string {
return '1';
}
getProjectVersion(): string {
return '1';
}
getScriptSnapshot(fileName: string): ts.IScriptSnapshot | undefined {
let result: ts.IScriptSnapshot | undefined = this._scriptSnapshots.get(fileName);
if (result === undefined) {
const content = ts.sys.readFile(fileName);
if (content === undefined) {
return undefined;
}
result = ts.ScriptSnapshot.fromString(content);
this._scriptSnapshots.set(fileName, result);
}
return result;
}
getCurrentDirectory(): string {
return path.dirname(this.projectPath);
}
getDefaultLibFileName(options: ts.CompilerOptions): string {
return ts.getDefaultLibFilePath(options);
}
directoryExists = ts.sys.directoryExists;
getDirectories = ts.sys.getDirectories;
fileExists = ts.sys.fileExists;
readFile = ts.sys.readFile;
readDirectory = ts.sys.readDirectory;
// this is necessary to make source references work.
realpath = ts.sys.realpath;
}
File diff suppressed because one or more lines are too long
+5 -7
View File
@@ -63,9 +63,10 @@ exports.referenceGeneratedDepsByArch = {
'libatk-bridge2.0-0 (>= 2.5.3)',
'libatk1.0-0 (>= 2.2.0)',
'libatspi2.0-0 (>= 2.9.90)',
'libc6 (>= 2.15)',
'libc6 (>= 2.17)',
'libc6 (>= 2.28)',
'libc6 (>= 2.4)',
'libc6 (>= 2.8)',
'libc6 (>= 2.9)',
'libcairo2 (>= 1.6.0)',
'libcurl3-gnutls | libcurl3-nss | libcurl4 | libcurl3',
@@ -73,7 +74,7 @@ exports.referenceGeneratedDepsByArch = {
'libdrm2 (>= 2.4.60)',
'libexpat1 (>= 2.0.1)',
'libgbm1 (>= 17.1.0~rc2)',
'libglib2.0-0 (>= 2.16.0)',
'libglib2.0-0 (>= 2.12.0)',
'libglib2.0-0 (>= 2.39.4)',
'libgtk-3-0 (>= 3.9.10)',
'libgtk-3-0 (>= 3.9.10) | libgtk-4-1',
@@ -82,7 +83,6 @@ exports.referenceGeneratedDepsByArch = {
'libnss3 (>= 3.26)',
'libpango-1.0-0 (>= 1.14.0)',
'libsecret-1-0 (>= 0.18)',
'libstdc++6 (>= 4.1.1)',
'libstdc++6 (>= 5)',
'libstdc++6 (>= 5.2)',
'libstdc++6 (>= 6)',
@@ -105,14 +105,13 @@ exports.referenceGeneratedDepsByArch = {
'libatk1.0-0 (>= 2.2.0)',
'libatspi2.0-0 (>= 2.9.90)',
'libc6 (>= 2.17)',
'libc6 (>= 2.28)',
'libcairo2 (>= 1.6.0)',
'libcurl3-gnutls | libcurl3-nss | libcurl4 | libcurl3',
'libdbus-1-3 (>= 1.0.2)',
'libdrm2 (>= 2.4.60)',
'libexpat1 (>= 2.0.1)',
'libgbm1 (>= 17.1.0~rc2)',
'libglib2.0-0 (>= 2.16.0)',
'libglib2.0-0 (>= 2.12.0)',
'libglib2.0-0 (>= 2.39.4)',
'libgtk-3-0 (>= 3.9.10)',
'libgtk-3-0 (>= 3.9.10) | libgtk-4-1',
@@ -121,7 +120,6 @@ exports.referenceGeneratedDepsByArch = {
'libnss3 (>= 3.26)',
'libpango-1.0-0 (>= 1.14.0)',
'libsecret-1-0 (>= 0.18)',
'libstdc++6 (>= 4.1.1)',
'libstdc++6 (>= 5)',
'libstdc++6 (>= 5.2)',
'libstdc++6 (>= 6)',
@@ -138,4 +136,4 @@ exports.referenceGeneratedDepsByArch = {
'xdg-utils (>= 1.0.2)'
]
};
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiZGVwLWxpc3RzLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiZGVwLWxpc3RzLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiI7QUFBQTs7O2dHQUdnRzs7O0FBRWhHLGtIQUFrSDtBQUNsSCw0REFBNEQ7QUFDL0MsUUFBQSxjQUFjLEdBQUc7SUFDN0IsaUJBQWlCO0lBQ2pCLHFDQUFxQztJQUNyQyxtQkFBbUI7SUFDbkIsc0RBQXNEO0lBQ3RELHNCQUFzQixDQUFDLGlCQUFpQjtDQUN4QyxDQUFDO0FBRUYsb0hBQW9IO0FBQ3BILDBDQUEwQztBQUMxQyw4REFBOEQ7QUFDakQsUUFBQSxlQUFlLEdBQUc7SUFDOUIsWUFBWSxDQUFDLHlFQUF5RTtDQUN0RixDQUFDO0FBRVcsUUFBQSw0QkFBNEIsR0FBRztJQUMzQyxPQUFPLEVBQUU7UUFDUixpQkFBaUI7UUFDakIsd0JBQXdCO1FBQ3hCLCtCQUErQjtRQUMvQix3QkFBd0I7UUFDeEIsMkJBQTJCO1FBQzNCLGlCQUFpQjtRQUNqQixpQkFBaUI7UUFDakIsa0JBQWtCO1FBQ2xCLHNCQUFzQjtRQUN0QixzREFBc0Q7UUFDdEQseUJBQXlCO1FBQ3pCLHFCQUFxQjtRQUNyQixzQkFBc0I7UUFDdEIseUJBQXlCO1FBQ3pCLDBCQUEwQjtRQUMxQiwwQkFBMEI7UUFDMUIsd0JBQXdCO1FBQ3hCLHFDQUFxQztRQUNyQyx3QkFBd0I7UUFDeEIscUJBQXFCO1FBQ3JCLG1CQUFtQjtRQUNuQiw0QkFBNEI7UUFDNUIseUJBQXlCO1FBQ3pCLFVBQVU7UUFDViwwQkFBMEI7UUFDMUIsb0JBQW9CO1FBQ3BCLCtCQUErQjtRQUMvQix3QkFBd0I7UUFDeEIsVUFBVTtRQUNWLFlBQVk7UUFDWiwwQkFBMEI7UUFDMUIsYUFBYTtRQUNiLFlBQVk7UUFDWixzQkFBc0I7S0FDdEI7SUFDRCxPQUFPLEVBQUU7UUFDUixpQkFBaUI7UUFDakIsd0JBQXdCO1FBQ3hCLCtCQUErQjtRQUMvQix3QkFBd0I7UUFDeEIsMkJBQTJCO1FBQzNCLGlCQUFpQjtRQUNqQixpQkFBaUI7UUFDakIsZ0JBQWdCO1FBQ2hCLGdCQUFnQjtRQUNoQixzQkFBc0I7UUFDdEIsc0RBQXNEO1FBQ3RELHlCQUF5QjtRQUN6QixxQkFBcUI7UUFDckIsc0JBQXNCO1FBQ3RCLHlCQUF5QjtRQUN6QiwwQkFBMEI7UUFDMUIsMEJBQTBCO1FBQzFCLHdCQUF3QjtRQUN4QixxQ0FBcUM7UUFDckMsd0JBQXdCO1FBQ3hCLHFCQUFxQjtRQUNyQixtQkFBbUI7UUFDbkIsNEJBQTRCO1FBQzVCLHlCQUF5QjtRQUN6Qix1QkFBdUI7UUFDdkIsbUJBQW1CO1FBQ25CLHFCQUFxQjtRQUNyQixtQkFBbUI7UUFDbkIsVUFBVTtRQUNWLDBCQUEwQjtRQUMxQixvQkFBb0I7UUFDcEIsK0JBQStCO1FBQy9CLHdCQUF3QjtRQUN4QixVQUFVO1FBQ1YsWUFBWTtRQUNaLDBCQUEwQjtRQUMxQixhQUFhO1FBQ2IsWUFBWTtRQUNaLHNCQUFzQjtLQUN0QjtJQUNELE9BQU8sRUFBRTtRQUNSLGlCQUFpQjtRQUNqQix3QkFBd0I7UUFDeEIsK0JBQStCO1FBQy9CLHdCQUF3QjtRQUN4QiwyQkFBMkI7UUFDM0IsaUJBQWlCO1FBQ2pCLGlCQUFpQjtRQUNqQixzQkFBc0I7UUFDdEIsc0RBQXNEO1FBQ3RELHdCQUF3QjtRQUN4QixxQkFBcUI7UUFDckIsc0JBQXNCO1FBQ3RCLHlCQUF5QjtRQUN6QiwwQkFBMEI7UUFDMUIsMEJBQTBCO1FBQzFCLHdCQUF3QjtRQUN4QixxQ0FBcUM7UUFDckMsd0JBQXdCO1FBQ3hCLHFCQUFxQjtRQUNyQixtQkFBbUI7UUFDbkIsNEJBQTRCO1FBQzVCLHlCQUF5QjtRQUN6Qix1QkFBdUI7UUFDdkIsbUJBQW1CO1FBQ25CLHFCQUFxQjtRQUNyQixtQkFBbUI7UUFDbkIsVUFBVTtRQUNWLDBCQUEwQjtRQUMxQixvQkFBb0I7UUFDcEIsK0JBQStCO1FBQy9CLHdCQUF3QjtRQUN4QixVQUFVO1FBQ1YsWUFBWTtRQUNaLDBCQUEwQjtRQUMxQixhQUFhO1FBQ2IsWUFBWTtRQUNaLHNCQUFzQjtLQUN0QjtDQUNELENBQUMifQ==
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiZGVwLWxpc3RzLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiZGVwLWxpc3RzLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiI7QUFBQTs7O2dHQUdnRzs7O0FBRWhHLGtIQUFrSDtBQUNsSCw0REFBNEQ7QUFDL0MsUUFBQSxjQUFjLEdBQUc7SUFDN0IsaUJBQWlCO0lBQ2pCLHFDQUFxQztJQUNyQyxtQkFBbUI7SUFDbkIsc0RBQXNEO0lBQ3RELHNCQUFzQixDQUFDLGlCQUFpQjtDQUN4QyxDQUFDO0FBRUYsb0hBQW9IO0FBQ3BILDBDQUEwQztBQUMxQyw4REFBOEQ7QUFDakQsUUFBQSxlQUFlLEdBQUc7SUFDOUIsWUFBWSxDQUFDLHlFQUF5RTtDQUN0RixDQUFDO0FBRVcsUUFBQSw0QkFBNEIsR0FBRztJQUMzQyxPQUFPLEVBQUU7UUFDUixpQkFBaUI7UUFDakIsd0JBQXdCO1FBQ3hCLCtCQUErQjtRQUMvQix3QkFBd0I7UUFDeEIsMkJBQTJCO1FBQzNCLGlCQUFpQjtRQUNqQixpQkFBaUI7UUFDakIsa0JBQWtCO1FBQ2xCLHNCQUFzQjtRQUN0QixzREFBc0Q7UUFDdEQseUJBQXlCO1FBQ3pCLHFCQUFxQjtRQUNyQixzQkFBc0I7UUFDdEIseUJBQXlCO1FBQ3pCLDBCQUEwQjtRQUMxQiwwQkFBMEI7UUFDMUIsd0JBQXdCO1FBQ3hCLHFDQUFxQztRQUNyQyx3QkFBd0I7UUFDeEIscUJBQXFCO1FBQ3JCLG1CQUFtQjtRQUNuQiw0QkFBNEI7UUFDNUIseUJBQXlCO1FBQ3pCLFVBQVU7UUFDViwwQkFBMEI7UUFDMUIsb0JBQW9CO1FBQ3BCLCtCQUErQjtRQUMvQix3QkFBd0I7UUFDeEIsVUFBVTtRQUNWLFlBQVk7UUFDWiwwQkFBMEI7UUFDMUIsYUFBYTtRQUNiLFlBQVk7UUFDWixzQkFBc0I7S0FDdEI7SUFDRCxPQUFPLEVBQUU7UUFDUixpQkFBaUI7UUFDakIsd0JBQXdCO1FBQ3hCLCtCQUErQjtRQUMvQix3QkFBd0I7UUFDeEIsMkJBQTJCO1FBQzNCLGlCQUFpQjtRQUNqQixpQkFBaUI7UUFDakIsZ0JBQWdCO1FBQ2hCLGdCQUFnQjtRQUNoQixnQkFBZ0I7UUFDaEIsc0JBQXNCO1FBQ3RCLHNEQUFzRDtRQUN0RCx5QkFBeUI7UUFDekIscUJBQXFCO1FBQ3JCLHNCQUFzQjtRQUN0Qix5QkFBeUI7UUFDekIsMEJBQTBCO1FBQzFCLDBCQUEwQjtRQUMxQix3QkFBd0I7UUFDeEIscUNBQXFDO1FBQ3JDLHdCQUF3QjtRQUN4QixxQkFBcUI7UUFDckIsbUJBQW1CO1FBQ25CLDRCQUE0QjtRQUM1Qix5QkFBeUI7UUFDekIsbUJBQW1CO1FBQ25CLHFCQUFxQjtRQUNyQixtQkFBbUI7UUFDbkIsVUFBVTtRQUNWLDBCQUEwQjtRQUMxQixvQkFBb0I7UUFDcEIsK0JBQStCO1FBQy9CLHdCQUF3QjtRQUN4QixVQUFVO1FBQ1YsWUFBWTtRQUNaLDBCQUEwQjtRQUMxQixhQUFhO1FBQ2IsWUFBWTtRQUNaLHNCQUFzQjtLQUN0QjtJQUNELE9BQU8sRUFBRTtRQUNSLGlCQUFpQjtRQUNqQix3QkFBd0I7UUFDeEIsK0JBQStCO1FBQy9CLHdCQUF3QjtRQUN4QiwyQkFBMkI7UUFDM0IsaUJBQWlCO1FBQ2pCLHNCQUFzQjtRQUN0QixzREFBc0Q7UUFDdEQsd0JBQXdCO1FBQ3hCLHFCQUFxQjtRQUNyQixzQkFBc0I7UUFDdEIseUJBQXlCO1FBQ3pCLDBCQUEwQjtRQUMxQiwwQkFBMEI7UUFDMUIsd0JBQXdCO1FBQ3hCLHFDQUFxQztRQUNyQyx3QkFBd0I7UUFDeEIscUJBQXFCO1FBQ3JCLG1CQUFtQjtRQUNuQiw0QkFBNEI7UUFDNUIseUJBQXlCO1FBQ3pCLG1CQUFtQjtRQUNuQixxQkFBcUI7UUFDckIsbUJBQW1CO1FBQ25CLFVBQVU7UUFDViwwQkFBMEI7UUFDMUIsb0JBQW9CO1FBQ3BCLCtCQUErQjtRQUMvQix3QkFBd0I7UUFDeEIsVUFBVTtRQUNWLFlBQVk7UUFDWiwwQkFBMEI7UUFDMUIsYUFBYTtRQUNiLFlBQVk7UUFDWixzQkFBc0I7S0FDdEI7Q0FDRCxDQUFDIn0=
+4 -6
View File
@@ -63,9 +63,10 @@ export const referenceGeneratedDepsByArch = {
'libatk-bridge2.0-0 (>= 2.5.3)',
'libatk1.0-0 (>= 2.2.0)',
'libatspi2.0-0 (>= 2.9.90)',
'libc6 (>= 2.15)',
'libc6 (>= 2.17)',
'libc6 (>= 2.28)',
'libc6 (>= 2.4)',
'libc6 (>= 2.8)',
'libc6 (>= 2.9)',
'libcairo2 (>= 1.6.0)',
'libcurl3-gnutls | libcurl3-nss | libcurl4 | libcurl3',
@@ -73,7 +74,7 @@ export const referenceGeneratedDepsByArch = {
'libdrm2 (>= 2.4.60)',
'libexpat1 (>= 2.0.1)',
'libgbm1 (>= 17.1.0~rc2)',
'libglib2.0-0 (>= 2.16.0)',
'libglib2.0-0 (>= 2.12.0)',
'libglib2.0-0 (>= 2.39.4)',
'libgtk-3-0 (>= 3.9.10)',
'libgtk-3-0 (>= 3.9.10) | libgtk-4-1',
@@ -82,7 +83,6 @@ export const referenceGeneratedDepsByArch = {
'libnss3 (>= 3.26)',
'libpango-1.0-0 (>= 1.14.0)',
'libsecret-1-0 (>= 0.18)',
'libstdc++6 (>= 4.1.1)',
'libstdc++6 (>= 5)',
'libstdc++6 (>= 5.2)',
'libstdc++6 (>= 6)',
@@ -105,14 +105,13 @@ export const referenceGeneratedDepsByArch = {
'libatk1.0-0 (>= 2.2.0)',
'libatspi2.0-0 (>= 2.9.90)',
'libc6 (>= 2.17)',
'libc6 (>= 2.28)',
'libcairo2 (>= 1.6.0)',
'libcurl3-gnutls | libcurl3-nss | libcurl4 | libcurl3',
'libdbus-1-3 (>= 1.0.2)',
'libdrm2 (>= 2.4.60)',
'libexpat1 (>= 2.0.1)',
'libgbm1 (>= 17.1.0~rc2)',
'libglib2.0-0 (>= 2.16.0)',
'libglib2.0-0 (>= 2.12.0)',
'libglib2.0-0 (>= 2.39.4)',
'libgtk-3-0 (>= 3.9.10)',
'libgtk-3-0 (>= 3.9.10) | libgtk-4-1',
@@ -121,7 +120,6 @@ export const referenceGeneratedDepsByArch = {
'libnss3 (>= 3.26)',
'libpango-1.0-0 (>= 1.14.0)',
'libsecret-1-0 (>= 0.18)',
'libstdc++6 (>= 4.1.1)',
'libstdc++6 (>= 5)',
'libstdc++6 (>= 5.2)',
'libstdc++6 (>= 6)',
File diff suppressed because one or more lines are too long
-2
View File
@@ -126,7 +126,6 @@ export const referenceGeneratedDepsByArch = {
'libc.so.6(GLIBC_2.16)',
'libc.so.6(GLIBC_2.17)',
'libc.so.6(GLIBC_2.25)',
'libc.so.6(GLIBC_2.28)',
'libc.so.6(GLIBC_2.4)',
'libc.so.6(GLIBC_2.6)',
'libc.so.6(GLIBC_2.7)',
@@ -220,7 +219,6 @@ export const referenceGeneratedDepsByArch = {
'libc.so.6()(64bit)',
'libc.so.6(GLIBC_2.17)(64bit)',
'libc.so.6(GLIBC_2.25)(64bit)',
'libc.so.6(GLIBC_2.28)(64bit)',
'libcairo.so.2()(64bit)',
'libcurl.so.4()(64bit)',
'libdbus-1.so.3()(64bit)',
+4
View File
@@ -38,6 +38,7 @@
"@types/through2": "^2.0.36",
"@types/tmp": "^0.2.1",
"@types/underscore": "^1.8.9",
"@types/workerpool": "^6.4.0",
"@types/xml2js": "0.0.33",
"@vscode/iconv-lite-umd": "0.7.0",
"@vscode/vsce": "^2.16.0",
@@ -70,5 +71,8 @@
"tree-sitter": "https://github.com/joaomoreno/node-tree-sitter/releases/download/v0.20.0/tree-sitter-0.20.0.tgz",
"tree-sitter-typescript": "^0.20.1",
"vscode-gulp-watch": "^5.0.3"
},
"dependencies": {
"workerpool": "^6.4.0"
}
}
+12
View File
@@ -646,6 +646,13 @@
dependencies:
"@types/node" "*"
"@types/workerpool@^6.4.0":
version "6.4.0"
resolved "https://registry.yarnpkg.com/@types/workerpool/-/workerpool-6.4.0.tgz#c79292915dd08350d10e78e74687b6f401f270b8"
integrity sha512-SIF2/169pDsLKeM8GQGHkOFifGalDbZgiBSaLUnnlVSRsAOenkAvQ6h4uhV2W+PZZczS+8LQxACwNkSykdT91A==
dependencies:
"@types/node" "*"
"@types/xml2js@0.0.33":
version "0.0.33"
resolved "https://registry.yarnpkg.com/@types/xml2js/-/xml2js-0.0.33.tgz#20c5dd6460245284d64a55690015b95e409fb7de"
@@ -3017,6 +3024,11 @@ wide-align@^1.1.0:
dependencies:
string-width "^1.0.2 || 2 || 3 || 4"
workerpool@^6.4.0:
version "6.4.0"
resolved "https://registry.yarnpkg.com/workerpool/-/workerpool-6.4.0.tgz#f8d5cfb45fde32fa3b7af72ad617c3369567a462"
integrity sha512-i3KR1mQMNwY2wx20ozq2EjISGtQWDIfV56We+yGJ5yDs8jTwQiLLaqHlkBHITlCuJnYlVRmXegxFxZg7gqI++A==
wrappy@1:
version "1.0.2"
resolved "https://registry.yarnpkg.com/wrappy/-/wrappy-1.0.2.tgz#b5243d8f3ec1aa35f1364605bc0d1036e30ab69f"
+5 -5
View File
@@ -3503,10 +3503,10 @@ export class CommandCenter {
const allRepositoriesLabel = l10n.t('All Repositories');
const allRepositoriesQuickPickItem: QuickPickItem = { label: allRepositoriesLabel };
const repositoriesQuickPickItems: QuickPickItem[] = Array.from(this.model.unsafeRepositories.keys())
const repositoriesQuickPickItems: QuickPickItem[] = this.model.unsafeRepositories
.sort(compareRepositoryLabel).map(r => new RepositoryItem(r));
quickpick.items = this.model.unsafeRepositories.size === 1 ? [...repositoriesQuickPickItems] :
quickpick.items = this.model.unsafeRepositories.length === 1 ? [...repositoriesQuickPickItems] :
[...repositoriesQuickPickItems, { label: '', kind: QuickPickItemKind.Separator }, allRepositoriesQuickPickItem];
quickpick.show();
@@ -3523,7 +3523,7 @@ export class CommandCenter {
if (repositoryItem.label === allRepositoriesLabel) {
// All Repositories
unsafeRepositories.push(...this.model.unsafeRepositories.keys());
unsafeRepositories.push(...this.model.unsafeRepositories);
} else {
// One Repository
unsafeRepositories.push((repositoryItem as RepositoryItem).path);
@@ -3531,11 +3531,11 @@ export class CommandCenter {
for (const unsafeRepository of unsafeRepositories) {
// Mark as Safe
await this.git.addSafeDirectory(this.model.unsafeRepositories.get(unsafeRepository)!);
await this.git.addSafeDirectory(this.model.getUnsafeRepositoryPath(unsafeRepository)!);
// Open Repository
await this.model.openRepository(unsafeRepository);
this.model.unsafeRepositories.delete(unsafeRepository);
this.model.deleteUnsafeRepository(unsafeRepository);
}
}
+1 -1
View File
@@ -2021,7 +2021,7 @@ export class Repository {
}
// --find-renames option is only available starting with git 2.18.0
if (opts?.similarityThreshold && this._git.compareGitVersionTo('2.18.0') !== -1) {
if (opts?.similarityThreshold && opts.similarityThreshold !== 50 && this._git.compareGitVersionTo('2.18.0') !== -1) {
args.push(`--find-renames=${opts.similarityThreshold}%`);
}
+55 -41
View File
@@ -34,40 +34,6 @@ class RepositoryPick implements QuickPickItem {
constructor(public readonly repository: Repository, public readonly index: number) { }
}
abstract class RepositoryMap<T = void> extends Map<string, T> {
constructor() {
super();
this.updateContextKey();
}
override set(key: string, value: T): this {
const result = super.set(key, value);
this.updateContextKey();
return result;
}
override delete(key: string): boolean {
const result = super.delete(key);
this.updateContextKey();
return result;
}
abstract updateContextKey(): void;
}
/**
* Key - normalized path used in user interface
* Value - path extracted from the output of the `git status` command
* used when calling `git config --global --add safe.directory`
*/
class UnsafeRepositoryMap extends RepositoryMap<string> {
updateContextKey(): void {
commands.executeCommand('setContext', 'git.unsafeRepositoryCount', this.size);
}
}
export interface ModelChangeEvent {
repository: Repository;
uri: Uri;
@@ -159,6 +125,45 @@ class ParentRepositoriesManager {
}
}
class UnsafeRepositoriesManager {
/**
* Key - normalized path used in user interface
* Value - path extracted from the output of the `git status` command
* used when calling `git config --global --add safe.directory`
*/
private _repositories = new Map<string, string>();
get repositories(): string[] {
return [...this._repositories.keys()];
}
addRepository(repository: string, path: string): void {
this._repositories.set(repository, path);
this.onDidChangeRepositories();
}
deleteRepository(repository: string): boolean {
const result = this._repositories.delete(repository);
if (result) {
this.onDidChangeRepositories();
}
return result;
}
getRepositoryPath(repository: string): string | undefined {
return this._repositories.get(repository);
}
hasRepository(repository: string): boolean {
return this._repositories.has(repository);
}
private onDidChangeRepositories(): void {
commands.executeCommand('setContext', 'git.unsafeRepositoryCount', this._repositories.size);
}
}
export class Model implements IBranchProtectionProviderRegistry, IRemoteSourcePublisherRegistry, IPostCommitCommandsProviderRegistry, IPushErrorHandlerRegistry {
private _onDidOpenRepository = new EventEmitter<Repository>();
@@ -226,9 +231,9 @@ export class Model implements IBranchProtectionProviderRegistry, IRemoteSourcePu
private pushErrorHandlers = new Set<PushErrorHandler>();
private _unsafeRepositories = new UnsafeRepositoryMap();
get unsafeRepositories(): UnsafeRepositoryMap {
return this._unsafeRepositories;
private _unsafeRepositoriesManager: UnsafeRepositoriesManager;
get unsafeRepositories(): string[] {
return this._unsafeRepositoriesManager.repositories;
}
private _parentRepositoriesManager: ParentRepositoriesManager;
@@ -257,6 +262,7 @@ export class Model implements IBranchProtectionProviderRegistry, IRemoteSourcePu
// Repositories managers
this._closedRepositoriesManager = new ClosedRepositoriesManager(workspaceState);
this._parentRepositoriesManager = new ParentRepositoriesManager(globalState);
this._unsafeRepositoriesManager = new UnsafeRepositoriesManager();
workspace.onDidChangeWorkspaceFolders(this.onDidChangeWorkspaceFolders, this, this.disposables);
window.onDidChangeVisibleTextEditors(this.onDidChangeVisibleTextEditors, this, this.disposables);
@@ -296,7 +302,7 @@ export class Model implements IBranchProtectionProviderRegistry, IRemoteSourcePu
parentRepositoryConfig === 'prompt') {
// Parent repositories notification
this.showParentRepositoryNotification();
} else if (this._unsafeRepositories.size !== 0) {
} else if (this.unsafeRepositories.length !== 0) {
// Unsafe repositories notification
this.showUnsafeRepositoryNotification();
}
@@ -547,11 +553,11 @@ export class Model implements IBranchProtectionProviderRegistry, IRemoteSourcePu
this.logger.trace(`Unsafe repository: ${repositoryRoot}`);
// Show a notification if the unsafe repository is opened after the initial scan
if (this._state === 'initialized' && !this._unsafeRepositories.has(repositoryRoot)) {
if (this._state === 'initialized' && !this._unsafeRepositoriesManager.hasRepository(repositoryRoot)) {
this.showUnsafeRepositoryNotification();
}
this._unsafeRepositories.set(repositoryRoot, unsafeRepositoryMatch[2]);
this._unsafeRepositoriesManager.addRepository(repositoryRoot, unsafeRepositoryMatch[2]);
return;
}
@@ -903,6 +909,14 @@ export class Model implements IBranchProtectionProviderRegistry, IRemoteSourcePu
return [...this.pushErrorHandlers];
}
getUnsafeRepositoryPath(repository: string): string | undefined {
return this._unsafeRepositoriesManager.getRepositoryPath(repository);
}
deleteUnsafeRepository(repository: string): boolean {
return this._unsafeRepositoriesManager.deleteRepository(repository);
}
private async isRepositoryOutsideWorkspace(repositoryPath: string): Promise<boolean> {
const workspaceFolders = (workspace.workspaceFolders || [])
.filter(folder => folder.uri.scheme === 'file');
@@ -969,7 +983,7 @@ export class Model implements IBranchProtectionProviderRegistry, IRemoteSourcePu
return;
}
const message = this._unsafeRepositories.size === 1 ?
const message = this.unsafeRepositories.length === 1 ?
l10n.t('The git repository in the current folder is potentially unsafe as the folder is owned by someone other than the current user.') :
l10n.t('The git repositories in the current folder are potentially unsafe as the folders are owned by someone other than the current user.');
+4 -4
View File
@@ -8,12 +8,12 @@ const fs = require('fs');
const webpack = require('webpack');
const fancyLog = require('fancy-log');
const ansiColors = require('ansi-colors');
const { Mangler } = require('../build/lib/mangleTypeScript');
const { Mangler } = require('../build/lib/mangle/index');
/**
* Map of project paths to mangled file contents
*
* @type {Map<string, Map<string, { out: string; sourceMap?: string }>>}
* @type {Map<string, Promise<Map<string, { out: string; sourceMap?: string }>>>}
*/
const mangleMap = new Map();
@@ -25,7 +25,7 @@ function getMangledFileContents(projectPath) {
if (!entry) {
const log = (...data) => fancyLog(ansiColors.blue('[mangler]'), ...data);
log(`Mangling ${projectPath}`);
const ts2tsMangler = new Mangler(projectPath, log);
const ts2tsMangler = new Mangler(projectPath, log, { mangleExports: true, manglePrivateFields: true });
entry = ts2tsMangler.computeNewFileContents();
mangleMap.set(projectPath, entry);
}
@@ -55,7 +55,7 @@ module.exports = async function (source, sourceMap, meta) {
const callback = this.async();
const fileContentsMap = getMangledFileContents(options.configFile);
const fileContentsMap = await getMangledFileContents(options.configFile);
const newContents = fileContentsMap.get(this.resourcePath);
callback(null, newContents?.out ?? source, sourceMap, meta);
@@ -58,7 +58,8 @@ class MyCompletionItem extends vscode.CompletionItem {
public readonly metadata: any | undefined,
client: ITypeScriptServiceClient,
) {
super(tsEntry.name, MyCompletionItem.convertKind(tsEntry.kind));
const label = tsEntry.name || (tsEntry.insertText ?? '');
super(label, MyCompletionItem.convertKind(tsEntry.kind));
if (tsEntry.source && tsEntry.hasAction && client.apiVersion.lt(API.v490)) {
// De-prioritze auto-imports
@@ -72,18 +73,18 @@ class MyCompletionItem extends vscode.CompletionItem {
// Render "fancy" when source is a workspace path
const qualifierCandidate = vscode.workspace.asRelativePath(tsEntry.source);
if (qualifierCandidate !== tsEntry.source) {
this.label = { label: tsEntry.name, description: qualifierCandidate };
this.label = { label, description: qualifierCandidate };
}
}
const { sourceDisplay, isSnippet } = tsEntry;
if (sourceDisplay) {
this.label = { label: tsEntry.name, description: Previewer.asPlainTextWithLinks(sourceDisplay, client) };
this.label = { label, description: Previewer.asPlainTextWithLinks(sourceDisplay, client) };
}
if (tsEntry.labelDetails) {
this.label = { label: tsEntry.name, ...tsEntry.labelDetails };
this.label = { label, ...tsEntry.labelDetails };
}
this.preselect = tsEntry.isRecommended;
+2 -2
View File
@@ -75,6 +75,7 @@
"@vscode/sudo-prompt": "9.3.1",
"@vscode/vscode-languagedetection": "1.0.21",
"@vscode/windows-mutex": "^0.4.4",
"@vscode/windows-process-tree": "^0.5.0",
"@vscode/windows-registry": "^1.1.0",
"graceful-fs": "4.2.8",
"http-proxy-agent": "^2.1.0",
@@ -85,7 +86,7 @@
"native-is-elevated": "0.6.0",
"native-keymap": "^3.3.2",
"native-watchdog": "^1.4.1",
"node-pty": "0.11.0-beta33",
"node-pty": "1.0",
"tas-client-umd": "0.1.8",
"v8-inspect-profiler": "^0.1.0",
"vscode-oniguruma": "1.7.0",
@@ -227,7 +228,6 @@
"url": "https://github.com/microsoft/vscode/issues"
},
"optionalDependencies": {
"@vscode/windows-process-tree": "0.4.2",
"windows-foreground-love": "0.5.0"
}
}
+2 -4
View File
@@ -11,6 +11,7 @@
"@vscode/ripgrep": "^1.15.4",
"@vscode/spdlog": "^0.13.10",
"@vscode/vscode-languagedetection": "1.0.21",
"@vscode/windows-process-tree": "^0.5.0",
"@vscode/windows-registry": "^1.1.0",
"cookie": "^0.4.0",
"graceful-fs": "4.2.8",
@@ -20,7 +21,7 @@
"keytar": "7.9.0",
"minimist": "^1.2.6",
"native-watchdog": "^1.4.1",
"node-pty": "0.11.0-beta33",
"node-pty": "1.0",
"tas-client-umd": "0.1.8",
"vscode-oniguruma": "1.7.0",
"vscode-regexpp": "^3.1.0",
@@ -35,8 +36,5 @@
"xterm-headless": "5.3.0-beta.1",
"yauzl": "^2.9.2",
"yazl": "^2.4.3"
},
"optionalDependencies": {
"@vscode/windows-process-tree": "0.4.2"
}
}
+8 -8
View File
@@ -101,10 +101,10 @@
dependencies:
node-addon-api "^3.0.2"
"@vscode/windows-process-tree@0.4.2":
version "0.4.2"
resolved "https://registry.yarnpkg.com/@vscode/windows-process-tree/-/windows-process-tree-0.4.2.tgz#54d010fdeb06dfe3a9c6d58fcb3ed9acfc962f33"
integrity sha512-b20865s1HG1VtGt887KrB1blwFS6p4L1Fl1o/WplO9j7sGBle8sLqkNnGXbCaRNgdIgfXtitmzG366FVynJZdQ==
"@vscode/windows-process-tree@^0.5.0":
version "0.5.0"
resolved "https://registry.yarnpkg.com/@vscode/windows-process-tree/-/windows-process-tree-0.5.0.tgz#b8205b862c75a1e0ad8b7bf4350dc85036ee3a2c"
integrity sha512-y8Oliel/rBSYh9f1T4F0zQjJNPeJRgYRhEKZsjas7JXKLf46FpE3Ux8e9+7HelUD8dXFH7C7N6895nU0WhrMlg==
dependencies:
nan "^2.17.0"
@@ -537,10 +537,10 @@ node-gyp-build@^4.3.0:
resolved "https://registry.yarnpkg.com/node-gyp-build/-/node-gyp-build-4.3.0.tgz#9f256b03e5826150be39c764bf51e993946d71a3"
integrity sha512-iWjXZvmboq0ja1pUGULQBexmxq8CV4xBhX7VDOTbL7ZR4FOowwY/VOtRxBN/yKxmdGoIp4j5ysNT4u3S2pDQ3Q==
node-pty@0.11.0-beta33:
version "0.11.0-beta33"
resolved "https://registry.yarnpkg.com/node-pty/-/node-pty-0.11.0-beta33.tgz#722a729fb9449f591279bee1f8b431b71a9af4a1"
integrity sha512-SoP5BbSfvc8Um51rIriUEOPvMltc43iTaKXGJaJKLR3+NfQbjcCcNQGyOd9P9pvBccWYg+Rncv18qMtJKIAi1Q==
node-pty@1.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/node-pty/-/node-pty-1.0.0.tgz#7daafc0aca1c4ca3de15c61330373af4af5861fd"
integrity sha512-wtBMWWS7dFZm/VgqElrTvtfMq4GzJ6+edFI0Y0zyzygUSZMgZdraDUMUhCIvkjhJjme15qWmbyJbtAx4ot4uZA==
dependencies:
nan "^2.17.0"
+13 -5
View File
@@ -27,17 +27,19 @@ const { getUNCHost, addUNCHostToAllowlist } = require('./vs/base/node/unc');
const product = require('../product.json');
const { app, protocol, crashReporter, Menu } = require('electron');
// Enable sandbox globally
app.enableSandbox();
// Enable portable support
const portable = bootstrapNode.configurePortable(product);
// Enable ASAR support
bootstrap.enableASARSupport();
// Set userData path before app 'ready' event
// Enable sandbox globally unless disabled via `--no-sandbox` argument
const args = parseCLIArgs();
if (args['sandbox']) {
app.enableSandbox();
}
// Set userData path before app 'ready' event
const userDataPath = getUserDataPath(args, product.nameShort ?? 'code-oss-dev');
if (process.platform === 'win32') {
const userDataUNCHost = getUNCHost(userDataPath);
@@ -464,7 +466,13 @@ function parseCLIArgs() {
'locale',
'js-flags',
'crash-reporter-directory'
]
],
default: {
'sandbox': true
},
alias: {
'no-sandbox': 'sandbox'
}
});
}
-75
View File
@@ -1,75 +0,0 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
// Copied from the `@vscode/windows-process-tree` package.
// The dependency is an optional dependency that is only used on Windows,
// but we need the typings to compile on all platforms.
// The `@types/windows-process-tree` package has also been deprecated.
declare module '@vscode/windows-process-tree' {
export enum ProcessDataFlag { }
export interface IProcessInfo {
pid: number;
ppid: number;
name: string;
/**
* The working set size of the process, in bytes.
*/
memory?: number;
/**
* The string returned is at most 512 chars, strings exceeding this length are truncated.
*/
commandLine?: string;
}
export interface IProcessCpuInfo extends IProcessInfo {
cpu?: number;
}
export interface IProcessTreeNode {
pid: number;
name: string;
memory?: number;
commandLine?: string;
children: IProcessTreeNode[];
}
/**
* Returns a tree of processes with the rootPid process as the root.
* @param rootPid - The pid of the process that will be the root of the tree.
* @param callback - The callback to use with the returned list of processes.
* @param flags - The flags for what process data should be included.
*/
export function getProcessTree(rootPid: number, callback: (tree: IProcessTreeNode | undefined) => void, flags?: ProcessDataFlag): void;
namespace getProcessTree {
function __promisify__(rootPid: number, flags?: ProcessDataFlag): Promise<IProcessTreeNode>;
}
/**
* Returns a list of processes containing the rootPid process and all of its descendants.
* @param rootPid - The pid of the process of interest.
* @param callback - The callback to use with the returned set of processes.
* @param flags - The flags for what process data should be included.
*/
export function getProcessList(rootPid: number, callback: (processList: IProcessInfo[] | undefined) => void, flags?: ProcessDataFlag): void;
namespace getProcessList {
function __promisify__(rootPid: number, flags?: ProcessDataFlag): Promise<IProcessInfo[]>;
}
/**
* Returns the list of processes annotated with cpu usage information.
* @param processList - The list of processes.
* @param callback - The callback to use with the returned list of processes.
*/
export function getProcessCpuUsage(processList: IProcessInfo[], callback: (processListWithCpu: IProcessCpuInfo[]) => void): void;
namespace getProcessCpuUsage {
function __promisify__(processList: IProcessInfo[]): Promise<IProcessCpuInfo[]>;
}
}
+26 -9
View File
@@ -129,17 +129,30 @@ class Trait<T> implements ISpliceable<boolean>, IDisposable {
const diff = elements.length - deleteCount;
const end = start + deleteCount;
const sortedIndexes = [
...this.sortedIndexes.filter(i => i < start),
...elements.map((hasTrait, i) => hasTrait ? i + start : -1).filter(i => i !== -1),
...this.sortedIndexes.filter(i => i >= end).map(i => i + diff)
];
const sortedIndexes: number[] = [];
let firstSortedIndex: number | undefined = undefined;
let i = 0;
while (i < this.sortedIndexes.length && this.sortedIndexes[i] < start) {
sortedIndexes.push(this.sortedIndexes[i++]);
}
for (let j = 0; j < elements.length; j++) {
if (elements[j]) {
sortedIndexes.push(j + start);
firstSortedIndex = firstSortedIndex ?? sortedIndexes[sortedIndexes.length - 1];
}
}
while (i < this.sortedIndexes.length && this.sortedIndexes[i] >= end) {
sortedIndexes.push(this.sortedIndexes[i++] + diff);
firstSortedIndex = firstSortedIndex ?? sortedIndexes[sortedIndexes.length - 1];
}
const length = this.length + diff;
if (this.sortedIndexes.length > 0 && sortedIndexes.length === 0 && length > 0) {
const first = this.sortedIndexes.find(index => index >= start) ?? length - 1;
sortedIndexes.push(Math.min(first, length - 1));
sortedIndexes.push(Math.min(firstSortedIndex ?? length - 1, length - 1));
}
this.renderer.splice(start, deleteCount, elements.length);
@@ -226,12 +239,16 @@ class TraitSpliceable<T> implements ISpliceable<T> {
splice(start: number, deleteCount: number, elements: T[]): void {
if (!this.identityProvider) {
return this.trait.splice(start, deleteCount, elements.map(() => false));
return this.trait.splice(start, deleteCount, new Array(elements.length).fill(false));
}
const pastElementsWithTrait = this.trait.get().map(i => this.identityProvider!.getId(this.view.element(i)).toString());
const elementsWithTrait = elements.map(e => pastElementsWithTrait.indexOf(this.identityProvider!.getId(e).toString()) > -1);
if (pastElementsWithTrait.length === 0) {
return this.trait.splice(start, deleteCount, new Array(elements.length).fill(false));
}
const pastElementsWithTraitSet = new Set(pastElementsWithTrait);
const elementsWithTrait = elements.map(e => pastElementsWithTraitSet.has(this.identityProvider!.getId(e).toString()));
this.trait.splice(start, deleteCount, elementsWithTrait);
}
}
+1
View File
@@ -74,6 +74,7 @@ export class ErrorHandler {
export const errorHandler = new ErrorHandler();
/** @skipMangle */
export function setUnexpectedErrorHandler(newUnexpectedErrorHandler: (e: any) => void): void {
errorHandler.setUnexpectedErrorHandler(newUnexpectedErrorHandler);
}
+2
View File
@@ -48,6 +48,8 @@ else {
* environments.
*
* Note: in web, this property is hardcoded to be `/`.
*
* @skipMangle
*/
export const cwd = safeProcess.cwd;
+1 -1
View File
@@ -10,5 +10,5 @@
* supported in JSON.
* @param content the content to strip comments from
* @returns the content without comments
*/
*/
export function stripComments(content: string): string;
@@ -558,6 +558,7 @@ export class SimpleWorkerServer<H extends object> {
/**
* Called on the worker side
* @skipMangle
*/
export function create(postMessage: (msg: Message, transfer?: ArrayBuffer[]) => void): SimpleWorkerServer<any> {
return new SimpleWorkerServer(postMessage, null);
+5 -8
View File
@@ -115,13 +115,13 @@ export function listProcesses(rootPid: number): Promise<ProcessItem> {
const cleanUNCPrefix = (value: string): string => {
if (value.indexOf('\\\\?\\') === 0) {
return value.substr(4);
return value.substring(4);
} else if (value.indexOf('\\??\\') === 0) {
return value.substr(4);
return value.substring(4);
} else if (value.indexOf('"\\\\?\\') === 0) {
return '"' + value.substr(5);
return '"' + value.substring(5);
} else if (value.indexOf('"\\??\\') === 0) {
return '"' + value.substr(5);
return '"' + value.substring(5);
} else {
return value;
}
@@ -169,10 +169,7 @@ export function listProcesses(rootPid: number): Promise<ProcessItem> {
reject(new Error(`Root process ${rootPid} not found`));
}
});
},
// Workaround duplicate enum identifiers issue in @vscode/windows-process-tree
// Ref https://github.com/microsoft/vscode/pull/179508
(windowsProcessTree.ProcessDataFlag as any).CommandLine | (windowsProcessTree.ProcessDataFlag as any).Memory);
}, windowsProcessTree.ProcessDataFlag.CommandLine | windowsProcessTree.ProcessDataFlag.Memory);
});
} else { // OS X & Linux
function calculateLinuxCpuUsage() {
+2
View File
@@ -9,6 +9,8 @@ interface ICSSPluginConfig {
/**
* Invoked by the loader at run-time
*
* @skipMangle
*/
export function load(name: string, req: AMDLoader.IRelativeRequire, load: AMDLoader.IPluginLoadCallback, config: AMDLoader.IConfigurationOptions): void {
config = config || {};
@@ -297,7 +297,12 @@ export class TextAreaHandler extends ViewPart {
};
const textAreaWrapper = this._register(new TextAreaWrapper(this.textArea.domNode));
this._textAreaInput = this._register(new TextAreaInput(textAreaInputHost, textAreaWrapper, platform.OS, browser));
this._textAreaInput = this._register(new TextAreaInput(textAreaInputHost, textAreaWrapper, platform.OS, {
isAndroid: browser.isAndroid,
isChrome: browser.isChrome,
isFirefox: browser.isFirefox,
isSafari: browser.isSafari,
}));
this._register(this._textAreaInput.onKeyDown((e: IKeyboardEvent) => {
this._viewController.emitKeyDown(e);
@@ -4,6 +4,7 @@
*--------------------------------------------------------------------------------------------*/
import { Codicon } from 'vs/base/common/codicons';
import { MarkdownString } from 'vs/base/common/htmlContent';
import { ThemeIcon } from 'vs/base/common/themables';
import { ModelDecorationOptions } from 'vs/editor/common/model/textModel';
import { localize } from 'vs/nls';
@@ -37,3 +38,10 @@ export const diffDeleteDecoration = ModelDecorationOptions.register({
className: 'char-delete',
description: 'char-delete',
});
export const arrowRevertChange = ModelDecorationOptions.register({
description: 'diff-editor-arrow-revert-change',
glyphMarginHoverMessage: new MarkdownString(undefined, { isTrusted: true, supportThemeIcons: true }).appendMarkdown(localize('revertChangeHoverMessage', 'Click to revert change')),
glyphMarginClassName: 'arrow-revert-change ' + ThemeIcon.asClassName(Codicon.arrowRight),
zIndex: 10001,
});
@@ -14,12 +14,12 @@ import { isDefined } from 'vs/base/common/types';
import { Constants } from 'vs/base/common/uint';
import 'vs/css!./style';
import { IEditorConstructionOptions } from 'vs/editor/browser/config/editorConfiguration';
import { ICodeEditor, IDiffEditor, IDiffEditorConstructionOptions } from 'vs/editor/browser/editorBrowser';
import { ICodeEditor, IDiffEditor, IDiffEditorConstructionOptions, IMouseTargetViewZone } from 'vs/editor/browser/editorBrowser';
import { EditorExtensionsRegistry, IDiffEditorContributionDescription } from 'vs/editor/browser/editorExtensions';
import { ICodeEditorService } from 'vs/editor/browser/services/codeEditorService';
import { CodeEditorWidget, ICodeEditorWidgetOptions } from 'vs/editor/browser/widget/codeEditorWidget';
import { IDiffCodeEditorWidgetOptions } from 'vs/editor/browser/widget/diffEditorWidget';
import { diffAddDecoration, diffDeleteDecoration, diffFullLineAddDecoration, diffFullLineDeleteDecoration } from 'vs/editor/browser/widget/diffEditorWidget2/decorations';
import { arrowRevertChange, diffAddDecoration, diffDeleteDecoration, diffFullLineAddDecoration, diffFullLineDeleteDecoration } from 'vs/editor/browser/widget/diffEditorWidget2/decorations';
import { DiffEditorSash } from 'vs/editor/browser/widget/diffEditorWidget2/diffEditorSash';
import { ViewZoneManager } from 'vs/editor/browser/widget/diffEditorWidget2/lineAlignment';
import { MovedBlocksLinesPart } from 'vs/editor/browser/widget/diffEditorWidget2/movedBlocksLines';
@@ -40,6 +40,8 @@ import { IInstantiationService } from 'vs/platform/instantiation/common/instanti
import { ServiceCollection } from 'vs/platform/instantiation/common/serviceCollection';
import { DelegatingEditor } from './delegatingEditorImpl';
import { DiffMapping, DiffModel } from './diffModel';
import { Range } from 'vs/editor/common/core/range';
import { LineRangeMapping } from 'vs/editor/common/diff/linesDiffComputer';
const diffEditorDefaultOptions: ValidDiffEditorBaseOptions = {
enableSplitViewResizing: true,
@@ -142,7 +144,16 @@ export class DiffEditorWidget2 extends DelegatingEditor implements IDiffEditor {
this._register(keepAlive(this._sash, true));
this._register(new UnchangedRangesFeature(this._originalEditor, this._modifiedEditor, this._diffModel));
this._register(this._instantiationService.createInstance(ViewZoneManager, this._originalEditor, this._modifiedEditor, this._diffModel, this._options.map(o => o.renderSideBySide)));
this._register(
this._instantiationService.createInstance(
ViewZoneManager,
this._originalEditor,
this._modifiedEditor,
this._diffModel,
this._options.map((o) => o.renderSideBySide),
this
)
);
this._register(this._instantiationService.createInstance(OverviewRulerPart,
this._originalEditor,
@@ -229,6 +240,10 @@ export class DiffEditorWidget2 extends DelegatingEditor implements IDiffEditor {
originalDecorations.push({ range: i.originalRange, options: diffDeleteDecoration });
modifiedDecorations.push({ range: i.modifiedRange, options: diffAddDecoration });
}
if (!m.lineRangeMapping.modifiedRange.isEmpty) {
modifiedDecorations.push({ range: Range.fromPositions(new Position(m.lineRangeMapping.modifiedRange.startLineNumber, 1)), options: arrowRevertChange });
}
}
if (currentMove) {
@@ -311,24 +326,32 @@ export class DiffEditorWidget2 extends DelegatingEditor implements IDiffEditor {
m.syncedMovedTexts.set(movedText, undefined);
}));
// Revert change when an arrow is clicked.
/*TODO
this._register(editor.onMouseDown(event => {
if (!event.event.rightButton && event.target.position && event.target.element?.className.includes('arrow-revert-change')) {
const lineNumber = event.target.position.lineNumber;
const viewZone = event.target as editorBrowser.IMouseTargetViewZone | undefined;
const change = this._diffComputationResult?.changes.find(c =>
// delete change
viewZone?.detail.afterLineNumber === c.modifiedStartLineNumber ||
// other changes
(c.modifiedEndLineNumber > 0 && c.modifiedStartLineNumber === lineNumber));
if (change) {
this.revertChange(change);
const viewZone = event.target as IMouseTargetViewZone | undefined;
const model = this._diffModel.get();
if (!model) {
return;
}
const diffs = model.diff.get()?.mappings;
if (!diffs) {
return;
}
const diff = diffs.find(d =>
viewZone?.detail.afterLineNumber === d.lineRangeMapping.modifiedRange.startLineNumber - 1 ||
d.lineRangeMapping.modifiedRange.startLineNumber === lineNumber
);
if (!diff) {
return;
}
this.revert(diff.lineRangeMapping);
event.event.stopPropagation();
this._updateDecorations();
return;
}
}));*/
}));
return editor;
}
@@ -579,6 +602,17 @@ export class DiffEditorWidget2 extends DelegatingEditor implements IDiffEditor {
};
}
public revert(diff: LineRangeMapping): void {
const model = this._model.get();
if (!model) {
return;
}
const originalText = model.original.getValueInRange(diff.originalRange.toExclusiveRange());
this._modifiedEditor.executeEdits('diffEditor', [
{ range: diff.modifiedRange.toExclusiveRange(), text: originalText }
]);
}
private _goTo(diff: DiffMapping): void {
this._modifiedEditor.setPosition(new Position(diff.lineRangeMapping.modifiedRange.startLineNumber, 1));
this._modifiedEditor.revealRangeInCenter(diff.lineRangeMapping.modifiedRange.toExclusiveRange());
@@ -11,6 +11,7 @@ import { isIOS } from 'vs/base/common/platform';
import { ThemeIcon } from 'vs/base/common/themables';
import { IEditorMouseEvent, MouseTargetType } from 'vs/editor/browser/editorBrowser';
import { CodeEditorWidget } from 'vs/editor/browser/widget/codeEditorWidget';
import { DiffEditorWidget2 } from 'vs/editor/browser/widget/diffEditorWidget2/diffEditorWidget2';
import { EditorOption } from 'vs/editor/common/config/editorOptions';
import { LineRangeMapping } from 'vs/editor/common/diff/linesDiffComputer';
import { EndOfLineSequence, ITextModel } from 'vs/editor/common/model';
@@ -42,9 +43,10 @@ export class InlineDiffDeletedCodeMargin extends Disposable {
constructor(
private readonly _getViewZoneId: () => string,
private readonly _marginDomNode: HTMLElement,
private readonly editor: CodeEditorWidget,
private readonly diff: LineRangeMapping,
private readonly viewLineCounts: number[],
private readonly _modifiedEditor: CodeEditorWidget,
private readonly _diff: LineRangeMapping,
private readonly _editor: DiffEditorWidget2,
private readonly _viewLineCounts: number[],
private readonly _originalTextModel: ITextModel,
private readonly _contextMenuService: IContextMenuService,
private readonly _clipboardService: IClipboardService,
@@ -57,7 +59,7 @@ export class InlineDiffDeletedCodeMargin extends Disposable {
this._diffActions = document.createElement('div');
this._diffActions.className = ThemeIcon.asClassName(Codicon.lightBulb) + ' lightbulb-glyph';
this._diffActions.style.position = 'absolute';
const lineHeight = this.editor.getOption(EditorOption.lineHeight);
const lineHeight = this._modifiedEditor.getOption(EditorOption.lineHeight);
this._diffActions.style.right = '0px';
this._diffActions.style.visibility = 'hidden';
this._diffActions.style.height = `${lineHeight}px`;
@@ -65,38 +67,38 @@ export class InlineDiffDeletedCodeMargin extends Disposable {
this._marginDomNode.appendChild(this._diffActions);
const actions: Action[] = [];
const isDeletion = diff.modifiedRange.isEmpty;
const isDeletion = _diff.modifiedRange.isEmpty;
// default action
actions.push(new Action(
'diff.clipboard.copyDeletedContent',
isDeletion
? (diff.originalRange.length > 1
? (_diff.originalRange.length > 1
? localize('diff.clipboard.copyDeletedLinesContent.label', "Copy deleted lines")
: localize('diff.clipboard.copyDeletedLinesContent.single.label', "Copy deleted line"))
: (diff.originalRange.length > 1
: (_diff.originalRange.length > 1
? localize('diff.clipboard.copyChangedLinesContent.label', "Copy changed lines")
: localize('diff.clipboard.copyChangedLinesContent.single.label', "Copy changed line")),
undefined,
true,
async () => {
const originalText = this._originalTextModel.getValueInRange(diff.originalRange.toExclusiveRange());
const originalText = this._originalTextModel.getValueInRange(_diff.originalRange.toExclusiveRange());
await this._clipboardService.writeText(originalText);
}
));
let currentLineNumberOffset = 0;
let copyLineAction: Action | undefined = undefined;
if (diff.originalRange.length > 1) {
if (_diff.originalRange.length > 1) {
copyLineAction = new Action(
'diff.clipboard.copyDeletedLineContent',
isDeletion
? localize('diff.clipboard.copyDeletedLineContent.label', "Copy deleted line ({0})", diff.originalRange.startLineNumber)
: localize('diff.clipboard.copyChangedLineContent.label', "Copy changed line ({0})", diff.originalRange.startLineNumber),
? localize('diff.clipboard.copyDeletedLineContent.label', "Copy deleted line ({0})", _diff.originalRange.startLineNumber)
: localize('diff.clipboard.copyChangedLineContent.label', "Copy changed line ({0})", _diff.originalRange.startLineNumber),
undefined,
true,
async () => {
let lineContent = this._originalTextModel.getLineContent(diff.originalRange.startLineNumber + currentLineNumberOffset);
let lineContent = this._originalTextModel.getLineContent(_diff.originalRange.startLineNumber + currentLineNumberOffset);
if (lineContent === '') {
// empty line -> new line
const eof = this._originalTextModel.getEndOfLineSequence();
@@ -109,21 +111,18 @@ export class InlineDiffDeletedCodeMargin extends Disposable {
actions.push(copyLineAction);
}
const readOnly = editor.getOption(EditorOption.readOnly);
const readOnly = _modifiedEditor.getOption(EditorOption.readOnly);
if (!readOnly) {
actions.push(new Action('diff.inline.revertChange', localize('diff.inline.revertChange.label', "Revert this change"), undefined, true, async () => {
const originalText = this._originalTextModel.getValueInRange(this.diff.originalRange.toExclusiveRange());
editor.executeEdits('diffEditor', [
{ range: this.diff.modifiedRange.toExclusiveRange(), text: originalText }
]);
this._editor.revert(this._diff);
}));
}
const useShadowDOM = editor.getOption(EditorOption.useShadowDOM) && !isIOS; // Do not use shadow dom on IOS #122035
const useShadowDOM = _modifiedEditor.getOption(EditorOption.useShadowDOM) && !isIOS; // Do not use shadow dom on IOS #122035
const showContextMenu = (x: number, y: number) => {
this._contextMenuService.showContextMenu({
domForShadowRoot: useShadowDOM ? editor.getDomNode() ?? undefined : undefined,
domForShadowRoot: useShadowDOM ? _modifiedEditor.getDomNode() ?? undefined : undefined,
getAnchor: () => {
return {
x,
@@ -134,8 +133,8 @@ export class InlineDiffDeletedCodeMargin extends Disposable {
if (copyLineAction) {
copyLineAction.label =
isDeletion
? localize('diff.clipboard.copyDeletedLineContent.label', "Copy deleted line ({0})", diff.originalRange.startLineNumber + currentLineNumberOffset)
: localize('diff.clipboard.copyChangedLineContent.label', "Copy changed line ({0})", diff.originalRange.startLineNumber + currentLineNumberOffset);
? localize('diff.clipboard.copyDeletedLineContent.label', "Copy deleted line ({0})", _diff.originalRange.startLineNumber + currentLineNumberOffset)
: localize('diff.clipboard.copyChangedLineContent.label', "Copy changed line ({0})", _diff.originalRange.startLineNumber + currentLineNumberOffset);
}
return actions;
},
@@ -150,7 +149,7 @@ export class InlineDiffDeletedCodeMargin extends Disposable {
showContextMenu(e.posx, top + height + pad);
}));
this._register(editor.onMouseMove((e: IEditorMouseEvent) => {
this._register(_modifiedEditor.onMouseMove((e: IEditorMouseEvent) => {
if ((e.target.type === MouseTargetType.CONTENT_VIEW_ZONE || e.target.type === MouseTargetType.GUTTER_VIEW_ZONE) && e.target.detail.viewZoneId === this._getViewZoneId()) {
currentLineNumberOffset = this._updateLightBulbPosition(this._marginDomNode, e.event.browserEvent.y, lineHeight);
this.visibility = true;
@@ -159,7 +158,7 @@ export class InlineDiffDeletedCodeMargin extends Disposable {
}
}));
this._register(editor.onMouseDown((e: IEditorMouseEvent) => {
this._register(_modifiedEditor.onMouseDown((e: IEditorMouseEvent) => {
if (!e.event.rightButton) {
return;
}
@@ -182,10 +181,10 @@ export class InlineDiffDeletedCodeMargin extends Disposable {
const lineNumberOffset = Math.floor(offset / lineHeight);
const newTop = lineNumberOffset * lineHeight;
this._diffActions.style.top = `${newTop}px`;
if (this.viewLineCounts) {
if (this._viewLineCounts) {
let acc = 0;
for (let i = 0; i < this.viewLineCounts.length; i++) {
acc += this.viewLineCounts[i];
for (let i = 0; i < this._viewLineCounts.length; i++) {
acc += this._viewLineCounts[i];
if (lineNumberOffset < acc) {
return i;
}
@@ -3,7 +3,9 @@
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import { $ } from 'vs/base/browser/dom';
import { ArrayQueue } from 'vs/base/common/arrays';
import { Codicon } from 'vs/base/common/codicons';
import { Disposable, DisposableStore } from 'vs/base/common/lifecycle';
import { IObservable, derived, observableFromEvent, observableSignalFromEvent, observableValue } from 'vs/base/common/observable';
import { autorun, autorunWithStore2 } from 'vs/base/common/observableImpl/autorun';
@@ -14,6 +16,7 @@ import { IViewZone } from 'vs/editor/browser/editorBrowser';
import { StableEditorScrollState } from 'vs/editor/browser/stableEditorScroll';
import { CodeEditorWidget } from 'vs/editor/browser/widget/codeEditorWidget';
import { diffDeleteDecoration, diffRemoveIcon } from 'vs/editor/browser/widget/diffEditorWidget2/decorations';
import { DiffEditorWidget2 } from 'vs/editor/browser/widget/diffEditorWidget2/diffEditorWidget2';
import { DiffMapping, DiffModel } from 'vs/editor/browser/widget/diffEditorWidget2/diffModel';
import { InlineDiffDeletedCodeMargin } from 'vs/editor/browser/widget/diffEditorWidget2/inlineDiffDeletedCodeMargin';
import { LineSource, RenderOptions, renderLines } from 'vs/editor/browser/widget/diffEditorWidget2/renderLines';
@@ -49,6 +52,7 @@ export class ViewZoneManager extends Disposable {
private readonly _modifiedEditor: CodeEditorWidget,
private readonly _diffModel: IObservable<DiffModel | undefined>,
private readonly _renderSideBySide: IObservable<boolean>,
private readonly _diffEditorWidget: DiffEditorWidget2,
@IClipboardService private readonly _clipboardService: IClipboardService,
@IContextMenuService private readonly _contextMenuService: IContextMenuService,
) {
@@ -190,10 +194,11 @@ export class ViewZoneManager extends Disposable {
marginDomNode,
this._modifiedEditor,
a.diff,
this._diffEditorWidget,
result.viewLineCounts,
this._originalEditor.getModel()!,
this._contextMenuService,
this._clipboardService
this._clipboardService,
)
);
@@ -245,10 +250,22 @@ export class ViewZoneManager extends Disposable {
continue;
}
function createViewZoneMarginArrow(): HTMLElement {
const arrow = document.createElement('div');
arrow.className = 'arrow-revert-change ' + ThemeIcon.asClassName(Codicon.arrowRight);
return $('div', {}, arrow);
}
let marginDomNode: HTMLElement | undefined = undefined;
if (a.diff && a.diff.modifiedRange.isEmpty) {
marginDomNode = createViewZoneMarginArrow();
}
modViewZones.push({
afterLineNumber: a.modifiedRange.endLineNumberExclusive - 1,
domNode: createFakeLinesDiv(),
heightInPx: -delta,
marginDomNode,
});
}
}
@@ -97,6 +97,10 @@ export class CodeActionController extends Disposable implements IEditorContribut
return this.showCodeActionList(actions, at, { includeDisabledActions: false, fromLightbulb: false });
}
public hideCodeActions(): void {
this._actionWidgetService.hide();
}
public manualTriggerAtCurrentPosition(
notAvailableMessage: string,
triggerAction: CodeActionTriggerSource,
@@ -126,6 +130,10 @@ export class CodeActionController extends Disposable implements IEditorContribut
}
}
public hideLightBulbWidget(): void {
this._lightBulbWidget.rawValue?.hide();
}
private async update(newState: CodeActionsState.State): Promise<void> {
if (newState.type !== CodeActionsState.Type.Triggered) {
this._lightBulbWidget.rawValue?.hide();
@@ -332,6 +332,7 @@ export class SuggestController implements IEditorContribution {
// keep item in memory
this._memoryService.memorize(model, this.editor.getPosition(), item);
const isResolved = item.isResolved;
if (Array.isArray(item.completion.additionalTextEdits)) {
@@ -346,7 +347,7 @@ export class SuggestController implements IEditorContribution {
);
scrollState.restoreRelativeVerticalPositionOfCursor(this.editor);
} else if (!item.isResolved) {
} else if (!isResolved) {
// async additional edits
const sw = new StopWatch(true);
let position: IPosition | undefined;
@@ -378,7 +379,7 @@ export class SuggestController implements IEditorContribution {
tasks.push(item.resolve(cts.token).then(() => {
if (!item.completion.additionalTextEdits || cts.token.isCancellationRequested) {
return false;
return undefined;
}
if (position && item.completion.additionalTextEdits.some(edit => Position.isBefore(position!, Range.getStartPosition(edit.range)))) {
return false;
@@ -398,6 +399,20 @@ export class SuggestController implements IEditorContribution {
return true;
}).then(applied => {
this._logService.trace('[suggest] async resolving of edits DONE (ms, applied?)', sw.elapsed(), applied);
type AsyncSuggestEdits = { providerId: string; applied: boolean };
type AsyncSuggestEditsClassification = {
owner: 'jrieken';
comment: 'Information about async additional text edits';
providerId: { classification: 'PublicNonPersonalData'; purpose: 'FeatureInsight'; comment: 'Provider of the completions item' };
applied: { classification: 'SystemMetaData'; purpose: 'FeatureInsight'; isMeasurement: true; comment: 'If async additional text edits could be applied' };
};
if (typeof applied === 'boolean') {
this._telemetryService.publicLog2<AsyncSuggestEdits, AsyncSuggestEditsClassification>('suggest.asyncAdditionalEdits', {
providerId: item.extensionId?.value ?? 'unknown',
applied
});
}
}).finally(() => {
docListener.dispose();
typeListener.dispose();
}));
@@ -467,7 +482,7 @@ export class SuggestController implements IEditorContribution {
// clear only now - after all tasks are done
Promise.all(tasks).finally(() => {
this._reportSuggestionAcceptedTelemetry(item, model, event);
this._reportSuggestionAcceptedTelemetry(item, model, event, isResolved);
this.model.clear();
cts.dispose();
@@ -475,12 +490,12 @@ export class SuggestController implements IEditorContribution {
}
private _telemetryGate: number = 0;
private _reportSuggestionAcceptedTelemetry(item: CompletionItem, model: ITextModel, acceptedSuggestion: ISelectedSuggestion) {
private _reportSuggestionAcceptedTelemetry(item: CompletionItem, model: ITextModel, acceptedSuggestion: ISelectedSuggestion, itemResolved: boolean) {
if (this._telemetryGate++ % 100 !== 0) {
return;
}
type AcceptedSuggestion = { providerId: string; fileExtension: string; languageId: string; basenameHash: string; kind: number };
type AcceptedSuggestion = { providerId: string; fileExtension: string; languageId: string; basenameHash: string; kind: number; itemResolved: boolean };
type AcceptedSuggestionClassification = {
owner: 'jrieken';
comment: 'Information accepting completion items';
@@ -488,7 +503,8 @@ export class SuggestController implements IEditorContribution {
basenameHash: { classification: 'PublicNonPersonalData'; purpose: 'FeatureInsight'; comment: 'Hash of the basename of the file into which the completion was inserted' };
fileExtension: { classification: 'SystemMetaData'; purpose: 'FeatureInsight'; comment: 'File extension of the file into which the completion was inserted' };
languageId: { classification: 'SystemMetaData'; purpose: 'FeatureInsight'; comment: 'Language type of the file into which the completion was inserted' };
kind: { classification: 'SystemMetaData'; purpose: 'FeatureInsight'; comment: 'The completion item kind' };
kind: { classification: 'SystemMetaData'; purpose: 'FeatureInsight'; isMeasurement: true; comment: 'The completion item kind' };
itemResolved: { classification: 'SystemMetaData'; purpose: 'FeatureInsight'; isMeasurement: true; comment: 'If the item was inserted before resolving was done' };
};
// _debugDisplayName looks like `vscode.css-language-features(/-:)`, where the last bit is the trigger chars
// normalize it to just the extension ID and lowercase
@@ -499,6 +515,7 @@ export class SuggestController implements IEditorContribution {
basenameHash: hash(basename(model.uri)).toString(16),
languageId: model.getLanguageId(),
fileExtension: extname(model.uri),
itemResolved
});
}
@@ -121,7 +121,12 @@ function doCreateTest(description: string, inputStr: string, expectedStr: string
}
};
const handler = new TextAreaInput(textAreaInputHost, new TextAreaWrapper(input), platform.OS, browser);
const handler = new TextAreaInput(textAreaInputHost, new TextAreaWrapper(input), platform.OS, {
isAndroid: browser.isAndroid,
isFirefox: browser.isFirefox,
isChrome: browser.isChrome,
isSafari: browser.isSafari,
});
const output = document.createElement('pre');
output.className = 'output';
+12
View File
@@ -123,6 +123,9 @@ export function localize(info: ILocalizeInfo, message: string, ...args: (string
*/
export function localize(key: string, message: string, ...args: (string | number | boolean | undefined | null)[]): string;
/**
* @skipMangle
*/
export function localize(data: ILocalizeInfo | string, message: string, ...args: (string | number | boolean | undefined | null)[]): string {
return _format(message, args);
}
@@ -133,18 +136,25 @@ export function localize(data: ILocalizeInfo | string, message: string, ...args:
* in order to ensure the loader plugin has been initialized before this function is called.
*/
export function getConfiguredDefaultLocale(stringFromLocalizeCall: string): string | undefined;
/**
* @skipMangle
*/
export function getConfiguredDefaultLocale(_: string): string | undefined {
// This returns undefined because this implementation isn't used and is overwritten by the loader
// when loaded.
return undefined;
}
/**
* @skipMangle
*/
export function setPseudoTranslation(value: boolean) {
isPseudo = value;
}
/**
* Invoked in a built product at run-time
* @skipMangle
*/
export function create(key: string, data: IBundledStrings & IConsumerAPI): IConsumerAPI {
return {
@@ -155,10 +165,12 @@ export function create(key: string, data: IBundledStrings & IConsumerAPI): ICons
/**
* Invoked by the loader at run-time
* @skipMangle
*/
export function load(name: string, req: AMDLoader.IRelativeRequire, load: AMDLoader.IPluginLoadCallback, config: AMDLoader.IConfigurationOptions): void {
const pluginConfig: INLSPluginConfig = config['vs/nls'] ?? {};
if (!name || name.length === 0) {
// TODO: We need to give back the mangled names here
return load({
localize: localize,
getConfiguredDefaultLocale: () => pluginConfig.availableLanguages?.['*']
@@ -11,7 +11,6 @@ import { IV8Profile, Utils } from 'vs/platform/profiling/common/profiling';
import { IProfileModel, BottomUpSample, buildModel, BottomUpNode, processNode, CdpCallFrame } from 'vs/platform/profiling/common/profilingModel';
import { BottomUpAnalysis, IProfileAnalysisWorker, ProfilingOutput } from 'vs/platform/profiling/electron-sandbox/profileAnalysisWorkerService';
export function create(): IRequestHandler {
return new ProfileAnalysisWorker();
}
@@ -7,7 +7,7 @@ import { URI, UriComponents } from 'vs/base/common/uri';
import { mixin } from 'vs/base/common/objects';
import type * as vscode from 'vscode';
import * as typeConvert from 'vs/workbench/api/common/extHostTypeConverters';
import { Range, Disposable, CompletionList, SnippetString, CodeActionKind, SymbolInformation, DocumentSymbol, SemanticTokensEdits, SemanticTokens, SemanticTokensEdit, Location, InlineCompletionTriggerKind, InternalDataTransferItem } from 'vs/workbench/api/common/extHostTypes';
import { Range, Disposable, CompletionList, SnippetString, CodeActionKind, SymbolInformation, DocumentSymbol, SemanticTokensEdits, SemanticTokens, SemanticTokensEdit, Location, InlineCompletionTriggerKind, InternalDataTransferItem, CodeActionTriggerKind } from 'vs/workbench/api/common/extHostTypes';
import { ISingleEditOperation } from 'vs/editor/common/core/editOperation';
import * as languages from 'vs/editor/common/languages';
import { ExtHostDocuments } from 'vs/workbench/api/common/extHostDocuments';
@@ -376,6 +376,7 @@ class CodeActionAdapter {
private readonly _cache = new Cache<vscode.CodeAction | vscode.Command>('CodeAction');
private readonly _disposables = new Map<number, DisposableStore>();
private readonly nbKind = new CodeActionKind('notebook');
constructor(
private readonly _documents: ExtHostDocuments,
@@ -414,6 +415,7 @@ class CodeActionAdapter {
if (!isNonEmptyArray(commandsOrActions) || token.isCancellationRequested) {
return undefined;
}
const cacheId = this._cache.add(commandsOrActions);
const disposables = new DisposableStore();
this._disposables.set(cacheId, disposables);
@@ -434,6 +436,10 @@ class CodeActionAdapter {
command: this._commands.toInternal(candidate, disposables),
});
} else {
if (codeActionContext.triggerKind !== CodeActionTriggerKind.Invoke && candidate.kind && this.nbKind.contains(candidate.kind)) {
continue;
}
if (codeActionContext.only) {
if (!candidate.kind) {
this._logService.warn(`${this._extension.identifier.value} - Code actions of kind '${codeActionContext.only.value} 'requested but returned code action does not have a 'kind'. Code action will be dropped. Please set 'CodeAction.kind'.`);
@@ -1040,7 +1046,7 @@ class CompletionsAdapter {
additionalTextEdits: resolvedItem.additionalTextEdits
};
if (item.insertText !== resolvedItem.insertText) {
if (CompletionsAdapter._insertTextIdent(item.insertText) !== CompletionsAdapter._insertTextIdent(resolvedItem.insertText)) {
this._apiDeprecation.report('CompletionItem.insertText', this._extension, 'extension MAY NOT change \'insertText\' of a CompletionItem during resolve');
enforcedResolvedItem.insertText = resolvedItem.insertText;
}
@@ -1048,6 +1054,14 @@ class CompletionsAdapter {
return this._convertCompletionItem(enforcedResolvedItem, id);
}
private static _insertTextIdent(insertText: string | vscode.SnippetString | undefined) {
switch (typeof insertText) {
case 'string': return insertText;
case 'undefined': return undefined;
case 'object': return insertText.value;
}
}
releaseCompletionItems(id: number): any {
this._disposables.get(id)?.dispose();
this._disposables.delete(id);
@@ -22,7 +22,14 @@ import { getSimpleEditorOptions } from 'vs/workbench/contrib/codeEditor/browser/
import { IDisposable } from 'xterm';
export interface IAccessibleContentProvider { id: string; provideContent(): string; onClose(): void; onKeyDown?(e: IKeyboardEvent): void; options: IAccessibleViewOptions }
export interface IAccessibleContentProvider {
id: string;
provideContent(): string;
onClose(): void;
onKeyDown?(e: IKeyboardEvent): void;
options: IAccessibleViewOptions;
}
export const IAccessibleViewService = createDecorator<IAccessibleViewService>('accessibleViewService');
export interface IAccessibleViewService {
@@ -96,12 +103,13 @@ class AccessibleView extends Disposable {
if (!domNode) {
return;
}
container.appendChild(domNode);
container.appendChild(this._editorContainer);
this._layout();
this._register(this._editorWidget.onKeyDown((e) => {
this._register(this._editorWidget.onKeyUp((e) => {
if (e.keyCode === KeyCode.Escape) {
this._contextViewService.hideContextView();
}
e.stopPropagation();
provider.onKeyDown?.(e);
}));
this._register(this._editorWidget.onDidBlurEditorText(() => this._contextViewService.hideContextView()));
@@ -113,11 +121,6 @@ class AccessibleView extends Disposable {
}
private _layout(): void {
const domNode = this._editorWidget.getDomNode();
if (!domNode) {
return;
}
const windowWidth = window.innerWidth;
const windowHeight = window.innerHeight;
@@ -125,9 +128,9 @@ class AccessibleView extends Disposable {
const height = Math.min(.4 * windowHeight, this._editorWidget.getContentHeight());
this._editorWidget.layout({ width, height });
const top = Math.round((windowHeight - height) / 2);
domNode.style.top = `${top}px`;
this._editorContainer.style.top = `${top}px`;
const left = Math.round((windowWidth - width) / 2);
domNode.style.left = `${left}px`;
this._editorContainer.style.left = `${left}px`;
}
private async _getTextModel(resource: URI): Promise<ITextModel | null> {
@@ -10,40 +10,30 @@ import { withNullAsUndefined } from 'vs/base/common/types';
import { ICodeEditor } from 'vs/editor/browser/editorBrowser';
import { ServicesAccessor } from 'vs/editor/browser/editorExtensions';
import { IChatWidgetService } from 'vs/workbench/contrib/chat/browser/chat';
import { IConfigurationService } from 'vs/platform/configuration/common/configuration';
import { EditMode } from 'vs/workbench/contrib/inlineChat/common/inlineChat';
import { IAccessibleViewService } from 'vs/workbench/contrib/accessibility/browser/accessibleView';
import { InlineChatController } from 'vs/workbench/contrib/inlineChat/browser/inlineChatController';
export function getAccessibilityHelpText(accessor: ServicesAccessor, type: 'chat' | 'inline', currentInput?: string): string {
export function getAccessibilityHelpText(accessor: ServicesAccessor, type: 'chat' | 'inline'): string {
const keybindingService = accessor.get(IKeybindingService);
const configurationService = accessor.get(IConfigurationService);
const content = [];
if (type === 'chat') {
content.push(localize('chat.overview', 'Chat responses will be announced as they come in. A response will indicate the number of code blocks, if any, and then the rest of the response.'));
content.push(localize('chat.requestHistory', 'In the input box, use UpArrow/DownArrow to navigate your request history. Edit input and use enter to run a new request.'));
content.push(localize('chat.requestHistory', 'In the input box, use up and down arrows to navigate your request history. Edit input and use enter to run a new request.'));
content.push(descriptionForCommand('chat.action.focus', localize('workbench.action.chat.focus', 'The Focus Chat command ({0}) focuses the chat request/response list, which can be navigated with UpArrow/DownArrow.',), localize('workbench.action.chat.focusNoKb', 'The Focus Chat List command focuses the chat request/response list, which can be navigated with UpArrow/DownArrow and is currently not triggerable by a keybinding.'), keybindingService));
content.push(descriptionForCommand('workbench.action.chat.focusInput', localize('workbench.action.chat.focusInput', 'The Focus Chat Input command ({0}) focuses the input box for chat requests.'), localize('workbench.action.interactiveSession.focusInputNoKb', 'Focus Chat Input command focuses the input box for chat requests and is currently not triggerable by a keybinding.'), keybindingService));
content.push(descriptionForCommand('workbench.action.chat.nextCodeBlock', localize('workbench.action.chat.nextCodeBlock', 'The Chat: Next Code Block command ({0}) focuses the next code block within a response.'), localize('workbench.action.chat.nextCodeBlockNoKb', 'The Chat: Next Code Block command focuses the next code block within a response and is currently not triggerable by a keybinding.'), keybindingService));
content.push(descriptionForCommand('workbench.action.chat.clear', localize('workbench.action.chat.clear', 'The Chat Clear command ({0}) clears the request/response list.'), localize('workbench.action.chat.clearNoKb', 'The Chat Clear command clears the request/response list and is currently not triggerable by a keybinding.'), keybindingService));
} else {
content.push(localize('inlineChat.makeRequest', "Tab once to reach the make request button, which will re-run the request."));
const regex = /^(\/fix|\/explain)/;
const match = currentInput?.match(regex);
const command = match && match.length ? match[0].substring(1) : undefined;
if (command === 'fix') {
const editMode = configurationService.getValue('inlineChat.mode');
if (editMode === EditMode.Preview) {
const keybinding = keybindingService.lookupKeybinding('editor.action.diffReview.next')?.getAriaLabel();
content.push(keybinding ? localize('inlineChat.diff', "Tab again to enter the Diff editor with the changes and enter review mode with ({0}). Use Up/DownArrow to navigate lines with the proposed changes.", keybinding) : localize('inlineChat.diffNoKb', "Tab again to enter the Diff editor with the changes and enter review mode with the Go to Next Difference Command. Use Up/DownArrow to navigate lines with the proposed changes."));
content.push(localize('inlineChat.acceptReject', "Tab again to reach the action bar, which can be navigated with Left/RightArrow."));
}
} else if (command === 'explain') {
content.push(localize('inlineChat.explain', "/explain commands will be run in the chat view."));
content.push(localize('inlineChat.chatViewFocus', "To focus the chat view, run the GitHub Copilot: Focus on GitHub Copilot View command, which will focus the input box."));
} else {
content.push(localize('inlineChat.toolbar', "Use tab to reach conditional parts like commands, status message, message responses and more."));
}
const startChatKeybinding = keybindingService.lookupKeybinding('inlineChat.start')?.getAriaLabel();
content.push(localize('inlineChat.overview', "Inline chat occurs within a code editor and takes into account current selection. It is useful for refactoring, fixing, and more. Keep in mind that Copilot generated code may be incorrect."));
content.push(localize('inlineChat.access', "It can be activated via the Fix and Explain with Copilot context menu actions or directly using the command: Inline Chat: Start Code Chat ({0}).", startChatKeybinding));
content.push(localize('chat.requestHistoryInline', 'In the input box, use up and down arrows to navigate your request history. Edit input and use enter or the make request button to run a new request.'));
content.push(localize('inlineChat.contextActions', "Explain and Fix with Copilot actions run a request prefixed with /fix or /explain. These prefixes can be used directly in the input box to apply those specific actions."));
content.push(localize('inlineChat.fix', "When a request is prefixed with /fix, a response will indicate the problem with the current code. A diff editor will be rendered and can be reached by tabbing."));
const diffReviewKeybinding = keybindingService.lookupKeybinding('editor.action.diffReview.next')?.getAriaLabel();
content.push(diffReviewKeybinding ? localize('inlineChat.diff', "Once in the diff editor, enter review mode with ({0}). Use up and down arrows to navigate lines with the proposed changes.", diffReviewKeybinding) : localize('inlineChat.diffNoKb', "Tab again to enter the Diff editor with the changes and enter review mode with the Go to Next Difference Command. Use Up/DownArrow to navigate lines with the proposed changes."));
content.push(localize('inlineChat.explain', "When a request is prefixed with /explain, a response will explain the code in the current selection and the chat view will be focused."));
content.push(localize('inlineChat.toolbar', "Use tab to reach conditional parts like commands, status, message responses and more."));
}
return content.join('\n');
}
@@ -70,10 +60,9 @@ export async function runAccessibilityHelpAction(accessor: ServicesAccessor, edi
return;
}
const cachedInput = inputEditor.getValue();
const cachedPosition = inputEditor.getPosition();
inputEditor.getSupportedActions();
const helpText = getAccessibilityHelpText(accessor, type, type === 'inline' ? cachedInput : undefined);
const helpText = getAccessibilityHelpText(accessor, type);
const provider = accessibleViewService.registerProvider({
id: type,
provideContent: () => helpText,
@@ -88,7 +88,6 @@ export interface IChatRendererDelegate {
}
export class ChatListItemRenderer extends Disposable implements ITreeRenderer<ChatTreeItem, FuzzyScore, IChatListItemTemplate> {
static readonly cursorCharacter = '\u258c';
static readonly ID = 'item';
private readonly codeBlocksByResponseId = new Map<string, IChatCodeBlockInfo[]>();
@@ -368,12 +367,7 @@ export class ChatListItemRenderer extends Disposable implements ITreeRenderer<Ch
isFullyRendered: renderValue.isFullString
};
// Don't add the cursor if it will go after a codeblock, since this will always cause layout shifting
// when the codeblock is the last thing in the response, and that happens often.
const plusCursor = renderValue.value.match(/```\s*$/) ?
renderValue.value :
renderValue.value + ` ${ChatListItemRenderer.cursorCharacter}`;
const result = this.renderMarkdown(new MarkdownString(plusCursor), element, disposables, templateData, true);
const result = this.renderMarkdown(new MarkdownString(renderValue.value), element, disposables, templateData, true);
// Doing the progressive render
dom.clearNode(templateData.value);
templateData.value.appendChild(result.element);
@@ -754,28 +748,16 @@ class CodeBlockPart extends Disposable implements IChatResultCodeBlockPart {
}
private setText(newText: string): void {
let currentText = this.textModel.getLinesContent().join('\n');
const currentText = this.textModel.getLinesContent().join('\n');
if (newText === currentText) {
return;
}
let removedChars = 0;
if (currentText.endsWith(` ${ChatListItemRenderer.cursorCharacter}`)) {
removedChars = 2;
} else if (currentText.endsWith(ChatListItemRenderer.cursorCharacter)) {
removedChars = 1;
}
if (removedChars > 0) {
currentText = currentText.slice(0, currentText.length - removedChars);
}
if (newText.startsWith(currentText)) {
const text = newText.slice(currentText.length);
const lastLine = this.textModel.getLineCount();
const lastCol = this.textModel.getLineMaxColumn(lastLine);
const insertAtCol = lastCol - removedChars;
this.textModel.applyEdits([{ range: new Range(lastLine, insertAtCol, lastLine, lastCol), text }]);
this.textModel.applyEdits([{ range: new Range(lastLine, lastCol, lastLine, lastCol), text }]);
} else {
// console.log(`Failed to optimize setText`);
this.textModel.setValue(newText);
@@ -3,12 +3,10 @@
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
.monaco-editor .accessibilityHelpWidget {
padding: 10px;
vertical-align: middle;
overflow: auto;
.accessible-view {
position: relative;
background-color: var(--vscode-editorWidget-background);
color: var(--vscode-editorWidget-foreground);
box-shadow: 0 2px 8px var(--vscode-widget-shadow);
border: 2px solid var(--vscode-contrastBorder);
border: 2px solid var(--vscode-contrastActiveBorder);
}
@@ -753,7 +753,7 @@ export class Repl extends FilterViewPane implements IHistoryNavigationWidget {
}
override dispose(): void {
this.replInput.dispose();
this.replInput?.dispose(); // Disposed before rendered? #174558
this.replElementsChangeListener?.dispose();
this.refreshScheduler.dispose();
this.modelChangeListener.dispose();
@@ -528,7 +528,7 @@ export class Thread implements IThread {
const firstAvailableStackFrame = callStack.find(sf => !!(sf &&
((this.stoppedDetails?.reason === 'instruction breakpoint' || (this.stoppedDetails?.reason === 'step' && this.lastSteppingGranularity === 'instruction')) && sf.instructionPointerReference) ||
(sf.source && sf.source.available && sf.source.presentationHint !== 'deemphasize')));
return firstAvailableStackFrame || (callStack.length > 0 ? callStack[0] : undefined);
return firstAvailableStackFrame;
}
get stateLabel(): string {
@@ -280,7 +280,7 @@ class CodeActionOnSaveParticipant implements IStoredFileWorkingCopySaveParticipa
private getActionsToRun(model: ITextModel, codeActionKind: CodeActionKind, excludes: readonly CodeActionKind[], progress: IProgress<CodeActionProvider>, token: CancellationToken) {
return getCodeActions(this.languageFeaturesService.codeActionProvider, model, model.getFullModelRange(), {
type: CodeActionTriggerType.Auto,
type: CodeActionTriggerType.Invoke,
triggerAction: CodeActionTriggerSource.OnSave,
filter: { include: codeActionKind, excludes: excludes, includeSourceActions: true },
}, progress, token);
@@ -30,6 +30,7 @@ import { CodeCellRenderTemplate } from 'vs/workbench/contrib/notebook/browser/vi
import { CodeCellViewModel, outputDisplayLimit } from 'vs/workbench/contrib/notebook/browser/viewModel/codeCellViewModel';
import { INotebookExecutionStateService } from 'vs/workbench/contrib/notebook/common/notebookExecutionStateService';
import { WordHighlighterContribution } from 'vs/editor/contrib/wordHighlighter/browser/wordHighlighter';
import { CodeActionController } from 'vs/editor/contrib/codeAction/browser/codeActionController';
export class CodeCell extends Disposable {
private _outputContainerRenderer: CellOutputContainer;
@@ -267,6 +268,8 @@ export class CodeCell extends Disposable {
this._register(this.templateData.editor.onDidBlurEditorWidget(() => {
WordHighlighterContribution.get(this.templateData.editor)?.stopHighlighting();
CodeActionController.get(this.templateData.editor)?.hideCodeActions();
CodeActionController.get(this.templateData.editor)?.hideLightBulbWidget();
}));
this._register(this.templateData.editor.onDidFocusEditorWidget(() => {
WordHighlighterContribution.get(this.templateData.editor)?.restoreViewState(true);
@@ -31,6 +31,7 @@ import { IExternalUriOpenerService } from 'vs/workbench/contrib/externalUriOpene
import { IHostService } from 'vs/workbench/services/host/browser/host';
import { IConfigurationRegistry, Extensions as ConfigurationExtensions } from 'vs/platform/configuration/common/configurationRegistry';
import { ILogService } from 'vs/platform/log/common/log';
import { IWorkbenchConfigurationService } from 'vs/workbench/services/configuration/common/configuration';
export const VIEWLET_ID = 'workbench.view.remote';
@@ -181,7 +182,7 @@ export class AutomaticPortForwarding extends Disposable implements IWorkbenchCon
@IRemoteExplorerService remoteExplorerService: IRemoteExplorerService,
@IWorkbenchEnvironmentService environmentService: IWorkbenchEnvironmentService,
@IContextKeyService contextKeyService: IContextKeyService,
@IConfigurationService configurationService: IConfigurationService,
@IWorkbenchConfigurationService configurationService: IWorkbenchConfigurationService,
@IDebugService debugService: IDebugService,
@IRemoteAgentService remoteAgentService: IRemoteAgentService,
@ITunnelService tunnelService: ITunnelService,
@@ -193,7 +194,7 @@ export class AutomaticPortForwarding extends Disposable implements IWorkbenchCon
return;
}
remoteAgentService.getEnvironment().then(environment => {
configurationService.whenRemoteConfigurationLoaded().then(() => remoteAgentService.getEnvironment()).then(environment => {
if (environment?.os !== OperatingSystem.Linux) {
Registry.as<IConfigurationRegistry>(ConfigurationExtensions.Configuration)
.registerDefaultConfigurations([{ overrides: { 'remote.autoForwardPortsSource': PORT_AUTO_SOURCE_SETTING_OUTPUT } }]);
@@ -404,18 +404,20 @@ export class XtermTerminal extends DisposableStore implements IXtermTerminal, II
};
}
private async _getSearchAddon(): Promise<SearchAddonType> {
if (this._searchAddon) {
return this._searchAddon;
private _searchAddonPromise: Promise<SearchAddonType> | undefined;
private _getSearchAddon(): Promise<SearchAddonType> {
if (!this._searchAddonPromise) {
this._searchAddonPromise = this._getSearchAddonConstructor().then((AddonCtor) => {
this._searchAddon = new AddonCtor({ highlightLimit: XtermTerminalConstants.SearchHighlightLimit });
this.raw.loadAddon(this._searchAddon);
this._searchAddon.onDidChangeResults((results: { resultIndex: number; resultCount: number }) => {
this._lastFindResult = results;
this._onDidChangeFindResults.fire(results);
});
return this._searchAddon;
});
}
const AddonCtor = await this._getSearchAddonConstructor();
this._searchAddon = new AddonCtor({ highlightLimit: XtermTerminalConstants.SearchHighlightLimit });
this.raw.loadAddon(this._searchAddon);
this._searchAddon.onDidChangeResults((results: { resultIndex: number; resultCount: number }) => {
this._lastFindResult = results;
this._onDidChangeFindResults.fire(results);
});
return this._searchAddon;
return this._searchAddonPromise;
}
clearSearchDecorations(): void {
@@ -6,14 +6,15 @@
border-radius: 6px;
}
.welcome-widget {
height: min-content;
border-radius: 6px;
.dialog-message-detail-title > div > p > .codicon[class*='codicon-']::before{
position: relative;
color: var(--vscode-textLink-foreground);
padding-right: 10px;
font-size: larger;
}
.dialog-message-detail-title {
height: 22px;
padding-bottom: 4px;
font-size: large;
}
@@ -23,7 +23,6 @@ import { INotificationService } from 'vs/platform/notification/common/notificati
import { IExtensionService } from 'vs/workbench/services/extensions/common/extensions';
import { LanguageService } from 'vs/editor/common/services/languageService';
import { ILanguageService } from 'vs/editor/common/languages/language';
import { GettingStartedDetailsRenderer } from 'vs/workbench/contrib/welcomeGettingStarted/browser/gettingStartedDetailsRenderer';
import { IConfigurationRegistry, Extensions as ConfigurationExtensions, ConfigurationScope } from 'vs/platform/configuration/common/configurationRegistry';
import { localize } from 'vs/nls';
import { applicationConfigurationNodeBase } from 'vs/workbench/common/configuration';
@@ -77,22 +76,18 @@ class WelcomeDialogContribution extends Disposable implements IWorkbenchContribu
const scheduler = new RunOnceScheduler(() => {
if (codeEditor === codeEditorService.getActiveCodeEditor()) {
this.isRendered = true;
const detailsRenderer = new GettingStartedDetailsRenderer(fileService, notificationService, extensionService, languageService);
const welcomeWidget = new WelcomeWidget(
codeEditor,
instantiationService,
commandService,
telemetryService,
openerService,
webviewService,
detailsRenderer);
openerService);
welcomeWidget.render(welcomeDialog.title,
welcomeDialog.message,
welcomeDialog.buttonText,
welcomeDialog.buttonCommand,
welcomeDialog.media);
welcomeDialog.buttonCommand);
}
}, 3000);
@@ -6,14 +6,14 @@
import 'vs/css!./media/welcomeWidget';
import { Disposable } from 'vs/base/common/lifecycle';
import { ICodeEditor, IOverlayWidget, IOverlayWidgetPosition, OverlayWidgetPositionPreference } from 'vs/editor/browser/editorBrowser';
import { $, append, hide } from 'vs/base/browser/dom'; import { RunOnceScheduler } from 'vs/base/common/async';
import { $, append, hide } from 'vs/base/browser/dom';
import { MarkdownString } from 'vs/base/common/htmlContent';
import { MarkdownRenderer } from 'vs/editor/contrib/markdownRenderer/browser/markdownRenderer';
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
import { ButtonBar } from 'vs/base/browser/ui/button/button';
import { mnemonicButtonLabel } from 'vs/base/common/labels';
import { ICommandService } from 'vs/platform/commands/common/commands';
import { defaultButtonStyles, defaultDialogStyles } from 'vs/platform/theme/browser/defaultStyles';
import { defaultButtonStyles } from 'vs/platform/theme/browser/defaultStyles';
import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry';
import { Action, WorkbenchActionExecutedClassification, WorkbenchActionExecutedEvent } from 'vs/base/common/actions';
import { ActionBar } from 'vs/base/browser/ui/actionbar/actionbar';
@@ -25,16 +25,12 @@ import { Link } from 'vs/platform/opener/browser/link';
import { renderLabelWithIcons } from 'vs/base/browser/ui/iconLabel/iconLabels';
import { renderFormattedText } from 'vs/base/browser/formattedTextRenderer';
import { IOpenerService } from 'vs/platform/opener/common/opener';
import { generateUuid } from 'vs/base/common/uuid';
import { GettingStartedDetailsRenderer } from 'vs/workbench/contrib/welcomeGettingStarted/browser/gettingStartedDetailsRenderer';
import { FileAccess } from 'vs/base/common/network';
import { IWebviewService } from 'vs/workbench/contrib/webview/browser/webview';
import { registerThemingParticipant } from 'vs/platform/theme/common/themeService';
import { Color } from 'vs/base/common/color';
import { contrastBorder, editorWidgetBackground, editorWidgetForeground, widgetBorder, widgetShadow } from 'vs/platform/theme/common/colorRegistry';
export class WelcomeWidget extends Disposable implements IOverlayWidget {
private static readonly WIDGET_TIMEOUT: number = 15000;
private static readonly WELCOME_MEDIA_PATH = 'vs/workbench/contrib/welcomeGettingStarted/common/media/';
private readonly _rootDomNode: HTMLElement;
private readonly element: HTMLElement;
private readonly messageContainer: HTMLElement;
@@ -45,9 +41,7 @@ export class WelcomeWidget extends Disposable implements IOverlayWidget {
private readonly instantiationService: IInstantiationService,
private readonly commandService: ICommandService,
private readonly telemetryService: ITelemetryService,
private readonly openerService: IOpenerService,
private readonly webviewService: IWebviewService,
private readonly detailsRenderer: GettingStartedDetailsRenderer
private readonly openerService: IOpenerService
) {
super();
this._rootDomNode = document.createElement('div');
@@ -64,7 +58,6 @@ export class WelcomeWidget extends Disposable implements IOverlayWidget {
async executeCommand(commandId: string, ...args: string[]) {
try {
await this.commandService.executeCommand(commandId, ...args);
this._hide(false);
this.telemetryService.publicLog2<WorkbenchActionExecutedEvent, WorkbenchActionExecutedClassification>('workbenchActionExecuted', {
id: commandId,
from: 'welcomeWidget'
@@ -74,41 +67,38 @@ export class WelcomeWidget extends Disposable implements IOverlayWidget {
}
}
public async render(title: string, message: string, buttonText: string, buttonAction: string, media: { altText: string; path: string }) {
public async render(title: string, message: string, buttonText: string, buttonAction: string) {
if (!this._editor._getViewModel()) {
return;
}
await this.buildWidgetContent(title, message, buttonText, buttonAction, media);
await this.buildWidgetContent(title, message, buttonText, buttonAction);
this._editor.addOverlayWidget(this);
this._revealTemporarily();
this._show();
this.telemetryService.publicLog2<WorkbenchActionExecutedEvent, WorkbenchActionExecutedClassification>('workbenchActionExecuted', {
id: 'welcomeWidgetRendered',
from: 'welcomeWidget'
});
}
private async buildWidgetContent(title: string, message: string, buttonText: string, buttonAction: string, media: { altText: string; path: string }) {
private async buildWidgetContent(title: string, message: string, buttonText: string, buttonAction: string) {
const actionBar = this._register(new ActionBar(this.element, {}));
const action = this._register(new Action('dialog.close', localize('dialogClose', "Close Dialog"), ThemeIcon.asClassName(Codicon.dialogClose), true, async () => {
this._hide(true);
this._hide();
}));
actionBar.push(action, { icon: true, label: false });
if (media) {
await this.buildSVGMediaComponent(media.path);
}
const renderBody = (message: string): MarkdownString => {
const mds = new MarkdownString(undefined, { supportHtml: true });
const renderBody = (message: string, icon: string): MarkdownString => {
const mds = new MarkdownString(undefined, { supportThemeIcons: true, supportHtml: true });
mds.appendMarkdown(`<a class="copilot">$(${icon})</a>`);
mds.appendMarkdown(message);
return mds;
};
const titleElement = this.messageContainer.appendChild($('#monaco-dialog-message-detail.dialog-message-detail-title'));
const titleElementMdt = this.markdownRenderer.render(renderBody(title));
const titleElementMdt = this.markdownRenderer.render(renderBody(title, 'zap'));
titleElement.appendChild(titleElementMdt.element);
this.buildStepMarkdownDescription(this.messageContainer, message.split('\n').filter(x => x).map(text => parseLinkedText(text)));
@@ -125,7 +115,6 @@ export class WelcomeWidget extends Disposable implements IOverlayWidget {
}));
buttonBar.buttons[0].focus();
this.applyStyles();
}
private buildStepMarkdownDescription(container: HTMLElement, text: LinkedText[]) {
@@ -158,18 +147,6 @@ export class WelcomeWidget extends Disposable implements IOverlayWidget {
return container;
}
private async buildSVGMediaComponent(path: string) {
const mediaContainer = this.messageContainer.appendChild($('.dialog-image-container'));
mediaContainer.id = generateUuid();
const webview = this._register(this.webviewService.createWebviewElement({ title: undefined, options: {}, contentOptions: {}, extension: undefined }));
webview.mountTo(mediaContainer);
const body = await this.detailsRenderer.renderSVG(FileAccess.asFileUri(`${WelcomeWidget.WELCOME_MEDIA_PATH}${path}`));
webview.setHtml(body);
}
getId(): string {
return 'editor.contrib.welcomeWidget';
}
@@ -184,14 +161,8 @@ export class WelcomeWidget extends Disposable implements IOverlayWidget {
};
}
private _hideSoon = this._register(new RunOnceScheduler(() => this._hide(false), WelcomeWidget.WIDGET_TIMEOUT));
private _isVisible: boolean = false;
private _revealTemporarily(): void {
this._show();
this._hideSoon.schedule();
}
private _show(): void {
if (this._isVisible) {
return;
@@ -200,32 +171,48 @@ export class WelcomeWidget extends Disposable implements IOverlayWidget {
this._rootDomNode.style.display = 'block';
}
private _hide(isUserDismissed: boolean): void {
private _hide(): void {
if (!this._isVisible) {
return;
}
this._isVisible = false;
this._isVisible = true;
this._rootDomNode.style.display = 'none';
this._editor.removeOverlayWidget(this);
this.telemetryService.publicLog2<WorkbenchActionExecutedEvent, WorkbenchActionExecutedClassification>('workbenchActionExecuted', {
id: isUserDismissed ? 'welcomeWidgetDismissed' : 'welcomeWidgetHidden',
id: 'welcomeWidgetDismissed',
from: 'welcomeWidget'
});
}
private applyStyles(): void {
const style = defaultDialogStyles;
const fgColor = style.dialogForeground;
const bgColor = style.dialogBackground;
const shadowColor = style.dialogShadow ? `0 0px 8px ${style.dialogShadow}` : '';
const border = style.dialogBorder ? `1px solid ${style.dialogBorder}` : '';
this._rootDomNode.style.boxShadow = shadowColor;
this._rootDomNode.style.color = fgColor ?? '';
this._rootDomNode.style.backgroundColor = bgColor ?? '';
this._rootDomNode.style.border = border;
}
}
registerThemingParticipant((theme, collector) => {
const addBackgroundColorRule = (selector: string, color: Color | undefined): void => {
if (color) {
collector.addRule(`.monaco-editor ${selector} { background-color: ${color}; }`);
}
};
const widgetBackground = theme.getColor(editorWidgetBackground);
addBackgroundColorRule('.welcome-widget', widgetBackground);
const widgetShadowColor = theme.getColor(widgetShadow);
if (widgetShadowColor) {
collector.addRule(`.welcome-widget { box-shadow: 0 0 8px 2px ${widgetShadowColor}; }`);
}
const widgetBorderColor = theme.getColor(widgetBorder);
if (widgetBorderColor) {
collector.addRule(`.welcome-widget { border-left: 1px solid ${widgetBorderColor}; border-right: 1px solid ${widgetBorderColor}; border-bottom: 1px solid ${widgetBorderColor}; }`);
}
const hcBorder = theme.getColor(contrastBorder);
if (hcBorder) {
collector.addRule(`.welcome-widget { border: 1px solid ${hcBorder}; }`);
}
const foreground = theme.getColor(editorWidgetForeground);
if (foreground) {
collector.addRule(`.welcome-widget { color: ${foreground}; }`);
}
});
@@ -251,10 +251,12 @@ registerAction2(class extends Action2 {
quickPick.hide();
});
quickPick.onDidHide(() => quickPick.dispose());
quickPick.show();
await extensionService.whenInstalledExtensionsRegistered();
gettingStartedService.onDidAddWalkthrough(async () => {
quickPick.items = await this.getQuickPickItems(contextService, gettingStartedService);
});
quickPick.show();
quickPick.busy = false;
quickPick.items = await this.getQuickPickItems(contextService, gettingStartedService);
}
});
@@ -55,8 +55,6 @@ export class StartupPageContribution implements IWorkbenchContribution {
@INotificationService private readonly notificationService: INotificationService,
@IEditorResolverService editorResolverService: IEditorResolverService
) {
this.run().then(undefined, onUnexpectedError);
editorResolverService.registerEditor(
`${GettingStartedInput.RESOURCE.scheme}:/**`,
{
@@ -80,6 +78,8 @@ export class StartupPageContribution implements IWorkbenchContribution {
}
}
);
this.run().then(undefined, onUnexpectedError);
}
private async run() {
@@ -185,11 +185,11 @@ class ExtensionBisectUi {
private _showBisectPrompt(): void {
const goodPrompt: IPromptChoice = {
label: 'Good Now',
label: localize('I cannot reproduce', "I can't reproduce"),
run: () => this._commandService.executeCommand('extension.bisect.next', false)
};
const badPrompt: IPromptChoice = {
label: 'This is Bad',
label: localize('This is Bad', "I can reproduce"),
run: () => this._commandService.executeCommand('extension.bisect.next', true)
};
const stop: IPromptChoice = {
@@ -329,11 +329,11 @@ registerAction2(class extends Action2 {
detail: localize('bisect', "Extension Bisect is active and has disabled {0} extensions. Check if you can still reproduce the problem and proceed by selecting from these options.", bisectService.disabledCount),
buttons: [
{
label: localize({ key: 'next.good', comment: ['&& denotes a mnemonic'] }, "&&Good now"),
label: localize({ key: 'next.good', comment: ['&& denotes a mnemonic'] }, "I ca&&n't reproduce"),
run: () => false // good now
},
{
label: localize({ key: 'next.bad', comment: ['&& denotes a mnemonic'] }, "This is &&bad"),
label: localize({ key: 'next.bad', comment: ['&& denotes a mnemonic'] }, "I can &&reproduce"),
run: () => true // bad
},
{
@@ -0,0 +1,375 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import { localize } from 'vs/nls';
import { IExtensionManagementService } from 'vs/platform/extensionManagement/common/extensionManagement';
import { ExtensionType } from 'vs/platform/extensions/common/extensions';
import { IProductService } from 'vs/platform/product/common/productService';
import { IWorkbenchIssueService } from 'vs/workbench/services/issue/common/issue';
import { Disposable } from 'vs/base/common/lifecycle';
import { Action2, registerAction2 } from 'vs/platform/actions/common/actions';
import { IUserDataProfileImportExportService, IUserDataProfileManagementService, IUserDataProfileService } from 'vs/workbench/services/userDataProfile/common/userDataProfile';
import { IDialogService } from 'vs/platform/dialogs/common/dialogs';
import { IExtensionBisectService } from 'vs/workbench/services/extensionManagement/browser/extensionBisect';
import { INotificationHandle, INotificationService, IPromptChoice, NotificationPriority, Severity } from 'vs/platform/notification/common/notification';
import { IWorkbenchExtensionEnablementService } from 'vs/workbench/services/extensionManagement/common/extensionManagement';
import { IHostService } from 'vs/workbench/services/host/browser/host';
import { IUserDataProfile, IUserDataProfilesService } from 'vs/platform/userDataProfile/common/userDataProfile';
import { ServicesAccessor, createDecorator } from 'vs/platform/instantiation/common/instantiation';
import { Categories } from 'vs/platform/action/common/actionCommonCategories';
import { InstantiationType, registerSingleton } from 'vs/platform/instantiation/common/extensions';
import { IContextKeyService, RawContextKey } from 'vs/platform/contextkey/common/contextkey';
import { Registry } from 'vs/platform/registry/common/platform';
import { Extensions, IWorkbenchContributionsRegistry } from 'vs/workbench/common/contributions';
import { LifecyclePhase } from 'vs/workbench/services/lifecycle/common/lifecycle';
import { IStorageService, StorageScope, StorageTarget } from 'vs/platform/storage/common/storage';
import { IOpenerService } from 'vs/platform/opener/common/opener';
import { URI } from 'vs/base/common/uri';
const ITroubleshootIssueService = createDecorator<ITroubleshootIssueService>('ITroubleshootIssueService');
interface ITroubleshootIssueService {
_serviceBrand: undefined;
isActive(): boolean;
start(): Promise<void>;
resume(): Promise<void>;
stop(): Promise<void>;
}
enum TroubleshootStage {
EXTENSIONS = 1,
WORKBENCH,
}
type TroubleShootResult = 'good' | 'bad' | 'stop';
class TroubleShootState {
static fromJSON(raw: string | undefined): TroubleShootState | undefined {
if (!raw) {
return undefined;
}
try {
interface Raw extends TroubleShootState { }
const data: Raw = JSON.parse(raw);
if (
(data.stage === TroubleshootStage.EXTENSIONS || data.stage === TroubleshootStage.WORKBENCH)
&& typeof data.profile === 'string'
) {
return new TroubleShootState(data.stage, data.profile);
}
} catch { /* ignore */ }
return undefined;
}
constructor(
readonly stage: TroubleshootStage,
readonly profile: string,
) { }
}
class TroubleshootIssueService extends Disposable implements ITroubleshootIssueService {
readonly _serviceBrand: undefined;
static readonly storageKey = 'issueTroubleshootState';
private notificationHandle: INotificationHandle | undefined;
constructor(
@IUserDataProfileService private readonly userDataProfileService: IUserDataProfileService,
@IUserDataProfilesService private readonly userDataProfilesService: IUserDataProfilesService,
@IUserDataProfileManagementService private readonly userDataProfileManagementService: IUserDataProfileManagementService,
@IUserDataProfileImportExportService private readonly userDataProfileImportExportService: IUserDataProfileImportExportService,
@IDialogService private readonly dialogService: IDialogService,
@IExtensionBisectService private readonly extensionBisectService: IExtensionBisectService,
@INotificationService private readonly notificationService: INotificationService,
@IExtensionManagementService private readonly extensionManagementService: IExtensionManagementService,
@IWorkbenchExtensionEnablementService private readonly extensionEnablementService: IWorkbenchExtensionEnablementService,
@IWorkbenchIssueService private readonly issueService: IWorkbenchIssueService,
@IProductService private readonly productService: IProductService,
@IHostService private readonly hostService: IHostService,
@IStorageService private readonly storageService: IStorageService,
@IOpenerService private readonly openerService: IOpenerService,
) {
super();
}
isActive(): boolean {
return this.state !== undefined;
}
async start(): Promise<void> {
if (this.isActive()) {
throw new Error('invalid state');
}
const res = await this.dialogService.confirm({
message: localize('troubleshoot issue', "Troubleshoot Issue"),
detail: localize('detail.start', "Issue troubleshooting is a process to help you identify if the issue is with {0} or caused by an extension.\n\nDuring the process the window reloads repeatedly. Each time you must confirm if you are still seeing problems.", this.productService.nameLong),
primaryButton: localize({ key: 'msg', comment: ['&& denotes a mnemonic'] }, "&&Troubleshoot Issue"),
custom: true
});
if (!res.confirmed) {
return;
}
const originalProfile = this.userDataProfileService.currentProfile;
await this.userDataProfileImportExportService.createTemporaryProfile(this.userDataProfileService.currentProfile, localize('troubleshoot issue', "Troubleshoot Issue"), true);
this.state = new TroubleShootState(TroubleshootStage.EXTENSIONS, originalProfile.id);
await this.resume();
}
async resume(): Promise<void> {
if (!this.isActive()) {
return;
}
if (this.state?.stage === TroubleshootStage.EXTENSIONS && !this.extensionBisectService.isActive) {
await this.reproduceIssueWithExtensionsDisabled();
}
if (this.state?.stage === TroubleshootStage.WORKBENCH) {
await this.reproduceIssueWithEmptyProfile();
}
await this.stop();
}
async stop(): Promise<void> {
if (!this.isActive()) {
return;
}
if (this.notificationHandle) {
this.notificationHandle.close();
this.notificationHandle = undefined;
}
if (this.extensionBisectService.isActive) {
await this.extensionBisectService.reset();
}
const profile = this.userDataProfilesService.profiles.find(p => p.id === this.state?.profile) ?? this.userDataProfilesService.defaultProfile;
this.state = undefined;
await this.userDataProfileManagementService.switchProfile(profile);
}
private async reproduceIssueWithExtensionsDisabled(): Promise<void> {
const result = await this.askToReproduceIssue(localize('profile.extensions.disabled', "Issue troubleshooting is active and has temprarily disabled all installed extensions. Check if you can still reproduce the problem and proceed by selecting from these options."));
if (result === 'good') {
const profile = this.userDataProfilesService.profiles.find(p => p.id === this.state!.profile) ?? this.userDataProfilesService.defaultProfile;
await this.reproduceIssueWithExtensionsBisect(profile);
}
if (result === 'bad') {
this.state = new TroubleShootState(TroubleshootStage.WORKBENCH, this.state!.profile);
}
if (result === 'stop') {
await this.stop();
}
}
private async reproduceIssueWithEmptyProfile(): Promise<void> {
await this.userDataProfileManagementService.createAndEnterTransientProfile();
this.updateState(this.state);
const result = await this.askToReproduceIssue(localize('empty.profile', "Issue troubleshooting is active and has temporarily reset your settings to defaults. Check if you can still reproduce the problem and proceed by selecting from these options."));
if (result === 'stop') {
await this.stop();
}
if (result === 'good') {
await this.askToReportIssue(localize('issue is with configuration', "Issue troubleshooting has identified that the issue is caused by your settings. Please report the issue by sharing your settings."));
}
if (result === 'bad') {
await this.askToReportIssue(localize('issue is in core', "Issue troubleshooting has identified that the issue is with {0}.", this.productService.nameLong));
}
}
private async reproduceIssueWithExtensionsBisect(profile: IUserDataProfile): Promise<void> {
await this.userDataProfileManagementService.switchProfile(profile);
const extensions = (await this.extensionManagementService.getInstalled(ExtensionType.User)).filter(ext => this.extensionEnablementService.isEnabled(ext));
await this.extensionBisectService.start(extensions);
await this.hostService.reload();
}
private askToReproduceIssue(message: string): Promise<TroubleShootResult> {
return new Promise((c, e) => {
const goodPrompt: IPromptChoice = {
label: localize('I cannot reproduce', "I can't reproduce"),
run: () => c('good')
};
const badPrompt: IPromptChoice = {
label: localize('This is Bad', "I can reproduce"),
run: () => c('bad')
};
const stop: IPromptChoice = {
label: localize('Stop', "Stop"),
run: () => c('stop')
};
this.notificationHandle = this.notificationService.prompt(
Severity.Info,
message,
[goodPrompt, badPrompt, stop],
{ sticky: true, priority: NotificationPriority.URGENT }
);
});
}
private async askToReportIssue(message: string): Promise<void> {
let isCheckedInInsiders = false;
if (this.productService.quality === 'stable') {
const res = await this.askToReproduceIssueWithInsiders();
if (res === 'good') {
await this.dialogService.prompt({
type: Severity.Info,
message: localize('troubleshoot issue', "Troubleshoot Issue"),
detail: localize('use insiders', "This likely means that the issue has been addressed already and will be available in an upcoming release. You can safely use {0} insiders until the new stable version is available.", this.productService.nameLong),
custom: true
});
return;
}
if (res === 'stop') {
await this.stop();
return;
}
if (res === 'bad') {
isCheckedInInsiders = true;
}
}
await this.issueService.openReporter({
issueBody: `> ${message} ${isCheckedInInsiders ? `It is confirmed that the issue exists in ${this.productService.nameLong} Insiders` : ''}`,
});
}
private async askToReproduceIssueWithInsiders(): Promise<TroubleShootResult | undefined> {
const confirmRes = await this.dialogService.confirm({
type: 'info',
message: localize('troubleshoot issue', "Troubleshoot Issue"),
primaryButton: localize('download insiders', "Download {0} Insiders", this.productService.nameLong),
cancelButton: localize('report anyway', "Report Issue Anyway"),
detail: localize('ask to download insiders', "Please try to download and reproduce the issue in {0} insiders.", this.productService.nameLong),
custom: {
disableCloseAction: true,
}
});
if (!confirmRes.confirmed) {
return undefined;
}
const opened = await this.openerService.open(URI.parse('https://aka.ms/vscode-insiders'));
if (!opened) {
return undefined;
}
const res = await this.dialogService.prompt<TroubleShootResult>({
type: 'info',
message: localize('troubleshoot issue', "Troubleshoot Issue"),
buttons: [{
label: localize('good', "I can't reproduce"),
run: () => 'good'
}, {
label: localize('bad', "I can reproduce"),
run: () => 'bad'
}],
cancelButton: {
label: localize('stop', "Stop"),
run: () => 'stop'
},
detail: localize('ask to reproduce issue', "Please try to reproduce the issue in {0} insiders and confirm if the issue exists there.", this.productService.nameLong),
custom: {
disableCloseAction: true,
}
});
return res.result;
}
private _state: TroubleShootState | undefined | null;
get state(): TroubleShootState | undefined {
if (this._state === undefined) {
const raw = this.storageService.get(TroubleshootIssueService.storageKey, StorageScope.PROFILE);
this._state = TroubleShootState.fromJSON(raw);
}
return this._state || undefined;
}
set state(state: TroubleShootState | undefined) {
this._state = state ?? null;
this.updateState(state);
}
private updateState(state: TroubleShootState | undefined) {
if (state) {
this.storageService.store(TroubleshootIssueService.storageKey, JSON.stringify(state), StorageScope.PROFILE, StorageTarget.MACHINE);
} else {
this.storageService.remove(TroubleshootIssueService.storageKey, StorageScope.PROFILE);
}
}
}
class IssueTroubleshootUi extends Disposable {
static ctxIsTroubleshootActive = new RawContextKey<boolean>('isIssueTroubleshootActive', false);
constructor(
@IContextKeyService private readonly contextKeyService: IContextKeyService,
@ITroubleshootIssueService private readonly troubleshootIssueService: ITroubleshootIssueService,
@IStorageService storageService: IStorageService,
) {
super();
this.updateContext();
if (troubleshootIssueService.isActive()) {
troubleshootIssueService.resume();
}
this._register(storageService.onDidChangeValue(e => {
if (e.key === TroubleshootIssueService.storageKey) {
this.updateContext();
}
}));
}
private updateContext(): void {
IssueTroubleshootUi.ctxIsTroubleshootActive.bindTo(this.contextKeyService).set(this.troubleshootIssueService.isActive());
}
}
Registry.as<IWorkbenchContributionsRegistry>(Extensions.Workbench).registerWorkbenchContribution(IssueTroubleshootUi, LifecyclePhase.Restored);
registerAction2(class TroubleshootIssueAction extends Action2 {
constructor() {
super({
id: 'workbench.action.troubleshootIssue.start',
title: { value: localize('troubleshootIssue', "Troubleshoot Issue..."), original: 'Troubleshoot Issue...' },
category: Categories.Help,
f1: true,
precondition: IssueTroubleshootUi.ctxIsTroubleshootActive.negate(),
});
}
run(accessor: ServicesAccessor): Promise<void> {
return accessor.get(ITroubleshootIssueService).start();
}
});
registerAction2(class extends Action2 {
constructor() {
super({
id: 'workbench.action.troubleshootIssue.stop',
title: { value: localize('title.stop', "Stop Troubleshoot Issue"), original: 'Stop Troubleshoot Issue' },
category: Categories.Help,
f1: true,
precondition: IssueTroubleshootUi.ctxIsTroubleshootActive
});
}
async run(accessor: ServicesAccessor): Promise<void> {
return accessor.get(ITroubleshootIssueService).stop();
}
});
registerSingleton(ITroubleshootIssueService, TroubleshootIssueService, InstantiationType.Delayed);
@@ -96,6 +96,7 @@ export class ExtensionsResourceInitializer implements IProfileResourceInitialize
export class ExtensionsResource implements IProfileResource {
constructor(
private readonly extensionsDisabled: boolean,
@IExtensionManagementService private readonly extensionManagementService: IExtensionManagementService,
@IExtensionGalleryService private readonly extensionGalleryService: IExtensionGalleryService,
@IUserDataProfileStorageService private readonly userDataProfileStorageService: IUserDataProfileStorageService,
@@ -189,7 +190,7 @@ export class ExtensionsResource implements IProfileResource {
}
}
const profileExtension: IProfileExtension = { identifier, displayName: extension.manifest.displayName };
if (disabled) {
if (this.extensionsDisabled || disabled) {
profileExtension.disabled = true;
}
if (!extension.isBuiltin && extension.pinned) {
@@ -276,17 +277,18 @@ export class ExtensionsResourceExportTreeItem extends ExtensionsResourceTreeItem
constructor(
private readonly profile: IUserDataProfile,
private readonly extensionsDisabled: boolean,
@IInstantiationService private readonly instantiationService: IInstantiationService,
) {
super();
}
protected getExtensions(): Promise<IProfileExtension[]> {
return this.instantiationService.createInstance(ExtensionsResource).getLocalExtensions(this.profile);
return this.instantiationService.createInstance(ExtensionsResource, this.extensionsDisabled).getLocalExtensions(this.profile);
}
async getContent(): Promise<string> {
return this.instantiationService.createInstance(ExtensionsResource).getContent(this.profile, [...this.excludedExtensions.values()]);
return this.instantiationService.createInstance(ExtensionsResource, this.extensionsDisabled).getContent(this.profile, [...this.excludedExtensions.values()]);
}
}
@@ -301,11 +303,11 @@ export class ExtensionsResourceImportTreeItem extends ExtensionsResourceTreeItem
}
protected getExtensions(): Promise<IProfileExtension[]> {
return this.instantiationService.createInstance(ExtensionsResource).getProfileExtensions(this.content);
return this.instantiationService.createInstance(ExtensionsResource, false).getProfileExtensions(this.content);
}
async getContent(): Promise<string> {
const extensionsResource = this.instantiationService.createInstance(ExtensionsResource);
const extensionsResource = this.instantiationService.createInstance(ExtensionsResource, false);
const extensions = await extensionsResource.getProfileExtensions(this.content);
return extensionsResource.toContent(extensions, [...this.excludedExtensions.values()]);
}
@@ -225,7 +225,7 @@ export class UserDataProfileImportExportService extends Disposable implements IU
}
const disposables = new DisposableStore();
try {
const userDataProfilesExportState = disposables.add(this.instantiationService.createInstance(UserDataProfileExportState, this.userDataProfileService.currentProfile));
const userDataProfilesExportState = disposables.add(this.instantiationService.createInstance(UserDataProfileExportState, this.userDataProfileService.currentProfile, false));
const barrier = new Barrier();
const exportAction = new BarrierAction(barrier, new Action('export', localize('export', "Export"), undefined, true, async () => {
exportAction.enabled = false;
@@ -247,7 +247,7 @@ export class UserDataProfileImportExportService extends Disposable implements IU
}
async createFromCurrentProfile(name: string): Promise<void> {
const userDataProfilesExportState = this.instantiationService.createInstance(UserDataProfileExportState, this.userDataProfileService.currentProfile);
const userDataProfilesExportState = this.instantiationService.createInstance(UserDataProfileExportState, this.userDataProfileService.currentProfile, false);
try {
const profileTemplate = await userDataProfilesExportState.getProfileTemplate(name, undefined);
await this.doImportProfile(profileTemplate);
@@ -256,6 +256,16 @@ export class UserDataProfileImportExportService extends Disposable implements IU
}
}
async createTemporaryProfile(profile: IUserDataProfile, name: string, extensionsDisabled: boolean): Promise<void> {
const userDataProfilesExportState = this.instantiationService.createInstance(UserDataProfileExportState, profile, extensionsDisabled);
try {
const profileTemplate = await userDataProfilesExportState.getProfileTemplate(name, undefined);
await this.importAndSwitch(profileTemplate, true, true, extensionsDisabled, localize('import', "Create Profile"));
} finally {
userDataProfilesExportState.dispose();
}
}
private async doExportProfile(userDataProfilesExportState: UserDataProfileExportState): Promise<void> {
const profile = await userDataProfilesExportState.getProfileToExport();
if (!profile) {
@@ -342,7 +352,7 @@ export class UserDataProfileImportExportService extends Disposable implements IU
const userDataProfileImportState = disposables.add(this.instantiationService.createInstance(UserDataProfileImportState, profileTemplate));
profileTemplate = await userDataProfileImportState.getProfileTemplateToImport();
const importedProfile = await this.importAndSwitch(profileTemplate, true, false, localize('preview profile', "Preview Profile"));
const importedProfile = await this.importAndSwitch(profileTemplate, true, false, false, localize('preview profile', "Preview Profile"));
if (!importedProfile) {
return;
@@ -385,7 +395,7 @@ export class UserDataProfileImportExportService extends Disposable implements IU
view.setMessage(undefined);
const profileTemplate = await userDataProfileImportState.getProfileTemplateToImport();
if (profileTemplate.extensions) {
await that.instantiationService.createInstance(ExtensionsResource).apply(profileTemplate.extensions, importedProfile);
await that.instantiationService.createInstance(ExtensionsResource, false).apply(profileTemplate.extensions, importedProfile);
}
});
}
@@ -393,7 +403,7 @@ export class UserDataProfileImportExportService extends Disposable implements IU
disposables.add(Event.debounce(this.extensionManagementService.onDidInstallExtensions, () => undefined, 100)(async () => {
const profileTemplate = await userDataProfileImportState.getProfileTemplateToImport();
if (profileTemplate.extensions) {
const profileExtensions = await that.instantiationService.createInstance(ExtensionsResource).getProfileExtensions(profileTemplate.extensions!);
const profileExtensions = await that.instantiationService.createInstance(ExtensionsResource, false).getProfileExtensions(profileTemplate.extensions!);
const installed = await this.extensionManagementService.getInstalled(ExtensionType.User);
if (profileExtensions.every(e => installed.some(i => areSameExtensions(e.identifier, i.identifier)))) {
disposable.dispose();
@@ -432,7 +442,7 @@ export class UserDataProfileImportExportService extends Disposable implements IU
const importProfileFn = async () => {
importAction.enabled = false;
const profileTemplate = await userDataProfileImportState.getProfileTemplateToImport();
const importedProfile = await this.importAndSwitch(profileTemplate, false, true, title);
const importedProfile = await this.importAndSwitch(profileTemplate, false, true, false, title);
if (!importedProfile) {
return;
}
@@ -448,7 +458,7 @@ export class UserDataProfileImportExportService extends Disposable implements IU
return importAction;
}
private async importAndSwitch(profileTemplate: IUserDataProfileTemplate, temporaryProfile: boolean, extensions: boolean, title: string): Promise<IUserDataProfile | undefined> {
private async importAndSwitch(profileTemplate: IUserDataProfileTemplate, temporaryProfile: boolean, extensions: boolean, extensionsDisabled: boolean, title: string): Promise<IUserDataProfile | undefined> {
return this.progressService.withProgress({
location: ProgressLocation.Window,
command: showWindowLogActionId,
@@ -481,7 +491,7 @@ export class UserDataProfileImportExportService extends Disposable implements IU
}
if (profileTemplate.extensions && extensions) {
progress.report({ message: localize('progress extensions', "{0} ({1}): Applying Extensions...", title, profileTemplate.name) });
await this.instantiationService.createInstance(ExtensionsResource).apply(profileTemplate.extensions, profile);
await this.instantiationService.createInstance(ExtensionsResource, extensionsDisabled).apply(profileTemplate.extensions, profile);
}
progress.report({ message: localize('switching profile', "{0} ({1}): Applying...", title, profileTemplate.name) });
@@ -545,8 +555,8 @@ export class UserDataProfileImportExportService extends Disposable implements IU
return result?.id;
}
private async getProfileToImport(profileTemplate: IUserDataProfileTemplate, temp?: boolean): Promise<IUserDataProfile | undefined> {
const profileName = temp ? `${profileTemplate.name} (${localize('preview', "Preview")})` : profileTemplate.name;
private async getProfileToImport(profileTemplate: IUserDataProfileTemplate, temp: boolean): Promise<IUserDataProfile | undefined> {
const profileName = profileTemplate.name;
const profile = this.userDataProfilesService.profiles.find(p => p.name === profileName);
if (profile) {
if (temp) {
@@ -666,7 +676,7 @@ export class UserDataProfileImportExportService extends Disposable implements IU
await this.instantiationService.createInstance(GlobalStateResource).apply(profile.globalState, this.userDataProfileService.currentProfile);
}
if (profile.extensions) {
await this.instantiationService.createInstance(ExtensionsResource).apply(profile.extensions, this.userDataProfileService.currentProfile);
await this.instantiationService.createInstance(ExtensionsResource, false).apply(profile.extensions, this.userDataProfileService.currentProfile);
}
});
this.notificationService.info(localize('applied profile', "{0}: Applied successfully.", PROFILES_CATEGORY.value));
@@ -997,6 +1007,7 @@ class UserDataProfileExportState extends UserDataProfileImportExportState {
constructor(
readonly profile: IUserDataProfile,
private readonly disableExtensions: boolean,
@IQuickInputService quickInputService: IQuickInputService,
@IFileService private readonly fileService: IFileService,
@IInstantiationService private readonly instantiationService: IInstantiationService
@@ -1052,7 +1063,7 @@ class UserDataProfileExportState extends UserDataProfileImportExportState {
roots.push(globalStateResourceTreeItem);
}
const extensionsResourceTreeItem = this.instantiationService.createInstance(ExtensionsResourceExportTreeItem, exportPreviewProfle);
const extensionsResourceTreeItem = this.instantiationService.createInstance(ExtensionsResourceExportTreeItem, exportPreviewProfle, this.disableExtensions);
if (await extensionsResourceTreeItem.hasContent()) {
roots.push(extensionsResourceTreeItem);
}
@@ -89,6 +89,7 @@ export interface IUserDataProfileImportExportService {
importProfile(uri: URI, options?: IProfileImportOptions): Promise<void>;
showProfileContents(): Promise<void>;
createFromCurrentProfile(name: string): Promise<void>;
createTemporaryProfile(from: IUserDataProfile, name: string, extensionsDisabled: boolean): Promise<void>;
setProfile(profile: IUserDataProfileTemplate): Promise<void>;
}
+2
View File
@@ -12,6 +12,8 @@ import { LanguagesRegistry } from 'vs/editor/common/services/languagesRegistry';
* and can be used to add assertions. e.g. that registries are empty, etc.
*
* !! This is called directly by the testing framework.
*
* @skipMangle
*/
export function assertCleanState(): void {
// If this test fails, it is a clear indication that
@@ -109,6 +109,7 @@ import 'vs/editor/common/services/treeViewsDndService';
import 'vs/workbench/services/textMate/browser/textMateTokenizationFeature.contribution';
import 'vs/workbench/services/userActivity/common/userActivityService';
import 'vs/workbench/services/userActivity/browser/userActivityBrowser';
import 'vs/workbench/services/issue/browser/issueTroubleshoot';
import { InstantiationType, registerSingleton } from 'vs/platform/instantiation/common/extensions';
import { ExtensionGalleryService } from 'vs/platform/extensionManagement/common/extensionGalleryService';
+8 -8
View File
@@ -1400,10 +1400,10 @@
bindings "^1.2.1"
nan "^2.17.0"
"@vscode/windows-process-tree@0.4.2":
version "0.4.2"
resolved "https://registry.yarnpkg.com/@vscode/windows-process-tree/-/windows-process-tree-0.4.2.tgz#54d010fdeb06dfe3a9c6d58fcb3ed9acfc962f33"
integrity sha512-b20865s1HG1VtGt887KrB1blwFS6p4L1Fl1o/WplO9j7sGBle8sLqkNnGXbCaRNgdIgfXtitmzG366FVynJZdQ==
"@vscode/windows-process-tree@^0.5.0":
version "0.5.0"
resolved "https://registry.yarnpkg.com/@vscode/windows-process-tree/-/windows-process-tree-0.5.0.tgz#b8205b862c75a1e0ad8b7bf4350dc85036ee3a2c"
integrity sha512-y8Oliel/rBSYh9f1T4F0zQjJNPeJRgYRhEKZsjas7JXKLf46FpE3Ux8e9+7HelUD8dXFH7C7N6895nU0WhrMlg==
dependencies:
nan "^2.17.0"
@@ -6973,10 +6973,10 @@ node-gyp-build@^4.3.0:
resolved "https://registry.yarnpkg.com/node-gyp-build/-/node-gyp-build-4.3.0.tgz#9f256b03e5826150be39c764bf51e993946d71a3"
integrity sha512-iWjXZvmboq0ja1pUGULQBexmxq8CV4xBhX7VDOTbL7ZR4FOowwY/VOtRxBN/yKxmdGoIp4j5ysNT4u3S2pDQ3Q==
node-pty@0.11.0-beta33:
version "0.11.0-beta33"
resolved "https://registry.yarnpkg.com/node-pty/-/node-pty-0.11.0-beta33.tgz#722a729fb9449f591279bee1f8b431b71a9af4a1"
integrity sha512-SoP5BbSfvc8Um51rIriUEOPvMltc43iTaKXGJaJKLR3+NfQbjcCcNQGyOd9P9pvBccWYg+Rncv18qMtJKIAi1Q==
node-pty@1.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/node-pty/-/node-pty-1.0.0.tgz#7daafc0aca1c4ca3de15c61330373af4af5861fd"
integrity sha512-wtBMWWS7dFZm/VgqElrTvtfMq4GzJ6+edFI0Y0zyzygUSZMgZdraDUMUhCIvkjhJjme15qWmbyJbtAx4ot4uZA==
dependencies:
nan "^2.17.0"