Merge branch 'master' into joh/completionOverwrite

This commit is contained in:
Johannes Rieken 2019-10-24 12:34:52 +02:00 committed by GitHub
commit 0bfdfa69bc
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
135 changed files with 1742 additions and 2265 deletions

View file

@ -1,6 +1,14 @@
name: CI
on: [push, pull_request]
on:
push:
branches:
- master
- release/*
pull_request:
branches:
- master
- release/*
jobs:
linux:

View file

@ -82,16 +82,11 @@ if (fs.existsSync(processTreeDts)) {
}
function getInstalledVersion(packageName, cwd) {
const opts = {};
if (cwd) {
opts.cwd = cwd;
}
const result = cp.spawnSync(yarn, ['list', '--pattern', packageName], opts);
const stdout = result.stdout.toString();
const { stdout } = cp.spawnSync(yarn, ['list', packageName], { encoding: 'utf8', cwd });
const match = stdout.match(new RegExp(packageName + '@(\\S+)'));
if (!match || !match[1]) {
throw new Error('Unexpected output from yarn list: ' + stdout);
throw new Error(`Missing ${packageName} in ${cwd}: \n${stdout}`);
}
return match[1];
@ -108,7 +103,7 @@ function assertSameVersionsBetweenFolders(packageName, otherFolder) {
// Check that modules in both the base package.json and remote/ have the same version installed
const requireSameVersionsInRemote = [
'xterm',
// 'xterm',
'xterm-addon-search',
'xterm-addon-web-links',
'node-pty',

File diff suppressed because one or more lines are too long

View file

@ -129,7 +129,7 @@ document.addEventListener('dblclick', event => {
}
});
const passThroughLinkSchemes = ['http:', 'https:', 'mailto:', 'vscode:', 'vscode-insiders'];
const passThroughLinkSchemes = ['http:', 'https:', 'mailto:', 'vscode:', 'vscode-insiders:'];
document.addEventListener('click', event => {
if (!event) {

View file

@ -7,7 +7,7 @@ import * as path from 'path';
import * as vscode from 'vscode';
import * as nls from 'vscode-nls';
import { OpenDocumentLinkCommand } from '../commands/openDocumentLink';
import { getUriForLinkWithKnownExternalScheme } from '../util/links';
import { getUriForLinkWithKnownExternalScheme, isOfScheme, Schemes } from '../util/links';
const localize = nls.loadMessageBundle();
@ -18,6 +18,10 @@ function parseLink(
): { uri: vscode.Uri, tooltip?: string } {
const externalSchemeUri = getUriForLinkWithKnownExternalScheme(link);
if (externalSchemeUri) {
// Normalize VS Code links to target currently running version
if (isOfScheme(Schemes.vscode, link) || isOfScheme(Schemes['vscode-insiders'], link)) {
return { uri: vscode.Uri.parse(link).with({ scheme: vscode.env.uriScheme }) };
}
return { uri: externalSchemeUri };
}

View file

@ -227,6 +227,11 @@ export class MarkdownEngine {
const normalizeLink = md.normalizeLink;
md.normalizeLink = (link: string) => {
try {
// Normalize VS Code schemes to target the current version
if (isOfScheme(Schemes.vscode, link) || isOfScheme(Schemes['vscode-insiders'], link)) {
return normalizeLink(vscode.Uri.parse(link).with({ scheme: vscode.env.uriScheme }).toString());
}
// If original link doesn't look like a url with a scheme, assume it must be a link to a file in workspace
if (!/^[a-z\-]+:/i.test(link)) {
// Use a fake scheme for parsing
@ -261,7 +266,11 @@ export class MarkdownEngine {
const validateLink = md.validateLink;
md.validateLink = (link: string) => {
// support file:// links
return validateLink(link) || isOfScheme(Schemes.file, link) || /^data:image\/.*?;/.test(link);
return validateLink(link)
|| isOfScheme(Schemes.file, link)
|| isOfScheme(Schemes.vscode, link)
|| isOfScheme(Schemes['vscode-insiders'], link)
|| /^data:image\/.*?;/.test(link);
};
}

View file

@ -13,7 +13,7 @@ export const Schemes = {
data: 'data:',
vscode: 'vscode:',
'vscode-insiders': 'vscode-insiders:',
'vscode-resource': 'vscode-resource',
'vscode-resource': 'vscode-resource:',
};
const knownSchemes = [

View file

@ -4,4 +4,5 @@
*--------------------------------------------------------------------------------------------*/
/// <reference path='../../../../src/vs/vscode.d.ts'/>
/// <reference path='../../../../src/vs/vscode.proposed.d.ts'/>
/// <reference types='@types/node'/>

File diff suppressed because it is too large Load diff

View file

@ -22,5 +22,11 @@
["\"", "\""],
["'", "'"],
["`", "`"]
]
],
"folding": {
"markers": {
"start": "^=pod\\s*$",
"end": "^=cut\\s*$"
}
}
}

View file

@ -176,6 +176,7 @@ class SyncedBuffer {
const args: Proto.OpenRequestArgs = {
file: this.filepath,
fileContent: this.document.getText(),
projectRootPath: this.client.getWorkspaceRootForResource(this.document.uri),
};
const scriptKind = mode2ScriptKind(this.document.languageId);
@ -183,10 +184,6 @@ class SyncedBuffer {
args.scriptKindName = scriptKind;
}
if (this.client.apiVersion.gte(API.v230)) {
args.projectRootPath = this.client.getWorkspaceRootForResource(this.document.uri);
}
if (this.client.apiVersion.gte(API.v240)) {
const tsPluginsForDocument = this.client.pluginManager.plugins
.filter(x => x.languages.indexOf(this.document.languageId) >= 0);
@ -349,6 +346,14 @@ export default class BufferSyncSupport extends Disposable {
vscode.workspace.onDidOpenTextDocument(this.openTextDocument, this, this._disposables);
vscode.workspace.onDidCloseTextDocument(this.onDidCloseTextDocument, this, this._disposables);
vscode.workspace.onDidChangeTextDocument(this.onDidChangeTextDocument, this, this._disposables);
vscode.window.onDidChangeVisibleTextEditors(e => {
for (const { document } of e) {
const syncedBuffer = this.syncedBuffers.get(document.uri);
if (syncedBuffer) {
this.requestDiagnostic(syncedBuffer);
}
}
}, this, this._disposables);
vscode.workspace.textDocuments.forEach(this.openTextDocument, this);
}

View file

@ -6,8 +6,6 @@
import * as vscode from 'vscode';
import * as nls from 'vscode-nls';
import { ITypeScriptServiceClient } from '../typescriptService';
import API from '../utils/api';
import { VersionDependentRegistration } from '../utils/dependentRegistration';
const localize = nls.loadMessageBundle();
@ -36,7 +34,6 @@ const directives: Directive[] = [
];
class DirectiveCommentCompletionProvider implements vscode.CompletionItemProvider {
public static readonly minVersion = API.v230;
constructor(
private readonly client: ITypeScriptServiceClient,
@ -71,9 +68,7 @@ export function register(
selector: vscode.DocumentSelector,
client: ITypeScriptServiceClient,
) {
return new VersionDependentRegistration(client, DirectiveCommentCompletionProvider.minVersion, () => {
return vscode.languages.registerCompletionItemProvider(selector,
new DirectiveCommentCompletionProvider(client),
'@');
});
return vscode.languages.registerCompletionItemProvider(selector,
new DirectiveCommentCompletionProvider(client),
'@');
}

View file

@ -5,13 +5,9 @@
import * as vscode from 'vscode';
import { ITypeScriptServiceClient } from '../typescriptService';
import API from '../utils/api';
import { VersionDependentRegistration } from '../utils/dependentRegistration';
import DefinitionProviderBase from './definitionProviderBase';
class TypeScriptImplementationProvider extends DefinitionProviderBase implements vscode.ImplementationProvider {
public static readonly minVersion = API.v220;
public provideImplementation(document: vscode.TextDocument, position: vscode.Position, token: vscode.CancellationToken): Promise<vscode.Definition | undefined> {
return this.getSymbolLocations('implementation', document, position, token);
}
@ -21,8 +17,6 @@ export function register(
selector: vscode.DocumentSelector,
client: ITypeScriptServiceClient,
) {
return new VersionDependentRegistration(client, TypeScriptImplementationProvider.minVersion, () => {
return vscode.languages.registerImplementationProvider(selector,
new TypeScriptImplementationProvider(client));
});
}
return vscode.languages.registerImplementationProvider(selector,
new TypeScriptImplementationProvider(client));
}

View file

@ -8,8 +8,7 @@ import * as nls from 'vscode-nls';
import * as Proto from '../protocol';
import * as PConst from '../protocol.const';
import { ITypeScriptServiceClient } from '../typescriptService';
import API from '../utils/api';
import { ConfigurationDependentRegistration, VersionDependentRegistration } from '../utils/dependentRegistration';
import { ConfigurationDependentRegistration } from '../utils/dependentRegistration';
import { TypeScriptBaseCodeLensProvider, ReferencesCodeLens, getSymbolRange } from './baseCodeLensProvider';
import { CachedResponse } from '../tsServer/cachedResponse';
import * as typeConverters from '../utils/typeConverters';
@ -17,7 +16,6 @@ import * as typeConverters from '../utils/typeConverters';
const localize = nls.loadMessageBundle();
export default class TypeScriptImplementationsCodeLensProvider extends TypeScriptBaseCodeLensProvider {
public static readonly minVersion = API.v220;
public async resolveCodeLens(
inputCodeLens: vscode.CodeLens,
@ -96,9 +94,8 @@ export function register(
client: ITypeScriptServiceClient,
cachedResponse: CachedResponse<Proto.NavTreeResponse>,
) {
return new VersionDependentRegistration(client, TypeScriptImplementationsCodeLensProvider.minVersion, () =>
new ConfigurationDependentRegistration(modeId, 'implementationsCodeLens.enabled', () => {
return vscode.languages.registerCodeLensProvider(selector,
new TypeScriptImplementationsCodeLensProvider(client, cachedResponse));
}));
return new ConfigurationDependentRegistration(modeId, 'implementationsCodeLens.enabled', () => {
return vscode.languages.registerCodeLensProvider(selector,
new TypeScriptImplementationsCodeLensProvider(client, cachedResponse));
});
}

View file

@ -3,7 +3,6 @@
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import * as fs from 'fs';
import * as path from 'path';
import * as vscode from 'vscode';
import * as nls from 'vscode-nls';
@ -14,23 +13,20 @@ import { nulToken } from '../utils/cancellation';
import { VersionDependentRegistration } from '../utils/dependentRegistration';
import { Disposable } from '../utils/dispose';
import * as fileSchemes from '../utils/fileSchemes';
import { isTypeScriptDocument } from '../utils/languageModeIds';
import * as typeConverters from '../utils/typeConverters';
import FileConfigurationManager from './fileConfigurationManager';
import { Delayer } from '../utils/async';
const localize = nls.loadMessageBundle();
const updateImportsOnFileMoveName = 'updateImportsOnFileMove.enabled';
function isDirectory(path: string): Promise<boolean> {
return new Promise<boolean>((resolve, reject) => {
fs.stat(path, (err, stat) => {
if (err) {
return reject(err);
}
return resolve(stat.isDirectory());
});
});
async function isDirectory(resource: vscode.Uri): Promise<boolean> {
try {
return (await vscode.workspace.fs.stat(resource)).type === vscode.FileType.Directory;
} catch {
return false;
}
}
const enum UpdateImportsOnFileMoveSetting {
@ -39,9 +35,24 @@ const enum UpdateImportsOnFileMoveSetting {
Never = 'never',
}
interface RenameAction {
readonly oldUri: vscode.Uri;
readonly newUri: vscode.Uri;
readonly newFilePath: string;
readonly oldFilePath: string;
readonly jsTsFileThatIsBeingMoved: vscode.Uri;
}
function doesResourceLookLikeATypeScriptFile(resource: vscode.Uri): boolean {
return /\.tsx?$/i.test(resource.fsPath);
}
class UpdateImportsOnFileRenameHandler extends Disposable {
public static readonly minVersion = API.v300;
private readonly _delayer = new Delayer(50);
private readonly _pendingRenames = new Set<RenameAction>();
public constructor(
private readonly client: ITypeScriptServiceClient,
private readonly fileConfigurationManager: FileConfigurationManager,
@ -49,64 +60,74 @@ class UpdateImportsOnFileRenameHandler extends Disposable {
) {
super();
this._register(vscode.workspace.onDidRenameFile(e => {
vscode.window.withProgress({
location: vscode.ProgressLocation.Window,
title: localize('renameProgress.title', "Checking for update of JS/TS imports")
}, () => {
return this.doRename(e.oldUri, e.newUri);
this._register(vscode.workspace.onDidRenameFile(async ({ newUri, oldUri }) => {
const newFilePath = this.client.toPath(newUri);
if (!newFilePath) {
return;
}
const oldFilePath = this.client.toPath(oldUri);
if (!oldFilePath) {
return;
}
const config = this.getConfiguration(newUri);
const setting = config.get<UpdateImportsOnFileMoveSetting>(updateImportsOnFileMoveName);
if (setting === UpdateImportsOnFileMoveSetting.Never) {
return;
}
// Try to get a js/ts file that is being moved
// For directory moves, this returns a js/ts file under the directory.
const jsTsFileThatIsBeingMoved = await this.getJsTsFileBeingMoved(newUri);
if (!jsTsFileThatIsBeingMoved || !this.client.toPath(jsTsFileThatIsBeingMoved)) {
return;
}
this._pendingRenames.add({ oldUri, newUri, newFilePath, oldFilePath, jsTsFileThatIsBeingMoved });
this._delayer.trigger(() => {
vscode.window.withProgress({
location: vscode.ProgressLocation.Window,
title: localize('renameProgress.title', "Checking for update of JS/TS imports")
}, () => this.flushRenames());
});
}));
}
private async doRename(
oldResource: vscode.Uri,
newResource: vscode.Uri,
): Promise<void> {
// Try to get a js/ts file that is being moved
// For directory moves, this returns a js/ts file under the directory.
const jsTsFileThatIsBeingMoved = await this.getJsTsFileBeingMoved(newResource);
if (!jsTsFileThatIsBeingMoved || !this.client.toPath(jsTsFileThatIsBeingMoved)) {
return;
}
private async flushRenames(): Promise<void> {
const renames = Array.from(this._pendingRenames);
this._pendingRenames.clear();
for (const group of this.groupRenames(renames)) {
const edits = new vscode.WorkspaceEdit();
const resourcesBeingRenamed: vscode.Uri[] = [];
const newFile = this.client.toPath(newResource);
if (!newFile) {
return;
}
for (const { oldUri, newUri, newFilePath, oldFilePath, jsTsFileThatIsBeingMoved } of group) {
const document = await vscode.workspace.openTextDocument(jsTsFileThatIsBeingMoved);
const oldFile = this.client.toPath(oldResource);
if (!oldFile) {
return;
}
// Make sure TS knows about file
this.client.bufferSyncSupport.closeResource(oldUri);
this.client.bufferSyncSupport.openTextDocument(document);
const document = await vscode.workspace.openTextDocument(jsTsFileThatIsBeingMoved);
if (await this.withEditsForFileRename(edits, document, oldFilePath, newFilePath)) {
resourcesBeingRenamed.push(newUri);
}
}
const config = this.getConfiguration(document);
const setting = config.get<UpdateImportsOnFileMoveSetting>(updateImportsOnFileMoveName);
if (setting === UpdateImportsOnFileMoveSetting.Never) {
return;
}
// Make sure TS knows about file
this.client.bufferSyncSupport.closeResource(oldResource);
this.client.bufferSyncSupport.openTextDocument(document);
const edits = await this.getEditsForFileRename(document, oldFile, newFile);
if (!edits || !edits.size) {
return;
}
if (await this.confirmActionWithUser(newResource, document)) {
await vscode.workspace.applyEdit(edits);
if (edits.size) {
if (await this.confirmActionWithUser(resourcesBeingRenamed)) {
await vscode.workspace.applyEdit(edits);
}
}
}
}
private async confirmActionWithUser(
newResource: vscode.Uri,
newDocument: vscode.TextDocument
): Promise<boolean> {
const config = this.getConfiguration(newDocument);
private async confirmActionWithUser(newResources: readonly vscode.Uri[]): Promise<boolean> {
if (!newResources.length) {
return false;
}
const config = this.getConfiguration(newResources[0]);
const setting = config.get<UpdateImportsOnFileMoveSetting>(updateImportsOnFileMoveName);
switch (setting) {
case UpdateImportsOnFileMoveSetting.Always:
@ -115,18 +136,19 @@ class UpdateImportsOnFileRenameHandler extends Disposable {
return false;
case UpdateImportsOnFileMoveSetting.Prompt:
default:
return this.promptUser(newResource, newDocument);
return this.promptUser(newResources);
}
}
private getConfiguration(newDocument: vscode.TextDocument) {
return vscode.workspace.getConfiguration(isTypeScriptDocument(newDocument) ? 'typescript' : 'javascript', newDocument.uri);
private getConfiguration(resource: vscode.Uri) {
return vscode.workspace.getConfiguration(doesResourceLookLikeATypeScriptFile(resource) ? 'typescript' : 'javascript', resource);
}
private async promptUser(
newResource: vscode.Uri,
newDocument: vscode.TextDocument
): Promise<boolean> {
private async promptUser(newResources: readonly vscode.Uri[]): Promise<boolean> {
if (!newResources.length) {
return false;
}
const enum Choice {
None = 0,
Accept = 1,
@ -136,11 +158,14 @@ class UpdateImportsOnFileRenameHandler extends Disposable {
}
interface Item extends vscode.MessageItem {
choice: Choice;
readonly choice: Choice;
}
const response = await vscode.window.showInformationMessage<Item>(
localize('prompt', "Update imports for moved file: '{0}'?", path.basename(newResource.fsPath)), {
newResources.length === 1
? localize('prompt', "Update imports for '{0}'?", path.basename(newResources[0].fsPath))
: this.getConfirmMessage(localize('promptMoreThanOne', "Update imports for the following {0} files?", newResources.length), newResources), {
modal: true,
}, {
title: localize('reject.title', "No"),
@ -172,7 +197,7 @@ class UpdateImportsOnFileRenameHandler extends Disposable {
}
case Choice.Always:
{
const config = this.getConfiguration(newDocument);
const config = this.getConfiguration(newResources[0]);
config.update(
updateImportsOnFileMoveName,
UpdateImportsOnFileMoveSetting.Always,
@ -181,7 +206,7 @@ class UpdateImportsOnFileRenameHandler extends Disposable {
}
case Choice.Never:
{
const config = this.getConfiguration(newDocument);
const config = this.getConfiguration(newResources[0]);
config.update(
updateImportsOnFileMoveName,
UpdateImportsOnFileMoveSetting.Never,
@ -198,7 +223,7 @@ class UpdateImportsOnFileRenameHandler extends Disposable {
return undefined;
}
if (await isDirectory(resource.fsPath)) {
if (await isDirectory(resource)) {
const files = await vscode.workspace.findFiles({
base: resource.fsPath,
pattern: '**/*.{ts,tsx,js,jsx}',
@ -209,24 +234,60 @@ class UpdateImportsOnFileRenameHandler extends Disposable {
return (await this._handles(resource)) ? resource : undefined;
}
private async getEditsForFileRename(
private async withEditsForFileRename(
edits: vscode.WorkspaceEdit,
document: vscode.TextDocument,
oldFile: string,
newFile: string,
): Promise<vscode.WorkspaceEdit | undefined> {
oldFilePath: string,
newFilePath: string,
): Promise<boolean> {
const response = await this.client.interruptGetErr(() => {
this.fileConfigurationManager.setGlobalConfigurationFromDocument(document, nulToken);
const args: Proto.GetEditsForFileRenameRequestArgs = {
oldFilePath: oldFile,
newFilePath: newFile,
oldFilePath,
newFilePath,
};
return this.client.execute('getEditsForFileRename', args, nulToken);
});
if (response.type !== 'response' || !response.body) {
return;
if (response.type !== 'response' || !response.body.length) {
return false;
}
return typeConverters.WorkspaceEdit.fromFileCodeEdits(this.client, response.body);
typeConverters.WorkspaceEdit.withFileCodeEdits(edits, this.client, response.body);
return true;
}
private groupRenames(renames: Iterable<RenameAction>): Iterable<Iterable<RenameAction>> {
const groups = new Map<string, Set<RenameAction>>();
for (const rename of renames) {
// Group renames by type (js/ts) and by workspace.
const key = `${this.client.getWorkspaceRootForResource(rename.jsTsFileThatIsBeingMoved)}@@@${doesResourceLookLikeATypeScriptFile(rename.jsTsFileThatIsBeingMoved)}`;
if (!groups.has(key)) {
groups.set(key, new Set());
}
groups.get(key)!.add(rename);
}
return groups.values();
}
private getConfirmMessage(start: string, resourcesToConfirm: readonly vscode.Uri[]): string {
const MAX_CONFIRM_FILES = 10;
const paths = [start];
paths.push('');
paths.push(...resourcesToConfirm.slice(0, MAX_CONFIRM_FILES).map(r => path.basename(r.fsPath)));
if (resourcesToConfirm.length > MAX_CONFIRM_FILES) {
if (resourcesToConfirm.length - MAX_CONFIRM_FILES === 1) {
paths.push(localize('moreFile', "...1 additional file not shown"));
} else {
paths.push(localize('moreFiles', "...{0} additional files not shown", resourcesToConfirm.length - MAX_CONFIRM_FILES));
}
}
paths.push('');
return paths.join('\n');
}
}

View file

@ -64,7 +64,7 @@ export class TypeScriptServerSpawner {
const { args, cancellationPipeName, tsServerLogFile } = this.getTsServerArgs(kind, configuration, version, apiVersion, pluginManager);
if (TypeScriptServerSpawner.isLoggingEnabled(apiVersion, configuration)) {
if (TypeScriptServerSpawner.isLoggingEnabled(configuration)) {
if (tsServerLogFile) {
this._logger.info(`<${kind}> Log file: ${tsServerLogFile}`);
} else {
@ -103,9 +103,8 @@ export class TypeScriptServerSpawner {
currentVersion: TypeScriptVersion,
apiVersion: API,
pluginManager: PluginManager,
): { args: string[], cancellationPipeName: string | undefined, tsServerLogFile: string | undefined } {
): { args: string[], cancellationPipeName: string, tsServerLogFile: string | undefined } {
const args: string[] = [];
let cancellationPipeName: string | undefined;
let tsServerLogFile: string | undefined;
if (kind === 'syntax') {
@ -126,12 +125,10 @@ export class TypeScriptServerSpawner {
args.push('--enableTelemetry');
}
if (apiVersion.gte(API.v222)) {
cancellationPipeName = electron.getTempFile('tscancellation');
args.push('--cancellationPipeName', cancellationPipeName + '*');
}
const cancellationPipeName = electron.getTempFile('tscancellation');
args.push('--cancellationPipeName', cancellationPipeName + '*');
if (TypeScriptServerSpawner.isLoggingEnabled(apiVersion, configuration)) {
if (TypeScriptServerSpawner.isLoggingEnabled(configuration)) {
const logDir = this._logDirectoryProvider.getNewLogDirectory();
if (logDir) {
tsServerLogFile = path.join(logDir, `tsserver.log`);
@ -140,29 +137,25 @@ export class TypeScriptServerSpawner {
}
}
if (apiVersion.gte(API.v230)) {
const pluginPaths = this._pluginPathsProvider.getPluginPaths();
const pluginPaths = this._pluginPathsProvider.getPluginPaths();
if (pluginManager.plugins.length) {
args.push('--globalPlugins', pluginManager.plugins.map(x => x.name).join(','));
if (pluginManager.plugins.length) {
args.push('--globalPlugins', pluginManager.plugins.map(x => x.name).join(','));
const isUsingBundledTypeScriptVersion = currentVersion.path === this._versionProvider.defaultVersion.path;
for (const plugin of pluginManager.plugins) {
if (isUsingBundledTypeScriptVersion || plugin.enableForWorkspaceTypeScriptVersions) {
pluginPaths.push(plugin.path);
}
const isUsingBundledTypeScriptVersion = currentVersion.path === this._versionProvider.defaultVersion.path;
for (const plugin of pluginManager.plugins) {
if (isUsingBundledTypeScriptVersion || plugin.enableForWorkspaceTypeScriptVersions) {
pluginPaths.push(plugin.path);
}
}
if (pluginPaths.length !== 0) {
args.push('--pluginProbeLocations', pluginPaths.join(','));
}
}
if (apiVersion.gte(API.v234)) {
if (configuration.npmLocation) {
args.push('--npmLocation', `"${configuration.npmLocation}"`);
}
if (pluginPaths.length !== 0) {
args.push('--pluginProbeLocations', pluginPaths.join(','));
}
if (configuration.npmLocation) {
args.push('--npmLocation', `"${configuration.npmLocation}"`);
}
if (apiVersion.gte(API.v260)) {
@ -195,9 +188,8 @@ export class TypeScriptServerSpawner {
return undefined;
}
private static isLoggingEnabled(apiVersion: API, configuration: TypeScriptServiceConfiguration) {
return apiVersion.gte(API.v222) &&
configuration.tsServerLogLevel !== TsServerLogLevel.Off;
private static isLoggingEnabled(configuration: TypeScriptServiceConfiguration) {
return configuration.tsServerLogLevel !== TsServerLogLevel.Off;
}
private static getTsLocale(configuration: TypeScriptServiceConfiguration): string {

View file

@ -15,7 +15,6 @@ import LanguageProvider from './languageProvider';
import * as Proto from './protocol';
import * as PConst from './protocol.const';
import TypeScriptServiceClient from './typescriptServiceClient';
import API from './utils/api';
import { CommandManager } from './utils/commandManager';
import { Disposable } from './utils/dispose';
import { DiagnosticLanguage, LanguageDescription } from './utils/languageDescription';
@ -105,10 +104,6 @@ export default class TypeScriptServiceClientHost extends Disposable {
this.client.ensureServiceStarted();
this.client.onReady(() => {
if (this.client.apiVersion.lt(API.v230)) {
return;
}
const languages = new Set<string>();
for (const plugin of pluginManager.plugins) {
for (const language of plugin.languages) {

View file

@ -392,14 +392,6 @@ export default class TypeScriptServiceClient extends Disposable implements IType
}
public async openTsServerLogFile(): Promise<boolean> {
if (this.apiVersion.lt(API.v222)) {
vscode.window.showErrorMessage(
localize(
'typescript.openTsServerLog.notSupported',
'TS Server logging requires TS 2.2.2+'));
return false;
}
if (this._configuration.tsServerLogLevel === TsServerLogLevel.Off) {
vscode.window.showErrorMessage<vscode.MessageItem>(
localize(

View file

@ -14,10 +14,6 @@ export default class API {
}
public static readonly defaultVersion = API.fromSimpleString('1.0.0');
public static readonly v220 = API.fromSimpleString('2.2.0');
public static readonly v222 = API.fromSimpleString('2.2.2');
public static readonly v230 = API.fromSimpleString('2.3.0');
public static readonly v234 = API.fromSimpleString('2.3.4');
public static readonly v240 = API.fromSimpleString('2.4.0');
public static readonly v250 = API.fromSimpleString('2.5.0');
public static readonly v260 = API.fromSimpleString('2.6.0');

View file

@ -1,7 +1,7 @@
{
"name": "code-oss-dev",
"version": "1.40.0",
"distro": "e8c2fa7c1c2249304102104d56e7cacb37ca27ec",
"distro": "f0585fa45498242d599deeb2bb18393f704f25d9",
"author": {
"name": "Microsoft Corporation"
},
@ -53,8 +53,8 @@
"vscode-ripgrep": "^1.5.7",
"vscode-sqlite3": "4.0.8",
"vscode-textmate": "^4.2.2",
"xterm": "^4.2.0-beta20",
"xterm-addon-search": "0.3.0-beta5",
"xterm": "^4.2.0-beta24",
"xterm-addon-search": "0.3.0-beta10",
"xterm-addon-web-links": "0.2.1",
"yauzl": "^2.9.2",
"yazl": "^2.4.3"

View file

@ -20,8 +20,8 @@
"vscode-proxy-agent": "0.4.0",
"vscode-ripgrep": "^1.5.7",
"vscode-textmate": "^4.2.2",
"xterm": "^4.2.0-beta20",
"xterm-addon-search": "0.3.0-beta5",
"xterm": "^4.2.0-beta24",
"xterm-addon-search": "0.3.0-beta10",
"xterm-addon-web-links": "0.2.1",
"yauzl": "^2.9.2",
"yazl": "^2.4.3"

View file

@ -5,8 +5,8 @@
"onigasm-umd": "^2.2.2",
"semver-umd": "^5.5.3",
"vscode-textmate": "^4.2.2",
"xterm": "^4.2.0-beta20",
"xterm-addon-search": "0.3.0-beta5",
"xterm": "^4.2.0-beta24",
"xterm-addon-search": "0.3.0-beta10",
"xterm-addon-web-links": "0.2.1"
}
}

View file

@ -31,17 +31,17 @@ vscode-textmate@^4.2.2:
dependencies:
oniguruma "^7.2.0"
xterm-addon-search@0.3.0-beta5:
version "0.3.0-beta5"
resolved "https://registry.yarnpkg.com/xterm-addon-search/-/xterm-addon-search-0.3.0-beta5.tgz#fd53d33a77a0235018479c712be8c12f7c0d083a"
integrity sha512-3GkGc4hST35/4hzgnQPLLvQ29WH7MkZ0mUrBE/Vm1IQum7TnMvWPTkGemwM+wAl4tdBmynNccHJlFeQzaQtVUg==
xterm-addon-search@0.3.0-beta10:
version "0.3.0-beta10"
resolved "https://registry.yarnpkg.com/xterm-addon-search/-/xterm-addon-search-0.3.0-beta10.tgz#24ca32062e8a2488e7df5d2e30855f0e2ce3e23d"
integrity sha512-3yPcHDgUYBM7Co5KGJkdOPUsRj2i+ZfhLSAJrHTNEP2vK6x6dO3YJ6M+YfBfiqP6ATXBXa+xTi0h0AV/IMukvQ==
xterm-addon-web-links@0.2.1:
version "0.2.1"
resolved "https://registry.yarnpkg.com/xterm-addon-web-links/-/xterm-addon-web-links-0.2.1.tgz#6d1f2ce613e09870badf17615e7a1170a31542b2"
integrity sha512-2KnHtiq0IG7hfwv3jw2/jQeH1RBk2d5CH4zvgwQe00rLofSJqSfgnJ7gwowxxpGHrpbPr6Lv4AmH/joaNw2+HQ==
xterm@^4.2.0-beta20:
version "4.2.0-beta20"
resolved "https://registry.yarnpkg.com/xterm/-/xterm-4.2.0-beta20.tgz#74a759414511b4577159293397914ac33a2375d8"
integrity sha512-lH52ksaNQqWmLVV4OdLKWvhGkSRUXgJNvb2YYmVkBAm1PdVVS36ir8Qr4zYygnc2tBw689Wj65t4cNckmfpU1Q==
xterm@^4.2.0-beta24:
version "4.2.0-beta24"
resolved "https://registry.yarnpkg.com/xterm/-/xterm-4.2.0-beta24.tgz#3f68ec50d9ae1ec2e0ee1e35f1e9f25c4060cc07"
integrity sha512-71qwhH3uo2V68QX/hEgjpn6wZ/XU1N9DzhbTBUVT0z1pJsCz9JUeDqIxenIIqkRut/MlzxUDU7mw/pX+ZVFCfg==

View file

@ -411,20 +411,20 @@ vscode-windows-registry@1.0.2:
resolved "https://registry.yarnpkg.com/vscode-windows-registry/-/vscode-windows-registry-1.0.2.tgz#b863e704a6a69c50b3098a55fbddbe595b0c124a"
integrity sha512-/CLLvuOSM2Vme2z6aNyB+4Omd7hDxpf4Thrt8ImxnXeQtxzel2bClJpFQvQqK/s4oaXlkBKS7LqVLeZM+uSVIA==
xterm-addon-search@0.3.0-beta5:
version "0.3.0-beta5"
resolved "https://registry.yarnpkg.com/xterm-addon-search/-/xterm-addon-search-0.3.0-beta5.tgz#fd53d33a77a0235018479c712be8c12f7c0d083a"
integrity sha512-3GkGc4hST35/4hzgnQPLLvQ29WH7MkZ0mUrBE/Vm1IQum7TnMvWPTkGemwM+wAl4tdBmynNccHJlFeQzaQtVUg==
xterm-addon-search@0.3.0-beta10:
version "0.3.0-beta10"
resolved "https://registry.yarnpkg.com/xterm-addon-search/-/xterm-addon-search-0.3.0-beta10.tgz#24ca32062e8a2488e7df5d2e30855f0e2ce3e23d"
integrity sha512-3yPcHDgUYBM7Co5KGJkdOPUsRj2i+ZfhLSAJrHTNEP2vK6x6dO3YJ6M+YfBfiqP6ATXBXa+xTi0h0AV/IMukvQ==
xterm-addon-web-links@0.2.1:
version "0.2.1"
resolved "https://registry.yarnpkg.com/xterm-addon-web-links/-/xterm-addon-web-links-0.2.1.tgz#6d1f2ce613e09870badf17615e7a1170a31542b2"
integrity sha512-2KnHtiq0IG7hfwv3jw2/jQeH1RBk2d5CH4zvgwQe00rLofSJqSfgnJ7gwowxxpGHrpbPr6Lv4AmH/joaNw2+HQ==
xterm@^4.2.0-beta20:
version "4.2.0-beta20"
resolved "https://registry.yarnpkg.com/xterm/-/xterm-4.2.0-beta20.tgz#74a759414511b4577159293397914ac33a2375d8"
integrity sha512-lH52ksaNQqWmLVV4OdLKWvhGkSRUXgJNvb2YYmVkBAm1PdVVS36ir8Qr4zYygnc2tBw689Wj65t4cNckmfpU1Q==
xterm@^4.2.0-beta24:
version "4.2.0-beta24"
resolved "https://registry.yarnpkg.com/xterm/-/xterm-4.2.0-beta24.tgz#3f68ec50d9ae1ec2e0ee1e35f1e9f25c4060cc07"
integrity sha512-71qwhH3uo2V68QX/hEgjpn6wZ/XU1N9DzhbTBUVT0z1pJsCz9JUeDqIxenIIqkRut/MlzxUDU7mw/pX+ZVFCfg==
yauzl@^2.9.2:
version "2.10.0"

View file

@ -860,7 +860,7 @@ declare module 'xterm' {
/**
* An object representing a range within the viewport of the terminal.
*/
interface IViewportRange {
export interface IViewportRange {
/**
* The start cell of the range.
*/

View file

@ -5,7 +5,7 @@
@font-face {
font-family: "codicon";
src: url("./codicon.ttf?3a05fcfc657285cdb4cd3eba790b7462") format("truetype");
src: url("./codicon.ttf?297296ccad95f5838f73ae67efd78fbc") format("truetype");
}
.codicon[class*='codicon-'] {
@ -309,75 +309,77 @@
.codicon-references:before { content: "\f1a0" }
.codicon-refresh:before { content: "\f1a1" }
.codicon-regex:before { content: "\f1a2" }
.codicon-remote:before { content: "\f1a3" }
.codicon-remove:before { content: "\f1a4" }
.codicon-replace-all:before { content: "\f1a5" }
.codicon-replace:before { content: "\f1a6" }
.codicon-repo-clone:before { content: "\f1a7" }
.codicon-repo-force-push:before { content: "\f1a8" }
.codicon-repo-pull:before { content: "\f1a9" }
.codicon-repo-push:before { content: "\f1aa" }
.codicon-report:before { content: "\f1ab" }
.codicon-request-changes:before { content: "\f1ac" }
.codicon-rocket:before { content: "\f1ad" }
.codicon-root-folder-opened:before { content: "\f1ae" }
.codicon-root-folder:before { content: "\f1af" }
.codicon-rss:before { content: "\f1b0" }
.codicon-ruby:before { content: "\f1b1" }
.codicon-save-all:before { content: "\f1b2" }
.codicon-save-as:before { content: "\f1b3" }
.codicon-save:before { content: "\f1b4" }
.codicon-screen-full:before { content: "\f1b5" }
.codicon-screen-normal:before { content: "\f1b6" }
.codicon-search-stop:before { content: "\f1b7" }
.codicon-selection:before { content: "\f1b8" }
.codicon-server:before { content: "\f1b9" }
.codicon-settings:before { content: "\f1ba" }
.codicon-shield:before { content: "\f1bb" }
.codicon-smiley:before { content: "\f1bc" }
.codicon-sort-precedence:before { content: "\f1bd" }
.codicon-split-horizontal:before { content: "\f1be" }
.codicon-split-vertical:before { content: "\f1bf" }
.codicon-squirrel:before { content: "\f1c0" }
.codicon-star-full:before { content: "\f1c1" }
.codicon-star-half:before { content: "\f1c2" }
.codicon-symbol-class:before { content: "\f1c3" }
.codicon-symbol-color:before { content: "\f1c4" }
.codicon-symbol-constant:before { content: "\f1c5" }
.codicon-symbol-enum-member:before { content: "\f1c6" }
.codicon-symbol-field:before { content: "\f1c7" }
.codicon-symbol-file:before { content: "\f1c8" }
.codicon-symbol-interface:before { content: "\f1c9" }
.codicon-symbol-keyword:before { content: "\f1ca" }
.codicon-symbol-misc:before { content: "\f1cb" }
.codicon-symbol-operator:before { content: "\f1cc" }
.codicon-symbol-property:before { content: "\f1cd" }
.codicon-symbol-snippet:before { content: "\f1ce" }
.codicon-tasklist:before { content: "\f1cf" }
.codicon-telescope:before { content: "\f1d0" }
.codicon-text-size:before { content: "\f1d1" }
.codicon-three-bars:before { content: "\f1d2" }
.codicon-thumbsdown:before { content: "\f1d3" }
.codicon-thumbsup:before { content: "\f1d4" }
.codicon-tools:before { content: "\f1d5" }
.codicon-triangle-down:before { content: "\f1d6" }
.codicon-triangle-left:before { content: "\f1d7" }
.codicon-triangle-right:before { content: "\f1d8" }
.codicon-triangle-up:before { content: "\f1d9" }
.codicon-twitter:before { content: "\f1da" }
.codicon-unfold:before { content: "\f1db" }
.codicon-unlock:before { content: "\f1dc" }
.codicon-unmute:before { content: "\f1dd" }
.codicon-unverified:before { content: "\f1de" }
.codicon-verified:before { content: "\f1df" }
.codicon-versions:before { content: "\f1e0" }
.codicon-vm-active:before { content: "\f1e1" }
.codicon-vm-outline:before { content: "\f1e2" }
.codicon-vm-running:before { content: "\f1e3" }
.codicon-watch:before { content: "\f1e4" }
.codicon-whitespace:before { content: "\f1e5" }
.codicon-whole-word:before { content: "\f1e6" }
.codicon-window:before { content: "\f1e7" }
.codicon-word-wrap:before { content: "\f1e8" }
.codicon-zoom-in:before { content: "\f1e9" }
.codicon-zoom-out:before { content: "\f1ea" }
.codicon-remote-explorer:before { content: "\f1a3" }
.codicon-remote:before { content: "\f1a4" }
.codicon-remove:before { content: "\f1a5" }
.codicon-replace-all:before { content: "\f1a6" }
.codicon-replace:before { content: "\f1a7" }
.codicon-repo-clone:before { content: "\f1a8" }
.codicon-repo-force-push:before { content: "\f1a9" }
.codicon-repo-pull:before { content: "\f1aa" }
.codicon-repo-push:before { content: "\f1ab" }
.codicon-report:before { content: "\f1ac" }
.codicon-request-changes:before { content: "\f1ad" }
.codicon-rocket:before { content: "\f1ae" }
.codicon-root-folder-opened:before { content: "\f1af" }
.codicon-root-folder:before { content: "\f1b0" }
.codicon-rss:before { content: "\f1b1" }
.codicon-ruby:before { content: "\f1b2" }
.codicon-save-all:before { content: "\f1b3" }
.codicon-save-as:before { content: "\f1b4" }
.codicon-save:before { content: "\f1b5" }
.codicon-screen-full:before { content: "\f1b6" }
.codicon-screen-normal:before { content: "\f1b7" }
.codicon-search-stop:before { content: "\f1b8" }
.codicon-selection:before { content: "\f1b9" }
.codicon-server:before { content: "\f1ba" }
.codicon-settings-gear:before { content: "\f1bb" }
.codicon-settings:before { content: "\f1bc" }
.codicon-shield:before { content: "\f1bd" }
.codicon-smiley:before { content: "\f1be" }
.codicon-sort-precedence:before { content: "\f1bf" }
.codicon-split-horizontal:before { content: "\f1c0" }
.codicon-split-vertical:before { content: "\f1c1" }
.codicon-squirrel:before { content: "\f1c2" }
.codicon-star-full:before { content: "\f1c3" }
.codicon-star-half:before { content: "\f1c4" }
.codicon-symbol-class:before { content: "\f1c5" }
.codicon-symbol-color:before { content: "\f1c6" }
.codicon-symbol-constant:before { content: "\f1c7" }
.codicon-symbol-enum-member:before { content: "\f1c8" }
.codicon-symbol-field:before { content: "\f1c9" }
.codicon-symbol-file:before { content: "\f1ca" }
.codicon-symbol-interface:before { content: "\f1cb" }
.codicon-symbol-keyword:before { content: "\f1cc" }
.codicon-symbol-misc:before { content: "\f1cd" }
.codicon-symbol-operator:before { content: "\f1ce" }
.codicon-symbol-property:before { content: "\f1cf" }
.codicon-symbol-snippet:before { content: "\f1d0" }
.codicon-tasklist:before { content: "\f1d1" }
.codicon-telescope:before { content: "\f1d2" }
.codicon-text-size:before { content: "\f1d3" }
.codicon-three-bars:before { content: "\f1d4" }
.codicon-thumbsdown:before { content: "\f1d5" }
.codicon-thumbsup:before { content: "\f1d6" }
.codicon-tools:before { content: "\f1d7" }
.codicon-triangle-down:before { content: "\f1d8" }
.codicon-triangle-left:before { content: "\f1d9" }
.codicon-triangle-right:before { content: "\f1da" }
.codicon-triangle-up:before { content: "\f1db" }
.codicon-twitter:before { content: "\f1dc" }
.codicon-unfold:before { content: "\f1dd" }
.codicon-unlock:before { content: "\f1de" }
.codicon-unmute:before { content: "\f1df" }
.codicon-unverified:before { content: "\f1e0" }
.codicon-verified:before { content: "\f1e1" }
.codicon-versions:before { content: "\f1e2" }
.codicon-vm-active:before { content: "\f1e3" }
.codicon-vm-outline:before { content: "\f1e4" }
.codicon-vm-running:before { content: "\f1e5" }
.codicon-watch:before { content: "\f1e6" }
.codicon-whitespace:before { content: "\f1e7" }
.codicon-whole-word:before { content: "\f1e8" }
.codicon-window:before { content: "\f1e9" }
.codicon-word-wrap:before { content: "\f1ea" }
.codicon-zoom-in:before { content: "\f1eb" }
.codicon-zoom-out:before { content: "\f1ec" }

View file

@ -338,6 +338,34 @@ export function compareIgnoreCase(a: string, b: string): number {
}
}
/**
* [0-9]
*/
export function isAsciiDigit(code: number): boolean {
return code >= CharCode.Digit0 && code <= CharCode.Digit9;
}
/**
* [a-f]
*/
export function isLowerAsciiHex(code: number): boolean {
return code >= CharCode.a && code <= CharCode.f;
}
/**
* [A-F]
*/
export function isUpperAsciiHex(code: number): boolean {
return code >= CharCode.A && code <= CharCode.F;
}
/**
* [0-9a-fA-F]
*/
export function isAsciiHex(code: number): boolean {
return isAsciiDigit(code) || isLowerAsciiHex(code) || isUpperAsciiHex(code);
}
export function isLowerAsciiLetter(code: number): boolean {
return code >= CharCode.a && code <= CharCode.z;
}
@ -346,7 +374,7 @@ export function isUpperAsciiLetter(code: number): boolean {
return code >= CharCode.A && code <= CharCode.Z;
}
function isAsciiLetter(code: number): boolean {
export function isAsciiLetter(code: number): boolean {
return isLowerAsciiLetter(code) || isUpperAsciiLetter(code);
}

View file

@ -5,10 +5,9 @@
import { isWindows } from 'vs/base/common/platform';
import { CharCode } from 'vs/base/common/charCode';
import { isHighSurrogate, isLowSurrogate, isLowerAsciiHex, isAsciiLetter } from 'vs/base/common/strings';
const _schemePattern = /^\w[\w\d+.-]*$/;
const _singleSlashStart = /^\//;
const _doubleSlashStart = /^\/\//;
const _schemeRegExp = /^\w[\w\d+.-]*$/;
function _validateUri(ret: URI): void {
@ -19,7 +18,7 @@ function _validateUri(ret: URI): void {
// scheme, https://tools.ietf.org/html/rfc3986#section-3.1
// ALPHA *( ALPHA / DIGIT / "+" / "-" / "." )
if (ret.scheme && !_schemePattern.test(ret.scheme)) {
if (ret.scheme && !_schemeRegExp.test(ret.scheme)) {
throw new Error('[UriError]: Scheme contains illegal characters.');
}
@ -30,11 +29,11 @@ function _validateUri(ret: URI): void {
// with two slash characters ("//").
if (ret.path) {
if (ret.authority) {
if (!_singleSlashStart.test(ret.path)) {
if (ret.path.charCodeAt(0) !== CharCode.Slash) {
throw new Error('[UriError]: If a URI contains an authority component, then the path component must either be empty or begin with a slash ("/") character');
}
} else {
if (_doubleSlashStart.test(ret.path)) {
if (ret.path.charCodeAt(0) === CharCode.Slash && ret.path.charCodeAt(1) === CharCode.Slash) {
throw new Error('[UriError]: If a URI does not contain an authority component, then the path cannot begin with two slash characters ("//")');
}
}
@ -42,10 +41,14 @@ function _validateUri(ret: URI): void {
}
// graceful behaviour when scheme is missing: fallback to using 'file'-scheme
function _schemeFix(scheme: string): string {
function _schemeFix(scheme: string, strict?: boolean): string {
if (!scheme) {
console.trace('BAD uri lacks scheme, falling back to file-scheme.');
scheme = 'file';
if (strict) {
throw new Error('[UriError]: A scheme must be provided');
} else {
// console.trace('BAD uri lacks scheme, falling back to file-scheme.');
scheme = 'file';
}
}
return scheme;
}
@ -62,18 +65,29 @@ function _referenceResolution(scheme: string, path: string): string {
case 'http':
case 'file':
if (!path) {
path = _slash;
} else if (path[0] !== _slash) {
path = _slash + path;
path = '/';
} else if (path[0].charCodeAt(0) !== CharCode.Slash) {
path = '/' + path;
}
break;
}
return path;
}
const _empty = '';
const _slash = '/';
const _regexp = /^(([^:/?#]+?):)?(\/\/([^/?#]*))?([^?#]*)(\?([^#]*))?(#(.*))?/;
const _uriRegExp = /^(([^:/?#]+?):)?(\/\/([^/?#]*))?([^?#]*)(\?([^#]*))?(#(.*))?/;
const enum MatchIndex {
scheme = 2,
authority = 4,
path = 5,
query = 7,
fragment = 9
}
const _percentRegExp = /%/g;
const _hashRegExp = /#/g;
const _backslashRegExp = /\\/g;
const _slashRegExp = /\//g;
/**
* Uniform Resource Identifier (URI) http://tools.ietf.org/html/rfc3986.
@ -151,20 +165,20 @@ export class URI implements UriComponents {
protected constructor(schemeOrData: string | UriComponents, authority?: string, path?: string, query?: string, fragment?: string) {
if (typeof schemeOrData === 'object') {
this.scheme = schemeOrData.scheme || _empty;
this.authority = schemeOrData.authority || _empty;
this.path = schemeOrData.path || _empty;
this.query = schemeOrData.query || _empty;
this.fragment = schemeOrData.fragment || _empty;
this.scheme = schemeOrData.scheme || '';
this.authority = schemeOrData.authority || '';
this.path = schemeOrData.path || '';
this.query = schemeOrData.query || '';
this.fragment = schemeOrData.fragment || '';
// no validation because it's this URI
// that creates uri components.
// _validateUri(this);
} else {
this.scheme = _schemeFix(schemeOrData);
this.authority = authority || _empty;
this.path = _referenceResolution(this.scheme, path || _empty);
this.query = query || _empty;
this.fragment = fragment || _empty;
this.authority = authority || '';
this.path = _referenceResolution(this.scheme, path || '');
this.query = query || '';
this.fragment = fragment || '';
_validateUri(this);
}
@ -197,10 +211,7 @@ export class URI implements UriComponents {
* with URIs that represent files on disk (`file` scheme).
*/
get fsPath(): string {
// if (this.scheme !== 'file') {
// console.warn(`[UriError] calling fsPath with scheme ${this.scheme}`);
// }
return _makeFsPath(this);
return _toFsPath(this.scheme, this.authority, this.path);
}
// ---- modify to new -------------------------
@ -215,27 +226,27 @@ export class URI implements UriComponents {
if (scheme === undefined) {
scheme = this.scheme;
} else if (scheme === null) {
scheme = _empty;
scheme = '';
}
if (authority === undefined) {
authority = this.authority;
} else if (authority === null) {
authority = _empty;
authority = '';
}
if (path === undefined) {
path = this.path;
} else if (path === null) {
path = _empty;
path = '';
}
if (query === undefined) {
query = this.query;
} else if (query === null) {
query = _empty;
query = '';
}
if (fragment === undefined) {
fragment = this.fragment;
} else if (fragment === null) {
fragment = _empty;
fragment = '';
}
if (scheme === this.scheme
@ -256,20 +267,31 @@ export class URI implements UriComponents {
* Creates a new URI from a string, e.g. `http://www.msft.com/some/path`,
* `file:///usr/home`, or `scheme:with/path`.
*
* *Note:* When the input lacks a scheme then `file` is used.
*
* @param value A string which represents an URI (see `URI#toString`).
*/
static parse(value: string): URI {
const match = _regexp.exec(value);
static parse(value: string, strict?: boolean): URI {
const match = _uriRegExp.exec(value);
if (!match) {
return new _URI(_empty, _empty, _empty, _empty, _empty);
throw new Error(`[UriError]: Invalid input: ${value}`);
}
return new _URI(
match[2] || _empty,
decodeURIComponent(match[4] || _empty),
decodeURIComponent(match[5] || _empty),
decodeURIComponent(match[7] || _empty),
decodeURIComponent(match[9] || _empty)
const scheme = _schemeFix(match[MatchIndex.scheme], strict) || '';
const authority = match[MatchIndex.authority] || '';
const path = _referenceResolution(scheme, match[MatchIndex.path] || '');
const query = match[MatchIndex.query] || '';
const fragment = match[MatchIndex.fragment] || '';
const result = new _URI(
scheme,
percentDecode(authority),
percentDecode(path),
percentDecode(query),
percentDecode(fragment),
);
result._external = _toExternal(_normalEncoder, scheme, authority, path, query, fragment);
return result;
}
/**
@ -295,29 +317,41 @@ export class URI implements UriComponents {
*/
static file(path: string): URI {
let authority = _empty;
let authority = '';
// normalize to fwd-slashes on windows,
// on other systems bwd-slashes are valid
// filename character, eg /f\oo/ba\r.txt
if (isWindows) {
path = path.replace(/\\/g, _slash);
path = path.replace(_backslashRegExp, '/');
}
// check for authority as used in UNC shares
// or use the path as given
if (path[0] === _slash && path[1] === _slash) {
const idx = path.indexOf(_slash, 2);
if (path.charCodeAt(0) === CharCode.Slash && path.charCodeAt(1) === CharCode.Slash) {
const idx = path.indexOf('/', 2);
if (idx === -1) {
authority = path.substring(2);
path = _slash;
path = '/';
} else {
authority = path.substring(2, idx);
path = path.substring(idx) || _slash;
path = path.substring(idx) || '/';
}
}
return new _URI('file', authority, path, _empty, _empty);
// ensures that path starts with /
path = _referenceResolution('file', path);
// escape some vital characters
authority = authority.replace(_percentRegExp, '%25');
path = path.replace(_percentRegExp, '%25');
path = path.replace(_hashRegExp, '%23');
if (!isWindows) {
path = path.replace(_backslashRegExp, '%5C');
}
return URI.parse('file://' + authority + path);
}
static from(components: { scheme: string; authority?: string; path?: string; query?: string; fragment?: string; }): URI {
@ -344,7 +378,7 @@ export class URI implements UriComponents {
* @param skipEncoding Do not encode the result, default is `false`
*/
toString(skipEncoding: boolean = false): string {
return _asFormatted(this, skipEncoding);
return _toExternal(skipEncoding ? _minimalEncoder : _normalEncoder, this.scheme, this.authority, this.path, this.query, this.fragment);
}
toJSON(): UriComponents {
@ -362,7 +396,7 @@ export class URI implements UriComponents {
return data;
} else {
const result = new _URI(data);
result._formatted = (<UriState>data).external;
result._external = (<UriState>data).external;
result._fsPath = (<UriState>data)._sep === _pathSepMarker ? (<UriState>data).fsPath : null;
return result;
}
@ -389,26 +423,25 @@ const _pathSepMarker = isWindows ? 1 : undefined;
// tslint:disable-next-line:class-name
class _URI extends URI {
_formatted: string | null = null;
_external: string | null = null;
_fsPath: string | null = null;
get fsPath(): string {
if (!this._fsPath) {
this._fsPath = _makeFsPath(this);
this._fsPath = _toFsPath(this.scheme, this.authority, this.path);
}
return this._fsPath;
}
toString(skipEncoding: boolean = false): string {
if (!skipEncoding) {
if (!this._formatted) {
this._formatted = _asFormatted(this, false);
}
return this._formatted;
} else {
if (skipEncoding) {
// we don't cache that
return _asFormatted(this, true);
return _toExternal(_minimalEncoder, this.scheme, this.authority, this.path, this.query, this.fragment);
}
if (!this._external) {
this._external = _toExternal(_normalEncoder, this.scheme, this.authority, this.path, this.query, this.fragment);
}
return this._external;
}
toJSON(): UriComponents {
@ -420,8 +453,8 @@ class _URI extends URI {
res.fsPath = this._fsPath;
res._sep = _pathSepMarker;
}
if (this._formatted) {
res.external = this._formatted;
if (this._external) {
res.external = this._external;
}
// uri components
if (this.path) {
@ -443,205 +476,221 @@ class _URI extends URI {
}
}
// reserved characters: https://tools.ietf.org/html/rfc3986#section-2.2
const encodeTable: { [ch: number]: string; } = {
[CharCode.Colon]: '%3A', // gen-delims
[CharCode.Slash]: '%2F',
[CharCode.QuestionMark]: '%3F',
[CharCode.Hash]: '%23',
[CharCode.OpenSquareBracket]: '%5B',
[CharCode.CloseSquareBracket]: '%5D',
[CharCode.AtSign]: '%40',
[CharCode.ExclamationMark]: '%21', // sub-delims
[CharCode.DollarSign]: '%24',
[CharCode.Ampersand]: '%26',
[CharCode.SingleQuote]: '%27',
[CharCode.OpenParen]: '%28',
[CharCode.CloseParen]: '%29',
[CharCode.Asterisk]: '%2A',
[CharCode.Plus]: '%2B',
[CharCode.Comma]: '%2C',
[CharCode.Semicolon]: '%3B',
[CharCode.Equals]: '%3D',
[CharCode.Space]: '%20',
};
function encodeURIComponentFast(uriComponent: string, allowSlash: boolean): string {
let res: string | undefined = undefined;
let nativeEncodePos = -1;
for (let pos = 0; pos < uriComponent.length; pos++) {
const code = uriComponent.charCodeAt(pos);
// unreserved characters: https://tools.ietf.org/html/rfc3986#section-2.3
if (
(code >= CharCode.a && code <= CharCode.z)
|| (code >= CharCode.A && code <= CharCode.Z)
|| (code >= CharCode.Digit0 && code <= CharCode.Digit9)
|| code === CharCode.Dash
|| code === CharCode.Period
|| code === CharCode.Underline
|| code === CharCode.Tilde
|| (allowSlash && code === CharCode.Slash)
) {
// check if we are delaying native encode
if (nativeEncodePos !== -1) {
res += encodeURIComponent(uriComponent.substring(nativeEncodePos, pos));
nativeEncodePos = -1;
}
// check if we write into a new string (by default we try to return the param)
if (res !== undefined) {
res += uriComponent.charAt(pos);
}
} else {
// encoding needed, we need to allocate a new string
if (res === undefined) {
res = uriComponent.substr(0, pos);
}
// check with default table first
const escaped = encodeTable[code];
if (escaped !== undefined) {
// check if we are delaying native encode
if (nativeEncodePos !== -1) {
res += encodeURIComponent(uriComponent.substring(nativeEncodePos, pos));
nativeEncodePos = -1;
}
// append escaped variant to result
res += escaped;
} else if (nativeEncodePos === -1) {
// use native encode only when needed
nativeEncodePos = pos;
}
}
}
if (nativeEncodePos !== -1) {
res += encodeURIComponent(uriComponent.substring(nativeEncodePos));
}
return res !== undefined ? res : uriComponent;
}
function encodeURIComponentMinimal(path: string): string {
let res: string | undefined = undefined;
for (let pos = 0; pos < path.length; pos++) {
const code = path.charCodeAt(pos);
if (code === CharCode.Hash || code === CharCode.QuestionMark) {
if (res === undefined) {
res = path.substr(0, pos);
}
res += encodeTable[code];
} else {
if (res !== undefined) {
res += path[pos];
}
}
}
return res !== undefined ? res : path;
}
/**
* Compute `fsPath` for the given uri
*/
function _makeFsPath(uri: URI): string {
function _toFsPath(scheme: string, authority: string, path: string): string {
let value: string;
if (uri.authority && uri.path.length > 1 && uri.scheme === 'file') {
if (authority && path.length > 1 && scheme === 'file') {
// unc path: file://shares/c$/far/boo
value = `//${uri.authority}${uri.path}`;
value = `//${authority}${path}`;
} else if (
uri.path.charCodeAt(0) === CharCode.Slash
&& (uri.path.charCodeAt(1) >= CharCode.A && uri.path.charCodeAt(1) <= CharCode.Z || uri.path.charCodeAt(1) >= CharCode.a && uri.path.charCodeAt(1) <= CharCode.z)
&& uri.path.charCodeAt(2) === CharCode.Colon
path.charCodeAt(0) === CharCode.Slash
&& isAsciiLetter(path.charCodeAt(1))
&& path.charCodeAt(2) === CharCode.Colon
) {
// windows drive letter: file:///c:/far/boo
value = uri.path[1].toLowerCase() + uri.path.substr(2);
value = path[1].toLowerCase() + path.substr(2);
} else {
// other path
value = uri.path;
value = path;
}
if (isWindows) {
value = value.replace(/\//g, '\\');
value = value.replace(_slashRegExp, '\\');
}
return value;
}
//#region ---- decode
function decodeURIComponentGraceful(str: string): string {
try {
return decodeURIComponent(str);
} catch {
if (str.length > 3) {
return str.substr(0, 3) + decodeURIComponentGraceful(str.substr(3));
} else {
return str;
}
}
}
const _encodedAsHexRegExp = /(%[0-9A-Za-z][0-9A-Za-z])+/g;
function percentDecode(str: string): string {
if (!str.match(_encodedAsHexRegExp)) {
return str;
}
return str.replace(_encodedAsHexRegExp, (match) => decodeURIComponentGraceful(match));
}
//#endregion
//#region ---- encode
// https://url.spec.whatwg.org/#percent-encoded-bytes
// "The C0 control percent-encode set are the C0 controls and all code points greater than U+007E (~)."
function isC0ControlPercentEncodeSet(code: number): boolean {
return code <= 0x1F || code > 0x7E;
}
// "The fragment percent-encode set is the C0 control percent-encode set and U+0020 SPACE, U+0022 ("), U+003C (<), U+003E (>), and U+0060 (`)."
function isFragmentPercentEncodeSet(code: number): boolean {
return isC0ControlPercentEncodeSet(code)
|| code === 0x20 || code === 0x22 || code === 0x3C || code === 0x3E || code === 0x60;
}
// "The path percent-encode set is the fragment percent-encode set and U+0023 (#), U+003F (?), U+007B ({), and U+007D (})."
function isPathPercentEncodeSet(code: number): boolean {
return isFragmentPercentEncodeSet(code)
|| code === 0x23 || code === 0x3F || code === 0x7B || code === 0x7D;
}
// "The userinfo percent-encode set is the path percent-encode set and U+002F (/), U+003A (:), U+003B (;), U+003D (=), U+0040 (@), U+005B ([), U+005C (\), U+005D (]), U+005E (^), and U+007C (|)."
function isUserInfoPercentEncodeSet(code: number): boolean {
return isPathPercentEncodeSet(code)
|| code === 0x2F || code === 0x3A || code === 0x3B || code === 0x3D || code === 0x40
|| code === 0x5B || code === 0x5C || code === 0x5D || code === 0x5E || code === 0x7C;
}
// https://url.spec.whatwg.org/#query-state
function isQueryPrecentEncodeSet(code: number): boolean {
return code < 0x21 || code > 0x7E
|| code === 0x22 || code === 0x23 || code === 0x3C || code === 0x3E
|| code === 0x27; // <- todo@joh https://url.spec.whatwg.org/#is-special
}
// this is non-standard and uses for `URI.toString(true)`
function isHashOrQuestionMark(code: number): boolean {
return code === CharCode.Hash || code === CharCode.QuestionMark;
}
const _encodeTable: string[] = (function () {
let table: string[] = [];
for (let code = 0; code < 128; code++) {
table[code] = `%${code.toString(16)}`;
}
return table;
})();
function percentEncode(str: string, mustEncode: (code: number) => boolean): string {
let lazyOutStr: string | undefined;
for (let pos = 0; pos < str.length; pos++) {
const code = str.charCodeAt(pos);
// invoke encodeURIComponent when needed
if (mustEncode(code)) {
if (!lazyOutStr) {
lazyOutStr = str.substr(0, pos);
}
if (isHighSurrogate(code)) {
// Append encoded version of this surrogate pair (2 characters)
if (pos + 1 < str.length && isLowSurrogate(str.charCodeAt(pos + 1))) {
lazyOutStr += encodeURIComponent(str.substr(pos, 2));
pos += 1;
} else {
// broken surrogate pair
lazyOutStr += str.charAt(pos);
}
} else {
// Append encoded version of the current character, use lookup table
// to speed up repeated encoding of the same characters.
if (code < _encodeTable.length) {
lazyOutStr += _encodeTable[code];
} else {
lazyOutStr += encodeURIComponent(str.charAt(pos));
}
}
continue;
}
// normalize percent encoded sequences to upper case
// todo@joh also changes invalid sequences
if (code === CharCode.PercentSign
&& pos + 2 < str.length
&& (isLowerAsciiHex(str.charCodeAt(pos + 1)) || isLowerAsciiHex(str.charCodeAt(pos + 2)))
) {
if (!lazyOutStr) {
lazyOutStr = str.substr(0, pos);
}
lazyOutStr += '%' + str.substr(pos + 1, 2).toUpperCase();
pos += 2;
continue;
}
// once started, continue to build up lazy output
if (lazyOutStr) {
lazyOutStr += str.charAt(pos);
}
}
return lazyOutStr || str;
}
const enum EncodePart {
user, authority, path, query, fragment
}
const _normalEncoder: { (code: number): boolean }[] = [isUserInfoPercentEncodeSet, isC0ControlPercentEncodeSet, isPathPercentEncodeSet, isQueryPrecentEncodeSet, isFragmentPercentEncodeSet];
const _minimalEncoder: { (code: number): boolean }[] = [isHashOrQuestionMark, isHashOrQuestionMark, isHashOrQuestionMark, isHashOrQuestionMark, () => false];
const _driveLetterRegExp = /^(\/?[a-z])(:|%3a)/i;
/**
* Create the external version of a uri
*/
function _asFormatted(uri: URI, skipEncoding: boolean): string {
const encoder = !skipEncoding
? encodeURIComponentFast
: encodeURIComponentMinimal;
function _toExternal(encoder: { (code: number): boolean }[], scheme: string, authority: string, path: string, query: string, fragment: string): string {
let res = '';
let { scheme, authority, path, query, fragment } = uri;
if (scheme) {
res += scheme;
res += ':';
}
if (authority || scheme === 'file') {
res += _slash;
res += _slash;
res += '//';
}
if (authority) {
let idx = authority.indexOf('@');
if (idx !== -1) {
// <user>@<auth>
const userinfo = authority.substr(0, idx);
authority = authority.substr(idx + 1);
idx = userinfo.indexOf(':');
if (idx === -1) {
res += encoder(userinfo, false);
} else {
// <user>:<pass>@<auth>
res += encoder(userinfo.substr(0, idx), false);
const idxUserInfo = authority.indexOf('@');
if (idxUserInfo !== -1) {
// <user:token>
const userInfo = authority.substr(0, idxUserInfo);
const idxPasswordOrToken = userInfo.indexOf(':');
if (idxPasswordOrToken !== -1) {
res += percentEncode(userInfo.substr(0, idxPasswordOrToken), encoder[EncodePart.user]);
res += ':';
res += encoder(userinfo.substr(idx + 1), false);
res += percentEncode(userInfo.substr(idxPasswordOrToken + 1), encoder[EncodePart.user]);
} else {
res += percentEncode(userInfo, encoder[EncodePart.user]);
}
res += '@';
}
authority = authority.toLowerCase();
idx = authority.indexOf(':');
if (idx === -1) {
res += encoder(authority, false);
} else {
// <auth>:<port>
res += encoder(authority.substr(0, idx), false);
res += authority.substr(idx);
authority = authority.substr(idxUserInfo + 1).toLowerCase();
const idxPort = authority.indexOf(':');
if (idxPort !== -1) {
// <authority>:<port>
res += percentEncode(authority.substr(0, idxPort), encoder[EncodePart.authority]);
res += ':';
}
res += percentEncode(authority.substr(idxPort + 1), encoder[EncodePart.authority]);
}
if (path) {
// lower-case windows drive letters in /C:/fff or C:/fff
if (path.length >= 3 && path.charCodeAt(0) === CharCode.Slash && path.charCodeAt(2) === CharCode.Colon) {
const code = path.charCodeAt(1);
if (code >= CharCode.A && code <= CharCode.Z) {
path = `/${String.fromCharCode(code + 32)}:${path.substr(3)}`; // "/c:".length === 3
}
} else if (path.length >= 2 && path.charCodeAt(1) === CharCode.Colon) {
const code = path.charCodeAt(0);
if (code >= CharCode.A && code <= CharCode.Z) {
path = `${String.fromCharCode(code + 32)}:${path.substr(2)}`; // "/c:".length === 3
}
// encode the path
let pathEncoded = percentEncode(path, encoder[EncodePart.path]);
// lower-case windows drive letters in /C:/fff or C:/fff and escape `:`
let match = _driveLetterRegExp.exec(pathEncoded);
if (match) {
pathEncoded = match[1].toLowerCase() + '%3A' + pathEncoded.substr(match[0].length);
}
// encode the rest of the path
res += encoder(path, true);
res += pathEncoded;
}
if (query) {
res += '?';
res += encoder(query, false);
res += percentEncode(query, encoder[EncodePart.query]);
}
if (fragment) {
res += '#';
res += !skipEncoding ? encodeURIComponentFast(fragment, false) : fragment;
res += percentEncode(fragment, encoder[EncodePart.fragment]);
}
return res;
}
//#endregion

View file

@ -2,10 +2,11 @@
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import * as assert from 'assert';
import { URI, UriComponents } from 'vs/base/common/uri';
import { isWindows } from 'vs/base/common/platform';
import { pathToFileURL, fileURLToPath } from 'url';
suite('URI', () => {
test('file#toString', () => {
@ -63,8 +64,8 @@ suite('URI', () => {
assert.equal(URI.from({ scheme: 'http', authority: '', path: 'my/path' }).toString(), 'http:/my/path');
assert.equal(URI.from({ scheme: 'http', authority: '', path: '/my/path' }).toString(), 'http:/my/path');
//http://a-test-site.com/#test=true
assert.equal(URI.from({ scheme: 'http', authority: 'a-test-site.com', path: '/', query: 'test=true' }).toString(), 'http://a-test-site.com/?test%3Dtrue');
assert.equal(URI.from({ scheme: 'http', authority: 'a-test-site.com', path: '/', query: '', fragment: 'test=true' }).toString(), 'http://a-test-site.com/#test%3Dtrue');
assert.equal(URI.from({ scheme: 'http', authority: 'a-test-site.com', path: '/', query: 'test=true' }).toString(), 'http://a-test-site.com/?test=true');
assert.equal(URI.from({ scheme: 'http', authority: 'a-test-site.com', path: '/', query: '', fragment: 'test=true' }).toString(), 'http://a-test-site.com/#test=true');
});
test('http#toString, encode=FALSE', () => {
@ -87,7 +88,7 @@ suite('URI', () => {
assert.equal(uri2.fragment, uri3.fragment);
});
test('with, identity', () => {
test('URI#with, identity', () => {
let uri = URI.parse('foo:bar/path');
let uri2 = uri.with(null!);
@ -100,17 +101,17 @@ suite('URI', () => {
assert.ok(uri === uri2);
});
test('with, changes', () => {
test('URI#with, changes', () => {
assert.equal(URI.parse('before:some/file/path').with({ scheme: 'after' }).toString(), 'after:some/file/path');
assert.equal(URI.from({ scheme: 's' }).with({ scheme: 'http', path: '/api/files/test.me', query: 't=1234' }).toString(), 'http:/api/files/test.me?t%3D1234');
assert.equal(URI.from({ scheme: 's' }).with({ scheme: 'http', authority: '', path: '/api/files/test.me', query: 't=1234', fragment: '' }).toString(), 'http:/api/files/test.me?t%3D1234');
assert.equal(URI.from({ scheme: 's' }).with({ scheme: 'https', authority: '', path: '/api/files/test.me', query: 't=1234', fragment: '' }).toString(), 'https:/api/files/test.me?t%3D1234');
assert.equal(URI.from({ scheme: 's' }).with({ scheme: 'HTTP', authority: '', path: '/api/files/test.me', query: 't=1234', fragment: '' }).toString(), 'HTTP:/api/files/test.me?t%3D1234');
assert.equal(URI.from({ scheme: 's' }).with({ scheme: 'HTTPS', authority: '', path: '/api/files/test.me', query: 't=1234', fragment: '' }).toString(), 'HTTPS:/api/files/test.me?t%3D1234');
assert.equal(URI.from({ scheme: 's' }).with({ scheme: 'boo', authority: '', path: '/api/files/test.me', query: 't=1234', fragment: '' }).toString(), 'boo:/api/files/test.me?t%3D1234');
assert.equal(URI.from({ scheme: 's' }).with({ scheme: 'http', path: '/api/files/test.me', query: 't=1234' }).toString(), 'http:/api/files/test.me?t=1234');
assert.equal(URI.from({ scheme: 's' }).with({ scheme: 'http', authority: '', path: '/api/files/test.me', query: 't=1234', fragment: '' }).toString(), 'http:/api/files/test.me?t=1234');
assert.equal(URI.from({ scheme: 's' }).with({ scheme: 'https', authority: '', path: '/api/files/test.me', query: 't=1234', fragment: '' }).toString(), 'https:/api/files/test.me?t=1234');
assert.equal(URI.from({ scheme: 's' }).with({ scheme: 'HTTP', authority: '', path: '/api/files/test.me', query: 't=1234', fragment: '' }).toString(), 'HTTP:/api/files/test.me?t=1234');
assert.equal(URI.from({ scheme: 's' }).with({ scheme: 'HTTPS', authority: '', path: '/api/files/test.me', query: 't=1234', fragment: '' }).toString(), 'HTTPS:/api/files/test.me?t=1234');
assert.equal(URI.from({ scheme: 's' }).with({ scheme: 'boo', authority: '', path: '/api/files/test.me', query: 't=1234', fragment: '' }).toString(), 'boo:/api/files/test.me?t=1234');
});
test('with, remove components #8465', () => {
test('URI#with, remove components #8465', () => {
assert.equal(URI.parse('scheme://authority/path').with({ authority: '' }).toString(), 'scheme:/path');
assert.equal(URI.parse('scheme:/path').with({ authority: 'authority' }).with({ authority: '' }).toString(), 'scheme:/path');
assert.equal(URI.parse('scheme:/path').with({ authority: 'authority' }).with({ authority: null }).toString(), 'scheme:/path');
@ -120,7 +121,7 @@ suite('URI', () => {
assert.equal(URI.parse('scheme:/path').with({ authority: null }).toString(), 'scheme:/path');
});
test('with, validation', () => {
test('URI#with, validation', () => {
let uri = URI.parse('foo:bar/path');
assert.throws(() => uri.with({ scheme: 'fai:l' }));
assert.throws(() => uri.with({ scheme: 'fäil' }));
@ -234,6 +235,11 @@ suite('URI', () => {
assert.throws(() => URI.parse('file:////shares/files/p.cs'));
});
test('URI#parse, missing scheme', () => {
assert.throws(() => URI.parse('/foo/bar', true));
assertToString('/foo/bar', 'file:///foo/bar');
});
test('URI#file, win-speciale', () => {
if (isWindows) {
let value = URI.file('c:\\test\\drive');
@ -254,7 +260,7 @@ suite('URI', () => {
assert.equal(value.fsPath, '\\\\localhost\\c$\\GitDevelopment\\express');
assert.equal(value.query, '');
assert.equal(value.fragment, '');
assert.equal(value.toString(), 'file://localhost/c%24/GitDevelopment/express');
assert.equal(value.toString(), 'file://localhost/c$/GitDevelopment/express');
value = URI.file('c:\\test with %\\path');
assert.equal(value.path, '/c:/test with %/path');
@ -309,50 +315,78 @@ suite('URI', () => {
assert.equal(value.toString(), 'file:///a.file');
});
function assertToString(input: string | URI, expected: string) {
if (typeof input === 'string') {
input = URI.parse(input);
}
const actual = input.toString();
assert.equal(actual, expected.toString());
}
function assertComponents(input: string | URI, scheme: string, authority: string, path: string, query: string, fragment: string) {
if (typeof input === 'string') {
input = URI.parse(input);
}
assert.equal(input.scheme, scheme);
assert.equal(input.authority, authority);
assert.equal(input.path, path);
assert.equal(input.query, query);
assert.equal(input.fragment, fragment);
}
function assertEqualUri(input: string | URI, other: string | URI) {
if (typeof input === 'string') {
input = URI.parse(input);
}
if (typeof other === 'string') {
other = URI.parse(other);
}
assert.equal(input.scheme, other.scheme);
assert.equal(input.authority, other.authority);
assert.equal(input.path, other.path);
assert.equal(input.query, other.query);
assert.equal(input.fragment, other.fragment);
assert.equal(input.toString(), other.toString());
}
test('URI.toString, only scheme and query', () => {
const value = URI.parse('stuff:?qüery');
assert.equal(value.toString(), 'stuff:?q%C3%BCery');
assertToString('stuff:?qüery', 'stuff:?q%C3%BCery');
});
test('URI#toString, upper-case percent espaces', () => {
const value = URI.parse('file://sh%c3%a4res/path');
assert.equal(value.toString(), 'file://sh%C3%A4res/path');
assertToString('file://sh%c3%a4res/path', 'file://sh%C3%A4res/path');
assertToString('file://sh%c3%z4res/path', 'file://sh%C3%z4res/path');
assertToString('file:///sh%a0res/path', 'file:///sh%A0res/path'); // also upper-cased invalid sequence
});
test('URI#toString, lower-case windows drive letter', () => {
assert.equal(URI.parse('untitled:c:/Users/jrieken/Code/abc.txt').toString(), 'untitled:c%3A/Users/jrieken/Code/abc.txt');
assert.equal(URI.parse('untitled:C:/Users/jrieken/Code/abc.txt').toString(), 'untitled:c%3A/Users/jrieken/Code/abc.txt');
assertToString('untitled:c:/Users/jrieken/Code/abc.txt', 'untitled:c%3A/Users/jrieken/Code/abc.txt');
assertToString('untitled:C:/Users/jrieken/Code/abc.txt', 'untitled:c%3A/Users/jrieken/Code/abc.txt');
});
test('URI#toString, escape all the bits', () => {
const value = URI.file('/Users/jrieken/Code/_samples/18500/Mödel + Other Thîngß/model.js');
assert.equal(value.toString(), 'file:///Users/jrieken/Code/_samples/18500/M%C3%B6del%20%2B%20Other%20Th%C3%AEng%C3%9F/model.js');
assertToString(value, 'file:///Users/jrieken/Code/_samples/18500/M%C3%B6del%20+%20Other%20Th%C3%AEng%C3%9F/model.js');
});
test('URI#toString, don\'t encode port', () => {
let value = URI.parse('http://localhost:8080/far');
assert.equal(value.toString(), 'http://localhost:8080/far');
assertToString(value, 'http://localhost:8080/far');
value = URI.from({ scheme: 'http', authority: 'löcalhost:8080', path: '/far', query: undefined, fragment: undefined });
assert.equal(value.toString(), 'http://l%C3%B6calhost:8080/far');
assertToString(value, 'http://l%C3%B6calhost:8080/far');
});
test('URI#toString, user information in authority', () => {
let value = URI.parse('http://foo:bar@localhost/far');
assert.equal(value.toString(), 'http://foo:bar@localhost/far');
value = URI.parse('http://foo@localhost/far');
assert.equal(value.toString(), 'http://foo@localhost/far');
value = URI.parse('http://foo:bAr@localhost:8080/far');
assert.equal(value.toString(), 'http://foo:bAr@localhost:8080/far');
value = URI.parse('http://foo@localhost:8080/far');
assert.equal(value.toString(), 'http://foo@localhost:8080/far');
value = URI.from({ scheme: 'http', authority: 'föö:bör@löcalhost:8080', path: '/far', query: undefined, fragment: undefined });
assert.equal(value.toString(), 'http://f%C3%B6%C3%B6:b%C3%B6r@l%C3%B6calhost:8080/far');
assertToString('http://foo:bar@localhost/far', 'http://foo:bar@localhost/far');
assertToString('http://foo@localhost/far', 'http://foo@localhost/far');
assertToString('http://foo:bAr@localhost:8080/far', 'http://foo:bAr@localhost:8080/far');
assertToString('http://foo@localhost:8080/far', 'http://foo@localhost:8080/far');
assertToString(
URI.from({ scheme: 'http', authority: 'föö:bör@löcalhost:8080', path: '/far', query: undefined, fragment: undefined }),
'http://f%C3%B6%C3%B6:b%C3%B6r@l%C3%B6calhost:8080/far'
);
});
test('correctFileUriToFilePath2', () => {
@ -376,7 +410,7 @@ suite('URI', () => {
let uri = URI.parse('https://go.microsoft.com/fwlink/?LinkId=518008');
assert.equal(uri.query, 'LinkId=518008');
assert.equal(uri.toString(true), 'https://go.microsoft.com/fwlink/?LinkId=518008');
assert.equal(uri.toString(), 'https://go.microsoft.com/fwlink/?LinkId%3D518008');
assert.equal(uri.toString(), 'https://go.microsoft.com/fwlink/?LinkId=518008');
let uri2 = URI.parse(uri.toString());
assert.equal(uri2.query, 'LinkId=518008');
@ -385,7 +419,7 @@ suite('URI', () => {
uri = URI.parse('https://go.microsoft.com/fwlink/?LinkId=518008&foö&ké¥=üü');
assert.equal(uri.query, 'LinkId=518008&foö&ké¥=üü');
assert.equal(uri.toString(true), 'https://go.microsoft.com/fwlink/?LinkId=518008&foö&ké¥=üü');
assert.equal(uri.toString(), 'https://go.microsoft.com/fwlink/?LinkId%3D518008%26fo%C3%B6%26k%C3%A9%C2%A5%3D%C3%BC%C3%BC');
assert.equal(uri.toString(), 'https://go.microsoft.com/fwlink/?LinkId=518008&fo%C3%B6&k%C3%A9%C2%A5=%C3%BC%C3%BC');
uri2 = URI.parse(uri.toString());
assert.equal(uri2.query, 'LinkId=518008&foö&ké¥=üü');
@ -427,47 +461,122 @@ suite('URI', () => {
});
test('Unable to open \'%A0.txt\': URI malformed #76506', function () {
let uri = URI.file('/foo/%A0.txt');
let uri2 = URI.parse(uri.toString());
assert.equal(uri.scheme, uri2.scheme);
assert.equal(uri.path, uri2.path);
uri = URI.file('/foo/%2e.txt');
uri2 = URI.parse(uri.toString());
assert.equal(uri.scheme, uri2.scheme);
assert.equal(uri.path, uri2.path);
let uriFromPath = URI.file('/foo/%A0.txt');
let uriFromStr = URI.parse(uriFromPath.toString());
assert.equal(uriFromPath.scheme, uriFromStr.scheme);
assert.equal(uriFromPath.path, uriFromStr.path);
assert.equal(uriFromPath.toString(), 'file:///foo/%25A0.txt');
assert.equal(uriFromStr.toString(), 'file:///foo/%25A0.txt');
});
test('Unable to open \'%2e.txt\'', function () {
let uriFromPath = URI.file('/foo/%2e.txt');
let uriFromStr = URI.parse(uriFromPath.toString());
assert.equal(uriFromPath.scheme, uriFromStr.scheme);
assert.equal(uriFromPath.path, uriFromStr.path);
assert.equal(uriFromPath.toString(), 'file:///foo/%252e.txt');
assert.equal(uriFromStr.toString(), 'file:///foo/%252e.txt');
});
test('Links in markdown are broken if url contains encoded parameters #79474', function () {
this.skip();
let strIn = 'https://myhost.com/Redirect?url=http%3A%2F%2Fwww.bing.com%3Fsearch%3Dtom';
let uri1 = URI.parse(strIn);
assertToString(uri1, strIn);
let strOut = uri1.toString();
let uri2 = URI.parse(strOut);
assert.equal(uri1.scheme, uri2.scheme);
assert.equal(uri1.authority, uri2.authority);
assert.equal(uri1.path, uri2.path);
assert.equal(uri1.query, uri2.query);
assert.equal(uri1.fragment, uri2.fragment);
assert.equal(strIn, strOut); // fails here!!
assertEqualUri(uri1, uri2);
assert.equal(strIn, strOut);
});
test('Uri#parse can break path-component #45515', function () {
this.skip();
let strIn = 'https://firebasestorage.googleapis.com/v0/b/brewlangerie.appspot.com/o/products%2FzVNZkudXJyq8bPGTXUxx%2FBetterave-Sesame.jpg?alt=media&token=0b2310c4-3ea6-4207-bbde-9c3710ba0437';
let uri1 = URI.parse(strIn);
assertToString(uri1, strIn);
assertComponents(uri1,
'https',
'firebasestorage.googleapis.com',
'/v0/b/brewlangerie.appspot.com/o/products/zVNZkudXJyq8bPGTXUxx/Betterave-Sesame.jpg', // INCORRECT: %2F got decoded but for compat reasons we cannot change this anymore...
'alt=media&token=0b2310c4-3ea6-4207-bbde-9c3710ba0437',
''
);
let strOut = uri1.toString();
let uri2 = URI.parse(strOut);
assertEqualUri(uri1, uri2);
});
assert.equal(uri1.scheme, uri2.scheme);
assert.equal(uri1.authority, uri2.authority);
assert.equal(uri1.path, uri2.path);
assert.equal(uri1.query, uri2.query);
assert.equal(uri1.fragment, uri2.fragment);
assert.equal(strIn, strOut); // fails here!!
test('Nonce does not match on login #75755', function () {
let uri = URI.parse('http://localhost:60371/signin?nonce=iiK1zRI%2BHyDCKb2zatvrYA%3D%3D');
assertComponents(uri, 'http', 'localhost:60371', '/signin', 'nonce=iiK1zRI+HyDCKb2zatvrYA==', '');
assertToString(uri, 'http://localhost:60371/signin?nonce=iiK1zRI%2BHyDCKb2zatvrYA%3D%3D');
});
test('URI.parse() failes with `Cannot read property \'toLowerCase\' of undefined` #75344', function () {
try {
URI.parse('abc');
assert.ok(false);
} catch (e) {
assert.ok(e instanceof Error && e.message.indexOf('[UriError]:'));
}
});
test('vscode.Uri.parse is double encoding certain characters', function () {
const inStr = 'https://github.com/PowerShell/vscode-powershell#reporting-problems';
assertToString(inStr, inStr);
assertComponents(inStr, 'https', 'github.com', '/PowerShell/vscode-powershell', '', 'reporting-problems');
});
test('Symbols in URL fragment should not be encoded #76635', function () {
const inStr = 'http://source.roslyn.io/#Microsoft.CodeAnalysis.CSharp/CSharpCompilationOptions.cs,20';
assertToString(inStr, inStr);
assertComponents(inStr, 'http', 'source.roslyn.io', '/', '', 'Microsoft.CodeAnalysis.CSharp/CSharpCompilationOptions.cs,20');
});
test('vscode.env.openExternal is not working correctly because of unnecessary escape processing. #76606', function () {
const inStr = 'x-github-client://openRepo/https://github.com/wraith13/open-in-github-desktop-vscode.git';
assertToString(inStr, 'x-github-client://openrepo/https://github.com/wraith13/open-in-github-desktop-vscode.git'); // lower-cased authory
assertComponents(inStr, 'x-github-client', 'openRepo', '/https://github.com/wraith13/open-in-github-desktop-vscode.git', '', '');
});
test('When I click on a link in the terminal, browser opens with a URL which seems to be the link, but run through decodeURIComponent #52211', function () {
const inStr = 'http://localhost:8448/#/repository?path=%2Fhome%2Fcapaj%2Fgit_projects%2Fartillery';
assertToString(inStr, inStr);
assertComponents(inStr, 'http', 'localhost:8448', '/', '', '/repository?path=/home/capaj/git_projects/artillery'); // INCORRECT %2F lost
});
test('Terminal breaks weblink for fish shell #44278', function () {
const inStr = 'https://eu-west-1.console.aws.amazon.com/cloudformation/home\\?region=eu-west-1#/stacks\\?filter=active';
assertToString(inStr, inStr);
assertComponents(inStr, 'https', 'eu-west-1.console.aws.amazon.com', '/cloudformation/home\\', 'region=eu-west-1', '/stacks\\?filter=active');
});
test('Markdown mode cannot open links that contains some codes by percent-encoding. #32026', function () {
const inStr = 'https://www.google.co.jp/search?q=%91%E5';
assertToString(inStr, inStr);
assertComponents(inStr, 'https', 'www.google.co.jp', '/search', 'q=%91%E5', '');
});
test('URI#parse creates normalized output', function () {
function assertToString(input: string, output: string = input): void {
const uri = URI.parse(input);
assert.equal(uri.toString(), output);
}
// don't break query string, encoded characters
assertToString('https://firebasestorage.googleapis.com/v0/b/brewlangerie.appspot.com/o/products%2FzVNZkudXJyq8bPGTXUxx%2FBetterave-Sesame.jpg?alt=media&token=0b2310c4-3ea6-4207-bbde-9c3710ba0437');
assertToString('https://go.microsoft.com/fwlink/?LinkId=518008');
assertToString('https://twitter.com/search?src=typd&q=%23tag');
assertToString('http://localhost:3000/#/foo?bar=baz');
assertToString('https://myhost.com/Redirect?url=http%3A%2F%2Fwww.bing.com%3Fsearch%3Dtom');
assertToString('https://myhost.com/Redirect?url=http%3a%2f%2Fwww.bing.com%3Fsearch%3Dtom', 'https://myhost.com/Redirect?url=http%3A%2F%2Fwww.bing.com%3Fsearch%3Dtom'); // upper-case hex
assertToString('https://go.microsoft.com/fwlink/?LinkId=518008&foö&ké¥=üü', 'https://go.microsoft.com/fwlink/?LinkId=518008&fo%C3%B6&k%C3%A9%C2%A5=%C3%BC%C3%BC'); // encode umlaute and friends
// normalize things like
assertToString('file:///c:/test/me', 'file:///c%3A/test/me'); // drive letter treatment
assertToString('file:///C:/test/me', 'file:///c%3A/test/me');
assertToString('file:///c%3A/test/me', 'file:///c%3A/test/me');
assertToString('file:///C%3A/test/me', 'file:///c%3A/test/me');
});
test('URI - (de)serialize', function () {
@ -499,4 +608,142 @@ suite('URI', () => {
// }
// console.profileEnd();
});
// ------ check against standard URL and nodejs-file-url utils
function assertUriFromFsPath(path: string, recurse = true): void {
let actual = URI.file(path).toString();
if (isWindows) {
// we always encode windows drive letters and since nodejs
// never does. to compare we need to undo our encoding...
actual = actual.replace(/(\/[a-z])%3A/, '$1:');
}
let expected = pathToFileURL(path).href;
assert.equal(actual, expected, path);
if (recurse) {
assertFsPathFromUri(expected, false);
}
}
function assertFsPathFromUri(uri: string, recurse = true): void {
let actual = URI.parse(uri).fsPath;
let expected = fileURLToPath(uri);
assert.equal(actual, expected, uri);
if (recurse) {
assertUriFromFsPath(actual, false);
}
}
test('URI.file and pathToFileURL', function () {
// nodejs is strict to the platform on which it runs
if (isWindows) {
assertUriFromFsPath('d:/foo/bar');
assertUriFromFsPath('d:/foo/%2e.txt');
assertUriFromFsPath('d:/foo/%A0.txt');
assertUriFromFsPath('d:/foo/ü.txt');
assertUriFromFsPath('d:/foo/ß.txt');
assertUriFromFsPath('d:/my/c#project/d.cs');
assertUriFromFsPath('c:\\win\\path');
assertUriFromFsPath('c:\\test\\drive');
assertUriFromFsPath('c:\\test with %\\path');
assertUriFromFsPath('c:\\test with %25\\path');
assertUriFromFsPath('c:\\test with %25\\c#code');
// assertUriFromFsPath('\\\\shäres\\path\\c#\\plugin.json'); // nodejs doesn't accept UNC paths as paths
// assertUriFromFsPath('\\\\localhost\\c$\\GitDevelopment\\express');
// assertUriFromFsPath('\\\\shares');
// assertUriFromFsPath('\\\\shares\\');
} else {
assertUriFromFsPath('/foo/bar');
assertUriFromFsPath('/foo/%2e.txt');
assertUriFromFsPath('/foo/%A0.txt');
assertUriFromFsPath('/foo/ü.txt');
assertUriFromFsPath('/foo/ß.txt');
assertUriFromFsPath('/my/c#project/d.cs');
assertUriFromFsPath('/c\\win\\path');
}
});
test('URI.fsPath and fileURLToPath', function () {
// nodejs is strict to the platform on which it runs
if (isWindows) {
assertFsPathFromUri('file:///f:/foo/bar');
assertFsPathFromUri('file:///f:/fo%25/bar');
assertFsPathFromUri('file:///f:/foo/b ar/text.cs');
assertFsPathFromUri('file:///f:/foö/bar');
assertFsPathFromUri('file:///f:/fo%C3%B6/bar');
assertFsPathFromUri('file:///f:/');
assertFsPathFromUri('file:///f:/my/c%23project/c.cs');
assertFsPathFromUri('file:///c:/bar/foo');
assertFsPathFromUri('file:///c:/alex.txt');
assertFsPathFromUri('file:///c:/Source/Z%C3%BCrich%20or%20Zurich%20(%CB%88zj%CA%8A%C9%99r%C9%AAk,/Code/resources/app/plugins');
assertFsPathFromUri('file://unc-host/foö/bar', false);
// assertFsPathFromUri('file://unc-host/', false); //nodejs \\unc-host\ vs code \
assertFsPathFromUri('file://monacotools/folder/isi.txt', false);
assertFsPathFromUri('file://monacotools1/certificates/SSL/', false);
} else {
assertFsPathFromUri('file:///foo/bar');
assertFsPathFromUri('file:///fo%25/bar');
assertFsPathFromUri('file:///foo/b ar/text.cs');
assertFsPathFromUri('file:///foö/bar');
assertFsPathFromUri('file:///fo%C3%B6/bar');
assertFsPathFromUri('file:///');
assertFsPathFromUri('file:///my/c%23project/c.cs');
assertFsPathFromUri('file:///foo%5cbar');
assertFsPathFromUri('file:///foo%5Cbar');
assertFsPathFromUri('file:///foo%5C%5cbar');
assertFsPathFromUri('file:///Source/Z%C3%BCrich%20or%20Zurich%20(%CB%88zj%CA%8A%C9%99r%C9%AAk,/Code/resources/app/plugins');
}
});
// ---- check against standard url
test('URI.toString equals (whatwg) URL.toString', function () {
function assertToString(uri: string): void {
const actual = URI.parse(uri).toString();
const expected = new URL(uri).href;
assert.equal(actual, expected);
}
assertToString('before:some/file/path');
assertToString('scheme://authority/path');
assertToString('scheme:/path');
assertToString('foo:bar/path');
// assertToString('http:/api/files/test.me?t=1234'); // URL makes api the hostname,
assertToString('http://api/files/test.me?t=1234');
// assertToString('file:///c:/test/me'); // we encode the colon
// assertToString('file:///c:/Source/Z%C3%BCrich%20or%20Zurich%20(%CB%88zj%CA%8A%C9%99r%C9%AAk,/Code/resources/app/plugins/c%23/plugin.json');
// assertToString('file:///c:/test %25/path');
assertToString('file://shares/files/c%23/p.cs');
assertToString('inmemory:');
assertToString('foo:api/files/test');
assertToString('f3ile:?q');
assertToString('f3ile:#d');
assertToString('foo+bar:path');
assertToString('foo-bar:path');
assertToString('foo.bar:path');
assertToString('file:///_:/path');
assertToString('https://firebasestorage.googleapis.com/v0/b/brewlangerie.appspot.com/o/products%2FzVNZkudXJyq8bPGTXUxx%2FBetterave-Sesame.jpg?alt=media&token=0b2310c4-3ea6-4207-bbde-9c3710ba0437');
assertToString('https://myhost.com/Redirect?url=http%3A%2F%2Fwww.bing.com%3Fsearch%3Dtom');
assertToString('debug:internalModule.js?session=aDebugSessionId&ref=11');
assertToString('debug:internalModule.js?session%3DaDebugSessionId%26ref%3D11');
assertToString('https://github.com/microsoft/vscode/issues/33746#issuecomment-545345356');
assertToString('http://localhost:3000/#/foo?bar=baz');
assertToString('https://myhost.com/Redirect?url=http%3A%2F%2Fwww.bing.com%3Fsearch%3Dtom');
assertToString('https://myhost.com/my/pãth/ìß/hē®ę');
assertToString('http://foo:bar@localhost/far');
assertToString('http://foo@localhost/far');
assertToString('http://foo:bAr@localhost:8080/far');
assertToString('http://foo@localhost:8080/far');
assertToString('http://localhost:60371/signin?nonce=iiK1zRI%2BHyDCKb2zatvrYA%3D%3D');
assertToString('https://github.com/PowerShell/vscode-powershell#reporting-problems');
assertToString('http://source.roslyn.io/#Microsoft.CodeAnalysis.CSharp/CSharpCompilationOptions.cs,20');
// assertToString('x-github-client://openRepo/https://github.com/wraith13/open-in-github-desktop-vscode.git'); we lower-case
assertToString('x-github-client://openrepo/https://github.com/wraith13/open-in-github-desktop-vscode.git');
assertToString('http://www.google.com/?parameter1=\'http://imageserver.domain.com/?parameter2=1\'');
assertToString('http://some.ws/page?id=123&select=%22quoted_string%22');
// assertToString('https://eu-west-1.console.aws.amazon.com/cloudformation/home\\?region=eu-west-1#/stacks\\?filter=active'); URL makes slash out of backslash
assertToString('http://localhost/?user=test%2B1@example.com');
assertToString('https://www.google.co.jp/search?q=%91%E5');
});
});

View file

@ -33,17 +33,17 @@ bootstrapWindow.load([
return require('vs/workbench/electron-browser/desktop.main').main(configuration);
});
}, {
removeDeveloperKeybindingsAfterLoad: true,
canModifyDOM: function (windowConfig) {
showPartsSplash(windowConfig);
},
beforeLoaderConfig: function (windowConfig, loaderConfig) {
loaderConfig.recordStats = true;
},
beforeRequire: function () {
perf.mark('willLoadWorkbenchMain');
}
});
removeDeveloperKeybindingsAfterLoad: true,
canModifyDOM: function (windowConfig) {
showPartsSplash(windowConfig);
},
beforeLoaderConfig: function (windowConfig, loaderConfig) {
loaderConfig.recordStats = true;
},
beforeRequire: function () {
perf.mark('willLoadWorkbenchMain');
}
});
/**
* @param {{
@ -84,7 +84,7 @@ function showPartsSplash(configuration) {
style.className = 'initialShellColors';
document.head.appendChild(style);
document.body.className = baseTheme;
style.innerHTML = `body { background-color: ${shellBackground}; color: ${shellForeground}; }`;
style.innerHTML = `body { background-color: ${shellBackground}; color: ${shellForeground}; margin: 0; padding: 0; }`;
if (data && data.layoutInfo) {
// restore parts if possible (we might not always store layout info)
@ -92,6 +92,18 @@ function showPartsSplash(configuration) {
const splash = document.createElement('div');
splash.id = id;
if (layoutInfo.windowBorder) {
splash.style.position = 'relative';
splash.style.height = 'calc(100vh - 2px)';
splash.style.width = 'calc(100vw - 2px)';
splash.style.border = '1px solid var(--window-border-color)';
splash.style.setProperty('--window-border-color', colorInfo.windowBorder);
if (layoutInfo.windowBorderRadius) {
splash.style.borderRadius = layoutInfo.windowBorderRadius;
}
}
// ensure there is enough space
layoutInfo.sideBarWidth = Math.min(layoutInfo.sideBarWidth, window.innerWidth - (layoutInfo.activityBarWidth + layoutInfo.editorPartMinWidth));

View file

@ -8,8 +8,8 @@ import { app, dialog } from 'electron';
import { assign } from 'vs/base/common/objects';
import { isWindows, IProcessEnvironment, isMacintosh } from 'vs/base/common/platform';
import product from 'vs/platform/product/common/product';
import { parseMainProcessArgv } from 'vs/platform/environment/node/argvHelper';
import { addArg, createWaitMarkerFile } from 'vs/platform/environment/node/argv';
import { parseMainProcessArgv, addArg } from 'vs/platform/environment/node/argvHelper';
import { createWaitMarkerFile } from 'vs/platform/environment/node/waitMarkerFile';
import { mkdirp } from 'vs/base/node/pfs';
import { validatePaths } from 'vs/code/node/paths';
import { LifecycleMainService, ILifecycleMainService } from 'vs/platform/lifecycle/electron-main/lifecycleMainService';

View file

@ -6,13 +6,14 @@
import { assign } from 'vs/base/common/objects';
import { memoize } from 'vs/base/common/decorators';
import { IEnvironmentService } from 'vs/platform/environment/common/environment';
import { BrowserWindow, ipcMain } from 'electron';
import { BrowserWindow, ipcMain, WebContents, Event as ElectronEvent } from 'electron';
import { ISharedProcess } from 'vs/platform/ipc/electron-main/sharedProcessMainService';
import { Barrier } from 'vs/base/common/async';
import { ILogService } from 'vs/platform/log/common/log';
import { ILifecycleMainService } from 'vs/platform/lifecycle/electron-main/lifecycleMainService';
import { IThemeMainService } from 'vs/platform/theme/electron-main/themeMainService';
import { toDisposable, DisposableStore } from 'vs/base/common/lifecycle';
import { Event } from 'vs/base/common/event';
export class SharedProcess implements ISharedProcess {
@ -53,7 +54,7 @@ export class SharedProcess implements ISharedProcess {
this.window.loadURL(url);
// Prevent the window from dying
const onClose = (e: Event) => {
const onClose = (e: ElectronEvent) => {
this.logService.trace('SharedProcess#close prevented');
// We never allow to close the shared process unless we get explicitly disposed()
@ -97,7 +98,8 @@ export class SharedProcess implements ISharedProcess {
});
return new Promise<void>(c => {
ipcMain.once('handshake:hello', ({ sender }: { sender: any }) => {
const onHello = Event.once(Event.fromNodeEventEmitter(ipcMain, 'handshake:hello', ({ sender }: { sender: WebContents }) => sender));
disposables.add(onHello(sender => {
sender.send('handshake:hey there', {
sharedIPCHandle: this.environmentService.sharedIPCHandle,
args: this.environmentService.args,
@ -106,7 +108,7 @@ export class SharedProcess implements ISharedProcess {
disposables.add(toDisposable(() => sender.send('handshake:goodbye')));
ipcMain.once('handshake:im ready', () => c(undefined));
});
}));
});
}

View file

@ -6,8 +6,9 @@
import * as os from 'os';
import * as fs from 'fs';
import { spawn, ChildProcess, SpawnOptions } from 'child_process';
import { buildHelpMessage, buildVersionMessage, addArg, createWaitMarkerFile, OPTIONS } from 'vs/platform/environment/node/argv';
import { parseCLIProcessArgv } from 'vs/platform/environment/node/argvHelper';
import { buildHelpMessage, buildVersionMessage, OPTIONS } from 'vs/platform/environment/node/argv';
import { parseCLIProcessArgv, addArg } from 'vs/platform/environment/node/argvHelper';
import { createWaitMarkerFile } from 'vs/platform/environment/node/waitMarkerFile';
import { ParsedArgs } from 'vs/platform/environment/common/environment';
import product from 'vs/platform/product/common/product';
import * as paths from 'vs/base/common/path';

View file

@ -3,7 +3,8 @@
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import * as assert from 'assert';
import { formatOptions, Option, addArg } from 'vs/platform/environment/node/argv';
import { formatOptions, Option } from 'vs/platform/environment/node/argv';
import { addArg } from 'vs/platform/environment/node/argvHelper';
suite('formatOptions', () => {

View file

@ -17,13 +17,12 @@ import { IViewCursorRenderData } from 'vs/editor/browser/viewParts/viewCursors/v
import { EditorZoom } from 'vs/editor/common/config/editorZoom';
import { Position } from 'vs/editor/common/core/position';
import { Selection } from 'vs/editor/common/core/selection';
import { HorizontalRange } from 'vs/editor/common/view/renderingContext';
import { HorizontalPosition } from 'vs/editor/common/view/renderingContext';
import { ViewContext } from 'vs/editor/common/view/viewContext';
import * as viewEvents from 'vs/editor/common/view/viewEvents';
import { ViewEventHandler } from 'vs/editor/common/viewModel/viewEventHandler';
import { EditorOption } from 'vs/editor/common/config/editorOptions';
/**
* Merges mouse events when mouse move events are throttled
*/
@ -59,7 +58,7 @@ export interface IPointerHandlerHelper {
*/
getPositionFromDOMInfo(spanNode: HTMLElement, offset: number): Position | null;
visibleRangeForPosition2(lineNumber: number, column: number): HorizontalRange | null;
visibleRangeForPosition(lineNumber: number, column: number): HorizontalPosition | null;
getLineWidth(lineNumber: number): number;
}

View file

@ -13,7 +13,7 @@ import { IViewCursorRenderData } from 'vs/editor/browser/viewParts/viewCursors/v
import { EditorLayoutInfo, EditorOption } from 'vs/editor/common/config/editorOptions';
import { Position } from 'vs/editor/common/core/position';
import { Range as EditorRange } from 'vs/editor/common/core/range';
import { HorizontalRange } from 'vs/editor/common/view/renderingContext';
import { HorizontalPosition } from 'vs/editor/common/view/renderingContext';
import { ViewContext } from 'vs/editor/common/view/viewContext';
import { IViewModel } from 'vs/editor/common/viewModel/viewModel';
import { CursorColumns } from 'vs/editor/common/controller/cursorCommon';
@ -346,8 +346,8 @@ export class HitTestContext {
return this._viewHelper.getLineWidth(lineNumber);
}
public visibleRangeForPosition2(lineNumber: number, column: number): HorizontalRange | null {
return this._viewHelper.visibleRangeForPosition2(lineNumber, column);
public visibleRangeForPosition(lineNumber: number, column: number): HorizontalPosition | null {
return this._viewHelper.visibleRangeForPosition(lineNumber, column);
}
public getPositionFromDOMInfo(spanNode: HTMLElement, offset: number): Position | null {
@ -743,7 +743,7 @@ export class MouseTargetFactory {
return request.fulfill(MouseTargetType.CONTENT_EMPTY, pos, undefined, detail);
}
const visibleRange = ctx.visibleRangeForPosition2(lineNumber, column);
const visibleRange = ctx.visibleRangeForPosition(lineNumber, column);
if (!visibleRange) {
return request.fulfill(MouseTargetType.UNKNOWN, pos);
@ -761,14 +761,14 @@ export class MouseTargetFactory {
const points: OffsetColumn[] = [];
points.push({ offset: visibleRange.left, column: column });
if (column > 1) {
const visibleRange = ctx.visibleRangeForPosition2(lineNumber, column - 1);
const visibleRange = ctx.visibleRangeForPosition(lineNumber, column - 1);
if (visibleRange) {
points.push({ offset: visibleRange.left, column: column - 1 });
}
}
const lineMaxColumn = ctx.model.getLineMaxColumn(lineNumber);
if (column < lineMaxColumn) {
const visibleRange = ctx.visibleRangeForPosition2(lineNumber, column + 1);
const visibleRange = ctx.visibleRangeForPosition(lineNumber, column + 1);
if (visibleRange) {
points.push({ offset: visibleRange.left, column: column + 1 });
}

View file

@ -25,13 +25,13 @@ import { Range } from 'vs/editor/common/core/range';
import { Selection } from 'vs/editor/common/core/selection';
import { ScrollType } from 'vs/editor/common/editorCommon';
import { EndOfLinePreference } from 'vs/editor/common/model';
import { HorizontalRange, RenderingContext, RestrictedRenderingContext } from 'vs/editor/common/view/renderingContext';
import { RenderingContext, RestrictedRenderingContext, HorizontalPosition } from 'vs/editor/common/view/renderingContext';
import { ViewContext } from 'vs/editor/common/view/viewContext';
import * as viewEvents from 'vs/editor/common/view/viewEvents';
import { AccessibilitySupport } from 'vs/platform/accessibility/common/accessibility';
export interface ITextAreaHandlerHelper {
visibleRangeForPositionRelativeToEditor(lineNumber: number, column: number): HorizontalRange | null;
visibleRangeForPositionRelativeToEditor(lineNumber: number, column: number): HorizontalPosition | null;
}
class VisibleTextAreaData {
@ -408,7 +408,7 @@ export class TextAreaHandler extends ViewPart {
// --- end view API
private _primaryCursorVisibleRange: HorizontalRange | null = null;
private _primaryCursorVisibleRange: HorizontalPosition | null = null;
public prepareRender(ctx: RenderingContext): void {
const primaryCursorPosition = new Position(this._selections[0].positionLineNumber, this._selections[0].positionColumn);

View file

@ -149,7 +149,7 @@ export class OpenerService extends Disposable implements IOpenerService {
private async _doOpenExternal(resource: URI, options: OpenOptions | undefined): Promise<boolean> {
const { resolved } = await this.resolveExternalUri(resource, options);
dom.windowOpenNoOpener(encodeURI(resolved.toString(true)));
dom.windowOpenNoOpener(resolved.toString());
return true;
}

View file

@ -261,7 +261,7 @@ export class View extends ViewEventHandler {
return this.viewLines.getPositionFromDOMInfo(spanNode, offset);
},
visibleRangeForPosition2: (lineNumber: number, column: number) => {
visibleRangeForPosition: (lineNumber: number, column: number) => {
this._flushAccumulatedAndRenderNow();
return this.viewLines.visibleRangeForPosition(new Position(lineNumber, column));
},

View file

@ -195,6 +195,9 @@ export class DecorationsOverlay extends DynamicViewOverlay {
for (let j = 0, lenJ = linesVisibleRanges.length; j < lenJ; j++) {
const lineVisibleRanges = linesVisibleRanges[j];
if (lineVisibleRanges.outsideRenderedLine) {
continue;
}
const lineIndex = lineVisibleRanges.lineNumber - visibleStartLineNumber;
if (showIfCollapsed && lineVisibleRanges.ranges.length === 1) {

View file

@ -10,7 +10,7 @@ import { IVisibleLine } from 'vs/editor/browser/view/viewLayer';
import { RangeUtil } from 'vs/editor/browser/viewParts/lines/rangeUtil';
import { IStringBuilder } from 'vs/editor/common/core/stringBuilder';
import { IConfiguration } from 'vs/editor/common/editorCommon';
import { HorizontalRange } from 'vs/editor/common/view/renderingContext';
import { HorizontalRange, VisibleRanges } from 'vs/editor/common/view/renderingContext';
import { LineDecoration } from 'vs/editor/common/viewLayout/lineDecorations';
import { CharacterMapping, ForeignElementType, RenderLineInput, renderViewLine, LineRange } from 'vs/editor/common/viewLayout/viewLineRenderer';
import { ViewportData } from 'vs/editor/common/viewLayout/viewLinesViewportData';
@ -295,7 +295,7 @@ export class ViewLine implements IVisibleLine {
return this._renderedViewLine.getWidthIsFast();
}
public getVisibleRangesForRange(startColumn: number, endColumn: number, context: DomReadingContext): HorizontalRange[] | null {
public getVisibleRangesForRange(startColumn: number, endColumn: number, context: DomReadingContext): VisibleRanges | null {
if (!this._renderedViewLine) {
return null;
}
@ -306,21 +306,27 @@ export class ViewLine implements IVisibleLine {
endColumn = Math.min(this._renderedViewLine.input.lineContent.length + 1, Math.max(1, endColumn));
const stopRenderingLineAfter = this._renderedViewLine.input.stopRenderingLineAfter | 0; // @perf
let outsideRenderedLine = false;
if (stopRenderingLineAfter !== -1 && startColumn > stopRenderingLineAfter && endColumn > stopRenderingLineAfter) {
if (stopRenderingLineAfter !== -1 && startColumn > stopRenderingLineAfter + 1 && endColumn > stopRenderingLineAfter + 1) {
// This range is obviously not visible
return null;
outsideRenderedLine = true;
}
if (stopRenderingLineAfter !== -1 && startColumn > stopRenderingLineAfter) {
startColumn = stopRenderingLineAfter;
if (stopRenderingLineAfter !== -1 && startColumn > stopRenderingLineAfter + 1) {
startColumn = stopRenderingLineAfter + 1;
}
if (stopRenderingLineAfter !== -1 && endColumn > stopRenderingLineAfter) {
endColumn = stopRenderingLineAfter;
if (stopRenderingLineAfter !== -1 && endColumn > stopRenderingLineAfter + 1) {
endColumn = stopRenderingLineAfter + 1;
}
return this._renderedViewLine.getVisibleRangesForRange(startColumn, endColumn, context);
const horizontalRanges = this._renderedViewLine.getVisibleRangesForRange(startColumn, endColumn, context);
if (horizontalRanges && horizontalRanges.length > 0) {
return new VisibleRanges(outsideRenderedLine, horizontalRanges);
}
return null;
}
public getColumnOfNodeOffset(lineNumber: number, spanNode: HTMLElement, offset: number): number {

View file

@ -14,7 +14,7 @@ import { Position } from 'vs/editor/common/core/position';
import { Range } from 'vs/editor/common/core/range';
import { Selection } from 'vs/editor/common/core/selection';
import { ScrollType } from 'vs/editor/common/editorCommon';
import { HorizontalRange, IViewLines, LineVisibleRanges } from 'vs/editor/common/view/renderingContext';
import { IViewLines, LineVisibleRanges, VisibleRanges, HorizontalPosition } from 'vs/editor/common/view/renderingContext';
import { ViewContext } from 'vs/editor/common/view/viewContext';
import * as viewEvents from 'vs/editor/common/view/viewEvents';
import { ViewportData } from 'vs/editor/common/viewLayout/viewLinesViewportData';
@ -390,7 +390,7 @@ export class ViewLines extends ViewPart implements IVisibleLinesHost<ViewLine>,
const endColumn = lineNumber === range.endLineNumber ? range.endColumn : this._context.model.getLineMaxColumn(lineNumber);
const visibleRangesForLine = this._visibleLines.getVisibleLine(lineNumber).getVisibleRangesForRange(startColumn, endColumn, domReadingContext);
if (!visibleRangesForLine || visibleRangesForLine.length === 0) {
if (!visibleRangesForLine) {
continue;
}
@ -399,11 +399,11 @@ export class ViewLines extends ViewPart implements IVisibleLinesHost<ViewLine>,
nextLineModelLineNumber = this._context.model.coordinatesConverter.convertViewPositionToModelPosition(new Position(lineNumber + 1, 1)).lineNumber;
if (currentLineModelLineNumber !== nextLineModelLineNumber) {
visibleRangesForLine[visibleRangesForLine.length - 1].width += this._typicalHalfwidthCharacterWidth;
visibleRangesForLine.ranges[visibleRangesForLine.ranges.length - 1].width += this._typicalHalfwidthCharacterWidth;
}
}
visibleRanges[visibleRangesLen++] = new LineVisibleRanges(lineNumber, visibleRangesForLine);
visibleRanges[visibleRangesLen++] = new LineVisibleRanges(visibleRangesForLine.outsideRenderedLine, lineNumber, visibleRangesForLine.ranges);
}
if (visibleRangesLen === 0) {
@ -413,54 +413,26 @@ export class ViewLines extends ViewPart implements IVisibleLinesHost<ViewLine>,
return visibleRanges;
}
private visibleRangesForRange2(_range: Range): HorizontalRange[] | null {
private _visibleRangesForLineRange(lineNumber: number, startColumn: number, endColumn: number): VisibleRanges | null {
if (this.shouldRender()) {
// Cannot read from the DOM because it is dirty
// i.e. the model & the dom are out of sync, so I'd be reading something stale
return null;
}
const range = Range.intersectRanges(_range, this._lastRenderedData.getCurrentVisibleRange());
if (!range) {
if (lineNumber < this._visibleLines.getStartLineNumber() || lineNumber > this._visibleLines.getEndLineNumber()) {
return null;
}
let result: HorizontalRange[] = [];
const domReadingContext = new DomReadingContext(this.domNode.domNode, this._textRangeRestingSpot);
const rendStartLineNumber = this._visibleLines.getStartLineNumber();
const rendEndLineNumber = this._visibleLines.getEndLineNumber();
for (let lineNumber = range.startLineNumber; lineNumber <= range.endLineNumber; lineNumber++) {
if (lineNumber < rendStartLineNumber || lineNumber > rendEndLineNumber) {
continue;
}
const startColumn = lineNumber === range.startLineNumber ? range.startColumn : 1;
const endColumn = lineNumber === range.endLineNumber ? range.endColumn : this._context.model.getLineMaxColumn(lineNumber);
const visibleRangesForLine = this._visibleLines.getVisibleLine(lineNumber).getVisibleRangesForRange(startColumn, endColumn, domReadingContext);
if (!visibleRangesForLine || visibleRangesForLine.length === 0) {
continue;
}
result = result.concat(visibleRangesForLine);
}
if (result.length === 0) {
return null;
}
return result;
return this._visibleLines.getVisibleLine(lineNumber).getVisibleRangesForRange(startColumn, endColumn, new DomReadingContext(this.domNode.domNode, this._textRangeRestingSpot));
}
public visibleRangeForPosition(position: Position): HorizontalRange | null {
const visibleRanges = this.visibleRangesForRange2(new Range(position.lineNumber, position.column, position.lineNumber, position.column));
public visibleRangeForPosition(position: Position): HorizontalPosition | null {
const visibleRanges = this._visibleRangesForLineRange(position.lineNumber, position.column, position.column);
if (!visibleRanges) {
return null;
}
return visibleRanges[0];
return new HorizontalPosition(visibleRanges.outsideRenderedLine, visibleRanges.ranges[0].left);
}
// --- implementation
@ -641,7 +613,7 @@ export class ViewLines extends ViewPart implements IVisibleLinesHost<ViewLine>,
const viewportStartX = viewport.left;
const viewportEndX = viewportStartX + viewport.width;
const visibleRanges = this.visibleRangesForRange2(new Range(lineNumber, startColumn, lineNumber, endColumn));
const visibleRanges = this._visibleRangesForLineRange(lineNumber, startColumn, endColumn);
let boxStartX = Constants.MAX_SAFE_SMALL_INTEGER;
let boxEndX = 0;
@ -653,7 +625,7 @@ export class ViewLines extends ViewPart implements IVisibleLinesHost<ViewLine>,
};
}
for (const visibleRange of visibleRanges) {
for (const visibleRange of visibleRanges.ranges) {
if (visibleRange.left < boxStartX) {
boxStartX = visibleRange.left;
}

View file

@ -121,7 +121,7 @@ export class ViewCursor {
if (this._cursorStyle === TextEditorCursorStyle.Line || this._cursorStyle === TextEditorCursorStyle.LineThin) {
const visibleRange = ctx.visibleRangeForPosition(this._position);
if (!visibleRange) {
if (!visibleRange || visibleRange.outsideRenderedLine) {
// Outside viewport
return null;
}
@ -151,13 +151,18 @@ export class ViewCursor {
const lineContent = this._context.model.getLineContent(this._position.lineNumber);
const nextCharLength = strings.nextCharLength(lineContent, this._position.column - 1);
const visibleRangeForCharacter = ctx.linesVisibleRangesForRange(new Range(this._position.lineNumber, this._position.column, this._position.lineNumber, this._position.column + nextCharLength), false);
if (!visibleRangeForCharacter || visibleRangeForCharacter.length === 0 || visibleRangeForCharacter[0].ranges.length === 0) {
if (!visibleRangeForCharacter || visibleRangeForCharacter.length === 0) {
// Outside viewport
return null;
}
const range = visibleRangeForCharacter[0].ranges[0];
const firstVisibleRangeForCharacter = visibleRangeForCharacter[0];
if (firstVisibleRangeForCharacter.outsideRenderedLine || firstVisibleRangeForCharacter.ranges.length === 0) {
// Outside viewport
return null;
}
const range = firstVisibleRangeForCharacter.ranges[0];
const width = range.width < 1 ? this._typicalHalfwidthCharacterWidth : range.width;
let textContentClassName = '';

View file

@ -137,7 +137,7 @@ export interface IEditorOptions {
fixedOverflowWidgets?: boolean;
/**
* The number of vertical lanes the overview ruler should render.
* Defaults to 2.
* Defaults to 3.
*/
overviewRulerLanes?: number;
/**
@ -1258,7 +1258,7 @@ class EditorFontSize extends SimpleEditorOption<EditorOption.fontSize, number> {
if (r === 0) {
return EDITOR_FONT_DEFAULTS.fontSize;
}
return EditorFloatOption.clamp(r, 8, 100);
return EditorFloatOption.clamp(r, 6, 100);
}
public compute(env: IEnvironmentalOptions, options: IComputedEditorOptions, value: number): number {
// The final fontSize respects the editor zoom level.
@ -3094,8 +3094,7 @@ export const EditorOptions = {
)),
overviewRulerLanes: register(new EditorIntOption(
EditorOption.overviewRulerLanes, 'overviewRulerLanes',
3, 0, 3,
{ description: nls.localize('overviewRulerLanes', "Controls the number of decorations that can show up at the same position in the overview ruler.") }
3, 0, 3
)),
parameterHints: register(new EditorParameterHints()),
quickSuggestions: register(new EditorQuickSuggestions()),

View file

@ -577,23 +577,34 @@ export class PieceTreeBase {
let m: RegExpExecArray | null;
// Reset regex to search from the beginning
searcher.reset(start);
let ret: BufferCursor = { line: 0, column: 0 };
let searchText: string;
let offsetInBuffer: (offset: number) => number;
if (searcher._wordSeparators) {
searchText = buffer.buffer.substring(start, end);
offsetInBuffer = (offset: number) => offset + start;
searcher.reset(-1);
} else {
searchText = buffer.buffer;
offsetInBuffer = (offset: number) => offset;
searcher.reset(start);
}
do {
m = searcher.next(buffer.buffer);
m = searcher.next(searchText);
if (m) {
if (m.index >= end) {
if (offsetInBuffer(m.index) >= end) {
return resultLen;
}
this.positionInBuffer(node, m.index - startOffsetInBuffer, ret);
this.positionInBuffer(node, offsetInBuffer(m.index) - startOffsetInBuffer, ret);
let lineFeedCnt = this.getLineFeedCnt(node.piece.bufferIndex, startCursor, ret);
let retStartColumn = ret.line === startCursor.line ? ret.column - startCursor.column + startColumn : ret.column + 1;
let retEndColumn = retStartColumn + m[0].length;
result[resultLen++] = createFindMatch(new Range(startLineNumber + lineFeedCnt, retStartColumn, startLineNumber + lineFeedCnt, retEndColumn), m, captureMatches);
if (m.index + m[0].length >= end) {
if (offsetInBuffer(m.index) + m[0].length >= end) {
return resultLen;
}
if (resultLen >= limitResultCount) {

View file

@ -510,7 +510,7 @@ export function isValidMatch(wordSeparators: WordCharacterClassifier, text: stri
}
export class Searcher {
private readonly _wordSeparators: WordCharacterClassifier | null;
public readonly _wordSeparators: WordCharacterClassifier | null;
private readonly _searchRegex: RegExp;
private _prevMatchStartIndex: number;
private _prevMatchLength: number;

View file

@ -264,6 +264,10 @@ export class LinkComputer {
case CharCode.BackTick:
chClass = (linkBeginChCode === CharCode.SingleQuote || linkBeginChCode === CharCode.DoubleQuote) ? CharacterClass.None : CharacterClass.ForceTermination;
break;
case CharCode.Asterisk:
// `*` terminates a link if the link began with `*`
chClass = (linkBeginChCode === CharCode.Asterisk) ? CharacterClass.ForceTermination : CharacterClass.None;
break;
default:
chClass = classifier.get(chCode);
}

View file

@ -10,7 +10,7 @@ import { IViewLayout, ViewModelDecoration } from 'vs/editor/common/viewModel/vie
export interface IViewLines {
linesVisibleRangesForRange(range: Range, includeNewLines: boolean): LineVisibleRanges[] | null;
visibleRangeForPosition(position: Position): HorizontalRange | null;
visibleRangeForPosition(position: Position): HorizontalPosition | null;
}
export abstract class RestrictedRenderingContext {
@ -77,26 +77,20 @@ export class RenderingContext extends RestrictedRenderingContext {
return this._viewLines.linesVisibleRangesForRange(range, includeNewLines);
}
public visibleRangeForPosition(position: Position): HorizontalRange | null {
public visibleRangeForPosition(position: Position): HorizontalPosition | null {
return this._viewLines.visibleRangeForPosition(position);
}
}
export class LineVisibleRanges {
_lineVisibleRangesBrand: void;
public lineNumber: number;
public ranges: HorizontalRange[];
constructor(lineNumber: number, ranges: HorizontalRange[]) {
this.lineNumber = lineNumber;
this.ranges = ranges;
}
constructor(
public readonly outsideRenderedLine: boolean,
public readonly lineNumber: number,
public readonly ranges: HorizontalRange[]
) { }
}
export class HorizontalRange {
_horizontalRangeBrand: void;
public left: number;
public width: number;
@ -109,3 +103,21 @@ export class HorizontalRange {
return `[${this.left},${this.width}]`;
}
}
export class HorizontalPosition {
public outsideRenderedLine: boolean;
public left: number;
constructor(outsideRenderedLine: boolean, left: number) {
this.outsideRenderedLine = outsideRenderedLine;
this.left = Math.round(left);
}
}
export class VisibleRanges {
constructor(
public readonly outsideRenderedLine: boolean,
public readonly ranges: HorizontalRange[]
) {
}
}

View file

@ -129,9 +129,7 @@ export class CoordinatesConverter implements ICoordinatesConverter {
}
public convertModelRangeToViewRange(modelRange: Range): Range {
let start = this._lines.convertModelPositionToViewPosition(modelRange.startLineNumber, modelRange.startColumn);
let end = this._lines.convertModelPositionToViewPosition(modelRange.endLineNumber, modelRange.endColumn);
return new Range(start.lineNumber, start.column, end.lineNumber, end.column);
return this._lines.convertModelRangeToViewRange(modelRange);
}
public modelPositionIsVisible(modelPosition: Position): boolean {
@ -737,9 +735,9 @@ export class SplitLinesCollection implements IViewModelLinesCollection {
public convertModelPositionToViewPosition(_modelLineNumber: number, _modelColumn: number): Position {
this._ensureValidState();
let validPosition = this.model.validatePosition(new Position(_modelLineNumber, _modelColumn));
let inputLineNumber = validPosition.lineNumber;
let inputColumn = validPosition.column;
const validPosition = this.model.validatePosition(new Position(_modelLineNumber, _modelColumn));
const inputLineNumber = validPosition.lineNumber;
const inputColumn = validPosition.column;
let lineIndex = inputLineNumber - 1, lineIndexChanged = false;
while (lineIndex > 0 && !this.lines[lineIndex].isVisible()) {
@ -751,7 +749,7 @@ export class SplitLinesCollection implements IViewModelLinesCollection {
// console.log('in -> out ' + inputLineNumber + ',' + inputColumn + ' ===> ' + 1 + ',' + 1);
return new Position(1, 1);
}
let deltaLineNumber = 1 + (lineIndex === 0 ? 0 : this.prefixSumComputer.getAccumulatedValue(lineIndex - 1));
const deltaLineNumber = 1 + (lineIndex === 0 ? 0 : this.prefixSumComputer.getAccumulatedValue(lineIndex - 1));
let r: Position;
if (lineIndexChanged) {
@ -764,6 +762,19 @@ export class SplitLinesCollection implements IViewModelLinesCollection {
return r;
}
public convertModelRangeToViewRange(modelRange: Range): Range {
let start = this.convertModelPositionToViewPosition(modelRange.startLineNumber, modelRange.startColumn);
let end = this.convertModelPositionToViewPosition(modelRange.endLineNumber, modelRange.endColumn);
if (modelRange.startLineNumber === modelRange.endLineNumber && start.lineNumber !== end.lineNumber) {
// This is a single line range that ends up taking more lines due to wrapping
if (end.column === this.getViewLineMinColumn(end.lineNumber)) {
// the end column lands on the first column of the next line
return new Range(start.lineNumber, start.column, end.lineNumber - 1, this.getViewLineMaxColumn(end.lineNumber - 1));
}
}
return new Range(start.lineNumber, start.column, end.lineNumber, end.column);
}
private _getViewLineNumberForModelPosition(inputLineNumber: number, inputColumn: number): number {
let lineIndex = inputLineNumber - 1;
if (this.lines[lineIndex].isVisible()) {

View file

@ -32,13 +32,13 @@
.monaco-editor .find-widget {
position: absolute;
z-index: 10;
top: -44px;
height: 33px;
overflow: hidden;
line-height: 19px;
transition: top 200ms linear;
transition: transform 200ms linear;
padding: 0 4px;
box-sizing: border-box;
transform: translateY(Calc(-100% - 10px)); /* shadow (10px) */
}
.monaco-editor .find-widget.hiddenEditor {
@ -46,30 +46,13 @@
}
/* Find widget when replace is toggled on */
.monaco-editor .find-widget.replaceToggled {
top: -74px; /* find input height + replace input height + shadow (10px) */
}
.monaco-editor .find-widget.replaceToggled > .replace-part {
display: flex;
display: -webkit-flex;
}
.monaco-editor .find-widget.visible,
.monaco-editor .find-widget.replaceToggled.visible {
top: 0;
}
/* Multiple line find widget */
.monaco-editor .find-widget.multipleline {
top: unset;
bottom: 10px;
}
.monaco-editor .find-widget.multipleline.visible,
.monaco-editor .find-widget.multipleline.replaceToggled.visible {
top: 0px;
bottom: unset;
.monaco-editor .find-widget.visible {
transform: translateY(0);
}
.monaco-editor .find-widget .monaco-inputbox.synthetic-focus {
@ -156,7 +139,6 @@
}
.monaco-editor .find-widget .button {
min-width: 20px;
width: 20px;
height: 20px;
display: flex;
@ -189,7 +171,7 @@
.monaco-editor .find-widget .button.toggle {
position: absolute;
top: 0;
left: 0;
left: 3px;
width: 18px;
height: 100%;
-webkit-box-sizing: border-box;

View file

@ -290,12 +290,6 @@ export class FindWidget extends Widget implements IOverlayWidget, IHorizontalSas
private _onStateChanged(e: FindReplaceStateChangedEvent): void {
if (e.searchString) {
if (this._state.searchString.indexOf('\n') >= 0) {
dom.addClass(this._domNode, 'multipleline');
} else {
dom.removeClass(this._domNode, 'multipleline');
}
try {
this._ignoreChangeEvent = true;
this._findInput.setValue(this._state.searchString);

View file

@ -354,7 +354,7 @@ export class ModesContentHoverWidget extends ContentHoverWidget {
containColorPicker = true;
const { red, green, blue, alpha } = msg.color;
const rgba = new RGBA(red * 255, green * 255, blue * 255, alpha);
const rgba = new RGBA(Math.round(red * 255), Math.round(green * 255), Math.round(blue * 255), alpha);
const color = new Color(rgba);
if (!this._editor.hasModel()) {

View file

@ -603,6 +603,17 @@ export class MultiCursorSelectionController extends Disposable implements IEdito
matches = this._session.selectAll();
}
if (findState.searchScope) {
const state = findState.searchScope;
let inSelection: FindMatch[] | null = [];
for (let i = 0; i < matches.length; i++) {
if (matches[i].range.endLineNumber <= state.endLineNumber && matches[i].range.startLineNumber >= state.startLineNumber) {
inSelection.push(matches[i]);
}
}
matches = inSelection;
}
if (matches.length > 0) {
const editorSelection = this._editor.getSelection();
// Have the primary cursor remain the one where the action was invoked

View file

@ -8,7 +8,7 @@ import { domEvent, stop } from 'vs/base/browser/event';
import * as aria from 'vs/base/browser/ui/aria/aria';
import { DomScrollableElement } from 'vs/base/browser/ui/scrollbar/scrollableElement';
import { Event } from 'vs/base/common/event';
import { IDisposable, Disposable, DisposableStore, MutableDisposable } from 'vs/base/common/lifecycle';
import { Disposable, DisposableStore } from 'vs/base/common/lifecycle';
import 'vs/css!./parameterHints';
import { ContentWidgetPositionPreference, ICodeEditor, IContentWidget, IContentWidgetPosition } from 'vs/editor/browser/editorBrowser';
import { ConfigurationChangedEvent, EditorOption } from 'vs/editor/common/config/editorOptions';
@ -25,13 +25,13 @@ import { ParameterHintsModel, TriggerContext } from 'vs/editor/contrib/parameter
const $ = dom.$;
export class ParameterHintsWidget extends Disposable implements IContentWidget, IDisposable {
export class ParameterHintsWidget extends Disposable implements IContentWidget {
private static readonly ID = 'editor.widget.parameterHintsWidget';
private readonly markdownRenderer: MarkdownRenderer;
private readonly renderDisposeables = this._register(new DisposableStore());
private readonly model = this._register(new MutableDisposable<ParameterHintsModel>());
private readonly model: ParameterHintsModel;
private readonly keyVisible: IContextKey<boolean>;
private readonly keyMultipleSignatures: IContextKey<boolean>;
@ -57,11 +57,11 @@ export class ParameterHintsWidget extends Disposable implements IContentWidget,
) {
super();
this.markdownRenderer = this._register(new MarkdownRenderer(editor, modeService, openerService));
this.model.value = new ParameterHintsModel(editor);
this.model = this._register(new ParameterHintsModel(editor));
this.keyVisible = Context.Visible.bindTo(contextKeyService);
this.keyMultipleSignatures = Context.MultipleSignatures.bindTo(contextKeyService);
this._register(this.model.value.onChangedHints(newParameterHints => {
this._register(this.model.onChangedHints(newParameterHints => {
if (newParameterHints) {
this.show();
this.render(newParameterHints);
@ -134,7 +134,7 @@ export class ParameterHintsWidget extends Disposable implements IContentWidget,
}
private show(): void {
if (!this.model || this.visible) {
if (this.visible) {
return;
}
@ -153,7 +153,7 @@ export class ParameterHintsWidget extends Disposable implements IContentWidget,
}
private hide(): void {
if (!this.model || !this.visible) {
if (!this.visible) {
return;
}
@ -189,7 +189,6 @@ export class ParameterHintsWidget extends Disposable implements IContentWidget,
this.domNodes.docs.innerHTML = '';
const signature = hints.signatures[hints.activeSignature];
if (!signature) {
return;
}
@ -204,14 +203,13 @@ export class ParameterHintsWidget extends Disposable implements IContentWidget,
if (!hasParameters) {
const label = dom.append(code, $('span'));
label.textContent = signature.label;
} else {
this.renderParameters(code, signature, hints.activeParameter);
}
this.renderDisposeables.clear();
const activeParameter = signature.parameters[hints.activeParameter];
const activeParameter: modes.ParameterInformation | undefined = signature.parameters[hints.activeParameter];
if (activeParameter && activeParameter.documentation) {
const documentation = $('span.documentation');
@ -236,25 +234,12 @@ export class ParameterHintsWidget extends Disposable implements IContentWidget,
dom.append(this.domNodes.docs, renderedContents.element);
}
let hasDocs = false;
if (activeParameter && typeof (activeParameter.documentation) === 'string' && activeParameter.documentation.length > 0) {
hasDocs = true;
}
if (activeParameter && typeof (activeParameter.documentation) === 'object' && activeParameter.documentation.value.length > 0) {
hasDocs = true;
}
if (typeof (signature.documentation) === 'string' && signature.documentation.length > 0) {
hasDocs = true;
}
if (typeof (signature.documentation) === 'object' && signature.documentation.value.length > 0) {
hasDocs = true;
}
const hasDocs = this.hasDocs(signature, activeParameter);
dom.toggleClass(this.domNodes.signature, 'has-docs', hasDocs);
dom.toggleClass(this.domNodes.docs, 'empty', !hasDocs);
let currentOverload = String(hints.activeSignature + 1);
if (hints.signatures.length < 10) {
currentOverload += `/${hints.signatures.length}`;
}
@ -276,8 +261,23 @@ export class ParameterHintsWidget extends Disposable implements IContentWidget,
this.domNodes.scrollbar.scanDomNode();
}
private renderParameters(parent: HTMLElement, signature: modes.SignatureInformation, currentParameter: number): void {
private hasDocs(signature: modes.SignatureInformation, activeParameter: modes.ParameterInformation | undefined): boolean {
if (activeParameter && typeof (activeParameter.documentation) === 'string' && activeParameter.documentation.length > 0) {
return true;
}
if (activeParameter && typeof (activeParameter.documentation) === 'object' && activeParameter.documentation.value.length > 0) {
return true;
}
if (typeof (signature.documentation) === 'string' && signature.documentation.length > 0) {
return true;
}
if (typeof (signature.documentation) === 'object' && signature.documentation.value.length > 0) {
return true;
}
return false;
}
private renderParameters(parent: HTMLElement, signature: modes.SignatureInformation, currentParameter: number): void {
const [start, end] = this.getParameterLabelOffsets(signature, currentParameter);
const beforeSpan = document.createElement('span');
@ -317,23 +317,17 @@ export class ParameterHintsWidget extends Disposable implements IContentWidget,
}
next(): void {
if (this.model.value) {
this.editor.focus();
this.model.value.next();
}
this.editor.focus();
this.model.next();
}
previous(): void {
if (this.model.value) {
this.editor.focus();
this.model.value.previous();
}
this.editor.focus();
this.model.previous();
}
cancel(): void {
if (this.model.value) {
this.model.value.cancel();
}
this.model.cancel();
}
getDomNode(): HTMLElement {
@ -348,9 +342,7 @@ export class ParameterHintsWidget extends Disposable implements IContentWidget,
}
trigger(context: TriggerContext): void {
if (this.model.value) {
this.model.value.trigger(context, 0);
}
this.model.trigger(context, 0);
}
private updateMaxHeight(): void {

View file

@ -202,4 +202,11 @@ suite('Editor Modes - Link Computer', () => {
' http://[::1]:5000/connect/token '
);
});
test('issue #70254: bold links dont open in markdown file using editor mode with ctrl + click', () => {
assertLink(
'2. Navigate to **https://portal.azure.com**',
' https://portal.azure.com '
);
});
});

View file

@ -103,16 +103,6 @@ suite('ViewModelDecorations', () => {
// view line 2: (1,14 -> 1,24)
assert.deepEqual(inlineDecorations1, [
{
range: new Range(1, 2, 2, 1),
inlineClassName: 'i-dec2',
type: InlineDecorationType.Regular
},
{
range: new Range(2, 1, 2, 1),
inlineClassName: 'a-dec2',
type: InlineDecorationType.After
},
{
range: new Range(1, 2, 2, 2),
inlineClassName: 'i-dec3',
@ -124,7 +114,7 @@ suite('ViewModelDecorations', () => {
type: InlineDecorationType.After
},
{
range: new Range(1, 2, 4, 1),
range: new Range(1, 2, 3, 13),
inlineClassName: 'i-dec4',
type: InlineDecorationType.Regular
},
@ -164,7 +154,7 @@ suite('ViewModelDecorations', () => {
type: InlineDecorationType.After
},
{
range: new Range(2, 1, 4, 1),
range: new Range(2, 1, 3, 13),
inlineClassName: 'i-dec8',
type: InlineDecorationType.Regular
},
@ -199,7 +189,7 @@ suite('ViewModelDecorations', () => {
type: InlineDecorationType.After
},
{
range: new Range(2, 3, 4, 1),
range: new Range(2, 3, 3, 13),
inlineClassName: 'i-dec11',
type: InlineDecorationType.Regular
},
@ -228,30 +218,45 @@ suite('ViewModelDecorations', () => {
// view line 3 (24 -> 36)
assert.deepEqual(inlineDecorations2, [
{
range: new Range(1, 2, 4, 1),
range: new Range(1, 2, 3, 13),
inlineClassName: 'i-dec4',
type: InlineDecorationType.Regular
},
{
range: new Range(3, 13, 3, 13),
inlineClassName: 'a-dec4',
type: InlineDecorationType.After
},
{
range: new Range(1, 2, 5, 8),
inlineClassName: 'i-dec5',
type: InlineDecorationType.Regular
},
{
range: new Range(2, 1, 4, 1),
range: new Range(2, 1, 3, 13),
inlineClassName: 'i-dec8',
type: InlineDecorationType.Regular
},
{
range: new Range(3, 13, 3, 13),
inlineClassName: 'a-dec8',
type: InlineDecorationType.After
},
{
range: new Range(2, 1, 5, 8),
inlineClassName: 'i-dec9',
type: InlineDecorationType.Regular
},
{
range: new Range(2, 3, 4, 1),
range: new Range(2, 3, 3, 13),
inlineClassName: 'i-dec11',
type: InlineDecorationType.Regular
},
{
range: new Range(3, 13, 3, 13),
inlineClassName: 'a-dec11',
type: InlineDecorationType.After
},
{
range: new Range(2, 3, 5, 8),
inlineClassName: 'i-dec12',

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

@ -129,9 +129,11 @@ declare namespace monaco {
* Creates a new Uri from a string, e.g. `http://www.msft.com/some/path`,
* `file:///usr/home`, or `scheme:with/path`.
*
* *Note:* When the input lacks a scheme then `file` is used.
*
* @param value A string which represents an Uri (see `Uri#toString`).
*/
static parse(value: string): Uri;
static parse(value: string, strict?: boolean): Uri;
/**
* Creates a new Uri from a file system path, e.g. `c:\my\files`,
* `/usr/home`, or `\\server\share\some\path`.
@ -2548,7 +2550,7 @@ declare namespace monaco.editor {
fixedOverflowWidgets?: boolean;
/**
* The number of vertical lanes the overview ruler should render.
* Defaults to 2.
* Defaults to 3.
*/
overviewRulerLanes?: number;
/**

View file

@ -142,6 +142,7 @@ export interface IEnvironmentService {
extensionsPath?: string;
extensionDevelopmentLocationURI?: URI[];
extensionTestsLocationURI?: URI;
logExtensionHostCommunication?: boolean;
debugExtensionHost: IExtensionHostDebugParams;

View file

@ -7,13 +7,10 @@ import * as minimist from 'vscode-minimist';
import * as os from 'os';
import { localize } from 'vs/nls';
import { ParsedArgs } from 'vs/platform/environment/common/environment';
import { join } from 'vs/base/common/path';
import { writeFileSync } from 'vs/base/node/pfs';
/**
* This code is also used by standalone cli's. Avoid adding any other dependencies.
*/
const helpCategories = {
o: localize('optionsUpperCase', "Options"),
e: localize('extensionsManagement', "Extensions Management"),
@ -161,7 +158,7 @@ export function parseArgs<T>(args: string[], options: OptionDescriptions<T>, err
}
}
}
// remote aliases to avoid confusion
// remove aliases to avoid confusion
const parsedArgs = minimist(args, { string, boolean, alias });
const cleanedArgs: any = {};
@ -310,33 +307,3 @@ export function buildVersionMessage(version: string | undefined, commit: string
return `${version || localize('unknownVersion', "Unknown version")}\n${commit || localize('unknownCommit', "Unknown commit")}\n${process.arch}`;
}
export function addArg(argv: string[], ...args: string[]): string[] {
const endOfArgsMarkerIndex = argv.indexOf('--');
if (endOfArgsMarkerIndex === -1) {
argv.push(...args);
} else {
// if the we have an argument "--" (end of argument marker)
// we cannot add arguments at the end. rather, we add
// arguments before the "--" marker.
argv.splice(endOfArgsMarkerIndex, 0, ...args);
}
return argv;
}
export function createWaitMarkerFile(verbose?: boolean): string | undefined {
const randomWaitMarkerPath = join(os.tmpdir(), Math.random().toString(36).replace(/[^a-z]+/g, '').substr(0, 10));
try {
writeFileSync(randomWaitMarkerPath, '');
if (verbose) {
console.log(`Marker file for --wait created: ${randomWaitMarkerPath}`);
}
return randomWaitMarkerPath;
} catch (err) {
if (verbose) {
console.error(`Failed to create marker file for --wait: ${err}`);
}
return undefined;
}
}

View file

@ -69,3 +69,17 @@ export function parseCLIProcessArgv(processArgv: string[]): ParsedArgs {
return parseAndValidate(args, true);
}
export function addArg(argv: string[], ...args: string[]): string[] {
const endOfArgsMarkerIndex = argv.indexOf('--');
if (endOfArgsMarkerIndex === -1) {
argv.push(...args);
} else {
// if the we have an argument "--" (end of argument marker)
// we cannot add arguments at the end. rather, we add
// arguments before the "--" marker.
argv.splice(endOfArgsMarkerIndex, 0, ...args);
}
return argv;
}

View file

@ -235,6 +235,8 @@ export class EnvironmentService implements IEnvironmentService {
@memoize
get debugExtensionHost(): IExtensionHostDebugParams { return parseExtensionHostPort(this._args, this.isBuilt); }
@memoize
get logExtensionHostCommunication(): boolean { return !!this.args.logExtensionHostCommunication; }
get isBuilt(): boolean { return !process.env['VSCODE_DEV']; }
get verbose(): boolean { return !!this._args.verbose; }

View file

@ -0,0 +1,28 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
/**
* This code is also used by standalone cli's. Avoid adding dependencies to keep the size of the cli small.
*/
import * as path from 'vs/base/common/path';
import * as os from 'os';
import * as fs from 'fs';
export function createWaitMarkerFile(verbose?: boolean): string | undefined {
const randomWaitMarkerPath = path.join(os.tmpdir(), Math.random().toString(36).replace(/[^a-z]+/g, '').substr(0, 10));
try {
fs.writeFileSync(randomWaitMarkerPath, ''); // use built-in fs to avoid dragging in more dependencies
if (verbose) {
console.log(`Marker file for --wait created: ${randomWaitMarkerPath}`);
}
return randomWaitMarkerPath;
} catch (err) {
if (verbose) {
console.error(`Failed to create marker file for --wait: ${err}`);
}
return undefined;
}
}

View file

@ -69,7 +69,7 @@ Registry.as<IConfigurationRegistry>(Extensions.Configuration)
properties: {
'http.proxy': {
type: 'string',
pattern: '^https?://([^:]*(:[^@]*)?@)?([^:]+)(:\\d+)?/?$|^$',
pattern: '^https?://([^:]*(:[^@]*)?@)?([^:]+|\\[[:0-9a-fA-F]+\\])(:\\d+)?/?$|^$',
markdownDescription: localize('proxy', "The proxy setting to use. If not set, will be inherited from the `http_proxy` and `https_proxy` environment variables.")
},
'http.proxyStrictSSL': {

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

@ -1236,8 +1236,8 @@ declare module 'vscode' {
* `file:///usr/home`, or `scheme:with/path`.
*
* *Note* that for a while uris without a `scheme` were accepted. That is not correct
* as all uris should have a scheme. To avoid breakage of existing code the optional
* `strict`-argument has been added. We *strongly* advise to use it, e.g. `Uri.parse('my:uri', true)`
* as all uris should have a scheme. When missing the `file`-scheme is being used unless
* the `strict`-argument is `true` in which case an error is thrown.
*
* @see [Uri.toString](#Uri.toString)
* @param value The string value of an Uri.
@ -4082,11 +4082,11 @@ declare module 'vscode' {
* - Workspace configuration (if available)
* - Workspace folder configuration of the requested resource (if available)
*
* *Global configuration* comes from User Settings and shadows Defaults.
* *Global configuration* comes from User Settings and overrides Defaults.
*
* *Workspace configuration* comes from Workspace Settings and shadows Global configuration.
* *Workspace configuration* comes from Workspace Settings and overrides Global configuration.
*
* *Workspace Folder configuration* comes from `.vscode` folder under one of the [workspace folders](#workspace.workspaceFolders).
* *Workspace Folder configuration* comes from `.vscode` folder under one of the [workspace folders](#workspace.workspaceFolders) and overrides Workspace configuration.
*
* *Note:* Workspace and Workspace Folder configurations contains `launch` and `tasks` settings. Their basename will be
* part of the section identifier. The following snippets shows how to retrieve all configurations
@ -4135,9 +4135,9 @@ declare module 'vscode' {
* a workspace-specific value and a folder-specific value.
*
* The *effective* value (returned by [`get`](#WorkspaceConfiguration.get))
* is computed like this: `defaultValue` overwritten by `globalValue`,
* `globalValue` overwritten by `workspaceValue`. `workspaceValue` overwritten by `workspaceFolderValue`.
* Refer to [Settings Inheritance](https://code.visualstudio.com/docs/getstarted/settings)
* is computed like this: `defaultValue` overridden by `globalValue`,
* `globalValue` overridden by `workspaceValue`. `workspaceValue` overwridden by `workspaceFolderValue`.
* Refer to [Settings](https://code.visualstudio.com/docs/getstarted/settings)
* for more information.
*
* *Note:* The configuration name must denote a leaf in the configuration tree
@ -9284,6 +9284,41 @@ declare module 'vscode' {
constructor(functionName: string, enabled?: boolean, condition?: string, hitCondition?: string, logMessage?: string);
}
/**
* Debug console mode used by debug session, see [options](#DebugSessionOptions).
*/
export enum DebugConsoleMode {
/**
* Debug session should have a separate debug console.
*/
Separate = 0,
/**
* Debug session should share debug console with its parent session.
* This value has no effect for sessions which do not have a parent session.
*/
MergeWithParent = 1
}
/**
* Options for [starting a debug session](#debug.startDebugging).
*/
export interface DebugSessionOptions {
/**
* When specified the newly created debug session is registered as a "child" session of this
* "parent" debug session.
*/
parentSession?: DebugSession;
/**
* Controls whether this session should have a separate debug console or share it
* with the parent session. Has no effect for sessions which do not have a parent session.
* Defaults to Separate.
*/
consoleMode?: DebugConsoleMode;
}
/**
* Namespace for debug functionality.
*/

View file

@ -616,41 +616,6 @@ declare module 'vscode' {
debugAdapterExecutable?(folder: WorkspaceFolder | undefined, token?: CancellationToken): ProviderResult<DebugAdapterExecutable>;
}
/**
* Debug console mode used by debug session, see [options](#DebugSessionOptions).
*/
export enum DebugConsoleMode {
/**
* Debug session should have a separate debug console.
*/
Separate = 0,
/**
* Debug session should share debug console with its parent session.
* This value has no effect for sessions which do not have a parent session.
*/
MergeWithParent = 1
}
/**
* Options for [starting a debug session](#debug.startDebugging).
*/
export interface DebugSessionOptions {
/**
* When specified the newly created debug session is registered as a "child" session of this
* "parent" debug session.
*/
parentSession?: DebugSession;
/**
* Controls whether this session should have a separate debug console or share it
* with the parent session. Has no effect for sessions which do not have a parent session.
* Defaults to Separate.
*/
consoleMode?: DebugConsoleMode;
}
//#endregion
//#region Rob, Matt: logging

View file

@ -348,7 +348,7 @@ class CodeActionAdapter {
only: context.only ? new CodeActionKind(context.only) : undefined
};
return asPromise(() => this._provider.provideCodeActions(doc, ran, codeActionContext, token)).then(commandsOrActions => {
return asPromise(() => this._provider.provideCodeActions(doc, ran, codeActionContext, token)).then((commandsOrActions): extHostProtocol.ICodeActionListDto | undefined => {
if (!isNonEmptyArray(commandsOrActions) || token.isCancellationRequested) {
return undefined;
}
@ -390,7 +390,7 @@ class CodeActionAdapter {
}
}
return <extHostProtocol.ICodeActionListDto>{ cacheId, actions };
return { cacheId, actions };
});
}

View file

@ -260,7 +260,7 @@ export namespace MarkdownString {
const collectUri = (href: string): string => {
try {
let uri = URI.parse(href);
let uri = URI.parse(href, true);
uri = uri.with({ query: _uriMassage(uri.query, resUris) });
resUris[href] = uri;
} catch (e) {

View file

@ -5,7 +5,7 @@
import { Disposable, DisposableStore } from 'vs/base/common/lifecycle';
import { Event, Emitter } from 'vs/base/common/event';
import { EventType, addDisposableListener, addClass, removeClass, isAncestor, getClientArea, position, size, Dimension } from 'vs/base/browser/dom';
import { EventType, addDisposableListener, addClass, removeClass, isAncestor, getClientArea, Dimension, toggleClass } from 'vs/base/browser/dom';
import { onDidChangeFullscreen, isFullscreen } from 'vs/base/browser/browser';
import { IBackupFileService } from 'vs/workbench/services/backup/common/backup';
import { Registry } from 'vs/platform/registry/common/platform';
@ -38,6 +38,8 @@ import { isCodeEditor } from 'vs/editor/browser/editorBrowser';
import { coalesce } from 'vs/base/common/arrays';
import { assertIsDefined } from 'vs/base/common/types';
import { INotificationService, NotificationsFilter } from 'vs/platform/notification/common/notification';
import { IThemeService } from 'vs/platform/theme/common/themeService';
import { WINDOW_ACTIVE_BORDER, WINDOW_INACTIVE_BORDER } from 'vs/workbench/common/theme';
enum Settings {
ACTIVITYBAR_VISIBLE = 'workbench.activityBar.visible',
@ -74,7 +76,8 @@ enum Classes {
EDITOR_HIDDEN = 'noeditorarea',
PANEL_HIDDEN = 'nopanel',
STATUSBAR_HIDDEN = 'nostatusbar',
FULLSCREEN = 'fullscreen'
FULLSCREEN = 'fullscreen',
WINDOW_BORDER = 'border'
}
export abstract class Layout extends Disposable implements IWorkbenchLayoutService {
@ -135,9 +138,12 @@ export abstract class Layout extends Disposable implements IWorkbenchLayoutServi
private contextService!: IWorkspaceContextService;
private backupFileService!: IBackupFileService;
private notificationService!: INotificationService;
private themeService!: IThemeService;
protected readonly state = {
fullscreen: false,
hasFocus: false,
windowBorder: false,
menuBar: {
visibility: 'default' as MenuBarVisibility,
@ -204,6 +210,7 @@ export abstract class Layout extends Disposable implements IWorkbenchLayoutServi
this.contextService = accessor.get(IWorkspaceContextService);
this.storageService = accessor.get(IStorageService);
this.backupFileService = accessor.get(IBackupFileService);
this.themeService = accessor.get(IThemeService);
// Parts
this.editorService = accessor.get(IEditorService);
@ -257,6 +264,12 @@ export abstract class Layout extends Disposable implements IWorkbenchLayoutServi
if ((isWindows || isLinux || isWeb) && getTitleBarStyle(this.configurationService, this.environmentService) === 'custom') {
this._register(this.titleService.onMenubarVisibilityChange(visible => this.onMenubarToggled(visible)));
}
// Theme changes
this._register(this.themeService.onThemeChange(theme => this.updateStyles()));
// Window focus changes
this._register(this.hostService.onDidChangeFocus(e => this.onWindowFocusChanged(e)));
}
private onMenubarToggled(visible: boolean) {
@ -297,6 +310,15 @@ export abstract class Layout extends Disposable implements IWorkbenchLayoutServi
this._onFullscreenChange.fire(this.state.fullscreen);
}
private onWindowFocusChanged(hasFocus: boolean): void {
if (this.state.hasFocus === hasFocus) {
return;
}
this.state.hasFocus = hasFocus;
this.updateWindowBorder();
}
private doUpdateLayoutConfiguration(skipLayout?: boolean): void {
// Sidebar position
@ -366,6 +388,44 @@ export abstract class Layout extends Disposable implements IWorkbenchLayoutServi
this.layout();
}
private updateWindowBorder(skipLayout: boolean = false) {
if (isWeb || getTitleBarStyle(this.configurationService, this.environmentService) !== 'custom') {
return;
}
const theme = this.themeService.getTheme();
const activeBorder = theme.getColor(WINDOW_ACTIVE_BORDER);
const inactiveBorder = theme.getColor(WINDOW_INACTIVE_BORDER);
let windowBorder = false;
if (activeBorder || inactiveBorder) {
windowBorder = true;
// If one color is missing, just fallback to the other one
const borderColor = this.state.hasFocus
? activeBorder ?? inactiveBorder
: inactiveBorder ?? activeBorder;
this.container.style.setProperty('--window-border-color', borderColor ? borderColor.toString() : 'transparent');
}
if (windowBorder === this.state.windowBorder) {
return;
}
this.state.windowBorder = windowBorder;
toggleClass(this.container, Classes.WINDOW_BORDER, windowBorder);
if (!skipLayout) {
this.layout();
}
}
private updateStyles() {
this.updateWindowBorder();
}
private initLayoutState(lifecycleService: ILifecycleService, fileService: IFileService): void {
// Fullscreen
@ -442,6 +502,11 @@ export abstract class Layout extends Disposable implements IWorkbenchLayoutServi
// Zen mode enablement
this.state.zenMode.restore = this.storageService.getBoolean(Storage.ZEN_MODE_ENABLED, StorageScope.WORKSPACE, false) && this.configurationService.getValue(Settings.ZEN_MODE_RESTORE);
this.state.hasFocus = this.hostService.hasFocus;
// Window border
this.updateWindowBorder(true);
}
private resolveEditorsToOpen(fileService: IFileService): Promise<IResourceEditor[]> | IResourceEditor[] {
@ -826,12 +891,14 @@ export abstract class Layout extends Disposable implements IWorkbenchLayoutServi
}));
}
getClientArea(): Dimension {
const dim = getClientArea(this.parent);
return this.state.windowBorder ? new Dimension(dim.width - 2, dim.height - 2) : dim;
}
layout(): void {
if (!this.disposed) {
this._dimension = getClientArea(this.parent);
position(this.container, 0, 0, 0, 0, 'relative');
size(this.container, this._dimension.width, this._dimension.height);
this._dimension = this.getClientArea();
// Layout the grid widget
this.workbenchGrid.layout(this._dimension.width, this._dimension.height);
@ -1079,6 +1146,14 @@ export abstract class Layout extends Disposable implements IWorkbenchLayoutServi
}
}
hasWindowBorder(): boolean {
return this.state.windowBorder;
}
getWindowBorderRadius(): string | undefined {
return this.state.windowBorder && isMacintosh ? '5px' : undefined;
}
isPanelMaximized(): boolean {
if (!this.workbenchGrid) {
return false;
@ -1169,7 +1244,7 @@ export abstract class Layout extends Disposable implements IWorkbenchLayoutServi
}
private createGridDescriptor(): ISerializedGrid {
const workbenchDimensions = getClientArea(this.parent);
const workbenchDimensions = this.getClientArea();
const width = this.storageService.getNumber(Storage.GRID_WIDTH, StorageScope.GLOBAL, workbenchDimensions.width);
const height = this.storageService.getNumber(Storage.GRID_HEIGHT, StorageScope.GLOBAL, workbenchDimensions.height);
// At some point, we will not fall back to old keys from legacy layout, but for now, let's migrate the keys

View file

@ -51,6 +51,18 @@ body.web {
position: relative;
z-index: 1;
overflow: hidden;
height: 100vh;
width: 100vw;
}
.monaco-workbench.border {
height: calc(100vh - 2px);
width: calc(100vw - 2px);
border: 1px solid var(--window-border-color);
}
.monaco-workbench.border.mac {
border-radius: 5px;
}
.monaco-workbench img {

View file

@ -270,11 +270,16 @@ registerThemingParticipant((theme: ITheme, collector: ICssStyleCollector) => {
const activeForegroundColor = theme.getColor(ACTIVITY_BAR_FOREGROUND);
if (activeForegroundColor) {
collector.addRule(`
.monaco-workbench .activitybar > .content :not(.monaco-menu) > .monaco-action-bar .action-item.active .action-label,
.monaco-workbench .activitybar > .content :not(.monaco-menu) > .monaco-action-bar .action-item:focus .action-label,
.monaco-workbench .activitybar > .content :not(.monaco-menu) > .monaco-action-bar .action-item:hover .action-label {
.monaco-workbench .activitybar > .content :not(.monaco-menu) > .monaco-action-bar .action-item.active .action-label:not(.codicon),
.monaco-workbench .activitybar > .content :not(.monaco-menu) > .monaco-action-bar .action-item:focus .action-label:not(.codicon),
.monaco-workbench .activitybar > .content :not(.monaco-menu) > .monaco-action-bar .action-item:hover .action-label:not(.codicon) {
background-color: ${activeForegroundColor} !important;
}
.monaco-workbench .activitybar > .content :not(.monaco-menu) > .monaco-action-bar .action-item.active .action-label.codicon,
.monaco-workbench .activitybar > .content :not(.monaco-menu) > .monaco-action-bar .action-item:focus .action-label.codicon,
.monaco-workbench .activitybar > .content :not(.monaco-menu) > .monaco-action-bar .action-item:hover .action-label.codicon {
color: ${activeForegroundColor} !important;
}
`);
}

View file

@ -306,7 +306,7 @@ export class ActivitybarPart extends Part implements IActivityBarService {
this.globalActivityAction = new ActivityAction({
id: 'workbench.actions.manage',
name: nls.localize('manage', "Manage"),
cssClass: 'update-activity'
cssClass: 'codicon-settings-gear'
});
this.globalActivityActionBar.push(this.globalActivityAction);

View file

@ -8,18 +8,27 @@
position: relative;
padding: 5px 0;
}
.monaco-workbench .activitybar > .content :not(.monaco-menu) > .monaco-action-bar .action-label {
position: relative;
z-index: 1;
display: flex;
overflow: hidden;
height: 40px;
line-height: 40px;
margin-right: 0;
padding: 0 0 0 48px;
box-sizing: border-box;
}
.monaco-workbench .activitybar > .content :not(.monaco-menu) > .monaco-action-bar .action-label:not(.codicon) {
font-size: 15px;
line-height: 40px;
padding: 0 0 0 48px;
}
.monaco-workbench .activitybar > .content :not(.monaco-menu) > .monaco-action-bar .action-label.codicon {
font-size: 24px;
align-items: center;
justify-content: center;
}
.monaco-workbench .activitybar > .content :not(.monaco-menu) > .monaco-action-bar .action-item.checked .active-item-indicator:before,
@ -102,7 +111,7 @@
/* Right aligned */
.monaco-workbench .activitybar.right > .content :not(.monaco-menu) > .monaco-action-bar .action-label {
.monaco-workbench .activitybar.right > .content :not(.monaco-menu) > .monaco-action-bar .action-label:not(.codicon) {
margin-left: 0;
padding: 0 50px 0 0;
background-position: calc(100% - 9px) center;

View file

@ -158,7 +158,16 @@ export class ActivityActionViewItem extends BaseActionViewItem {
if (this.label) {
if (this.options.icon) {
const foreground = this._action.checked ? colors.activeBackgroundColor || colors.activeForegroundColor : colors.inactiveBackgroundColor || colors.inactiveForegroundColor;
this.label.style.backgroundColor = foreground ? foreground.toString() : '';
// TODO @misolori find a cleaner way to do this
const isExtension = this.activity.cssClass?.indexOf('extensionViewlet') === 0;
if (!isExtension) {
// Apply foreground color to activity bar items (codicons)
this.label.style.color = foreground ? foreground.toString() : '';
} else {
// Apply background color to extensions + remote explorer (svgs)
this.label.style.backgroundColor = foreground ? foreground.toString() : '';
}
} else {
const foreground = this._action.checked ? colors.activeForegroundColor : colors.inactiveForegroundColor;
const borderBottomColor = this._action.checked ? colors.activeBorderBottomColor : null;
@ -310,6 +319,12 @@ export class ActivityActionViewItem extends BaseActionViewItem {
this.label.className = 'action-label';
if (this.activity.cssClass) {
// TODO @misolori find a cleaner way to do this
const isExtension = this.activity.cssClass?.indexOf('extensionViewlet') === 0;
if (this.options.icon && !isExtension) {
// Only apply icon class to activity bar items (exclude extensions + remote explorer)
dom.addClass(this.label, 'codicon');
}
dom.addClass(this.label, this.activity.cssClass);
}
@ -346,7 +361,7 @@ export class CompositeOverflowActivityAction extends ActivityAction {
super({
id: 'additionalComposites.action',
name: nls.localize('additionalViews', "Additional Views"),
cssClass: 'toggle-more'
cssClass: 'codicon-more'
});
}

View file

@ -76,6 +76,15 @@
padding-right: 4px; /* does not have trailing separator*/
}
.monaco-workbench .part.editor > .content .editor-group-container > .title.breadcrumbs .breadcrumbs-control .monaco-breadcrumb-item .codicon[class*='codicon-symbol-'] {
padding: 0 1px;
}
.monaco-workbench .part.editor > .content .editor-group-container > .title.breadcrumbs .breadcrumbs-control .monaco-breadcrumb-item .codicon:last-child,
.monaco-workbench .part.editor > .content .editor-group-container > .title .tabs-breadcrumbs .breadcrumbs-control .monaco-breadcrumb-item:last-child .codicon:last-child {
display: none; /* hides chevrons when no tabs visible and when last items */
}
/* Title Actions */
.monaco-workbench .part.editor > .content .editor-group-container > .title .title-actions {
display: flex;

View file

@ -199,8 +199,8 @@
}
/* change close icon to dirty state icon */
.monaco-workbench .part.editor > .content .editor-group-container.active > .title .tabs-container > .tab.dirty > .tab-close .action-label:not(:hover)::before,
.monaco-workbench .part.editor > .content .editor-group-container > .title .tabs-container > .tab.dirty > .tab-close .action-label:not(:hover)::before {
.monaco-workbench .part.editor > .content .editor-group-container.active > .title .tabs-container > .tab.dirty:not(.dirty-border-top) > .tab-close .action-label:not(:hover)::before,
.monaco-workbench .part.editor > .content .editor-group-container > .title .tabs-container > .tab.dirty:not(.dirty-border-top) > .tab-close .action-label:not(:hover)::before {
content: "\ea71"; /* use `circle-filled` icon unicode */
}
@ -232,6 +232,7 @@
padding-right: 5px; /* we need less room when sizing is shrink */
}
.monaco-workbench .part.editor > .content .editor-group-container > .title .tabs-container > .tab.close-button-off.dirty-border-top > .tab-close,
.monaco-workbench .part.editor > .content .editor-group-container > .title .tabs-container > .tab.close-button-off.dirty-border-top > .tab-close {
display: none; /* hide dirty state when highlightModifiedTabs is enabled and when running without close button */
}

View file

@ -589,6 +589,18 @@ export const NOTIFICATIONS_INFO_ICON_FOREGROUND = registerColor('notificationsIn
hc: editorInfoForeground
}, nls.localize('notificationsInfoIconForeground', "The color used for the notification info icon."));
export const WINDOW_ACTIVE_BORDER = registerColor('window.activeBorder', {
dark: null,
light: null,
hc: contrastBorder
}, nls.localize('windowActiveBorder', "The color used for the border of the window when it is active. Only supported in the desktop client."));
export const WINDOW_INACTIVE_BORDER = registerColor('window.inactiveBorder', {
dark: null,
light: null,
hc: contrastBorder
}, nls.localize('windowInactiveBorder', "The color used for the border of the window when it is inactive. Only supported in the desktop client."));
/**
* Base class for all themable workbench components.
*/

View file

@ -180,7 +180,7 @@ export class CustomEditorService extends Disposable implements ICustomEditorServ
): CustomFileEditorInput {
const id = generateUuid();
const webview = new Lazy(() => {
return new UnownedDisposable(this.webviewService.createWebviewEditorOverlay(id, { customClasses: options ? options.customClasses : undefined }, {}));
return new UnownedDisposable(this.webviewService.createWebviewEditorOverlay(id, { customClasses: options?.customClasses }, {}));
});
const input = this.instantiationService.createInstance(CustomFileEditorInput, resource, viewType, id, webview);
if (group) {

View file

@ -84,7 +84,7 @@ Registry.as<ViewletRegistry>(ViewletExtensions.Viewlets).registerViewlet(new Vie
DebugViewlet,
VIEWLET_ID,
nls.localize('debug', "Debug"),
'debug',
'codicon-debug',
3
));

View file

@ -1,5 +0,0 @@
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M3.46279 12.86L3.45815 12.79C3.45964 12.8134 3.46119 12.8367 3.46279 12.86Z" fill="white"/>
<path d="M10.7275 13.5509L7.69304 10.501L8.70723 9.4868L11.9159 12.7117L15.0789 9.54875L16.0931 10.5629L13.0589 13.5972L16.0934 16.647L15.0792 17.6612L11.8705 14.4362L8.70748 17.5993L7.69329 16.5851L10.7275 13.5509Z" fill="white"/>
<path fill-rule="evenodd" clip-rule="evenodd" d="M16.9329 5.00286V6H18.2784L21.1205 3.15788L22.1347 4.17207L19.4435 6.86321L19.476 6.94805C20.0424 8.42597 20.3614 10.094 20.3614 11.86C20.3614 12.1955 20.3499 12.5274 20.3274 12.8552L20.3222 12.93H23.8629V14.3643H20.142L20.1315 14.4217C19.8292 16.075 19.2409 17.5825 18.4398 18.851L18.3802 18.9454L21.8027 22.3852L20.7859 23.3968L17.512 20.1063L17.4131 20.2169C15.934 21.8712 14.0177 22.8629 11.93 22.8629C9.81001 22.8629 7.86653 21.8402 6.37842 20.1395L6.27988 20.0268L3.07125 23.2355L2.05706 22.2213L5.42258 18.8558L5.36431 18.7615C4.59172 17.5118 4.02373 16.0363 3.72847 14.4217L3.71797 14.3643H0V12.93H3.53777L3.53262 12.8552C3.51009 12.5274 3.49858 12.1955 3.49858 11.86C3.49858 10.117 3.80935 8.46951 4.36194 7.00599L4.39377 6.92168L1.63228 4.14621L2.64904 3.13457L5.50003 6H6.92715V5.00286C6.92715 2.23986 9.16701 0 11.93 0C14.693 0 16.9329 2.23986 16.9329 5.00286ZM8.36144 5.00286V6H15.4986V5.00286C15.4986 3.03199 13.9009 1.43429 11.93 1.43429C9.95914 1.43429 8.36144 3.03199 8.36144 5.00286ZM18.1609 7.52498L18.1267 7.43429H5.73328L5.69915 7.52498C5.21331 8.81605 4.93286 10.2859 4.93286 11.86C4.93286 14.6199 5.7951 17.061 7.11691 18.7793C8.43755 20.4962 10.1529 21.4286 11.93 21.4286C13.7072 21.4286 15.4225 20.4962 16.7431 18.7793C18.0649 17.061 18.9271 14.6199 18.9271 11.86C18.9271 10.2859 18.6467 8.81605 18.1609 7.52498Z" fill="white"/>
</svg>

Before

Width:  |  Height:  |  Size: 1.8 KiB

View file

@ -4,10 +4,6 @@
*--------------------------------------------------------------------------------------------*/
/* Activity Bar */
.monaco-workbench .activitybar .monaco-action-bar .action-label.debug {
-webkit-mask: url('debug-activity-bar.svg') no-repeat 50% 50%;
}
.monaco-editor .debug-top-stack-frame-column::before {
background: url('current-arrow.svg') center center no-repeat;
}

View file

@ -36,7 +36,7 @@ suite('Debug - Source', () => {
assert.equal(source.name, 'internalModule.js');
assert.equal(source.inMemory, true);
assert.equal(source.reference, 11);
assert.equal(source.uri.toString(), 'debug:internalModule.js?session%3DaDebugSessionId%26ref%3D11');
assert.equal(source.uri.toString(), 'debug:internalModule.js?session=aDebugSessionId&ref=11');
});
test('get encoded debug data', () => {

View file

@ -3,7 +3,6 @@
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import 'vs/css!./media/extensions';
import { localize } from 'vs/nls';
import { KeyMod, KeyChord, KeyCode } from 'vs/base/common/keyCodes';
import { Registry } from 'vs/platform/registry/common/platform';
@ -81,7 +80,7 @@ const viewletDescriptor = new ViewletDescriptor(
ExtensionsViewlet,
VIEWLET_ID,
localize('extensions', "Extensions"),
'extensions',
'codicon-extensions',
4
);

View file

@ -1,3 +0,0 @@
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
<path fill-rule="evenodd" clip-rule="evenodd" d="M13.5 1.5L15 0H22.5L24 1.5V9L22.5 10.5H15L13.5 9V1.5ZM15 1.5V9H22.5V1.5H15ZM0 15V6L1.5 4.5H9L10.5 6V13.5H18L19.5 15V22.5L18 24H10.5H9H1.5L0 22.5V15ZM9 13.5V6H1.5V13.5H9ZM9 15H1.5V22.5H9V15ZM10.5 22.5H18V15H10.5V22.5Z" fill="white"/>
</svg>

Before

Width:  |  Height:  |  Size: 385 B

View file

@ -1,8 +0,0 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
.monaco-workbench .activitybar > .content .monaco-action-bar .action-label.extensions {
-webkit-mask: url('extensions-activity-bar.svg') no-repeat 50% 50%;
}

View file

@ -77,7 +77,7 @@ Registry.as<ViewletRegistry>(ViewletExtensions.Viewlets).registerViewlet(new Vie
ExplorerViewlet,
VIEWLET_ID,
nls.localize('explore', "Explorer"),
'explore',
'codicon-files',
0
));

View file

@ -3,11 +3,6 @@
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
/* Activity Bar */
.monaco-workbench .activitybar .monaco-action-bar .action-label.explore {
-webkit-mask: url('files-activity-bar.svg') no-repeat 50% 50%;
}
/* --- Explorer viewlet --- */
.explorer-viewlet,
.explorer-folders-view {

View file

@ -1,3 +0,0 @@
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
<path fill-rule="evenodd" clip-rule="evenodd" d="M8.50001 0L17.5 3.57628e-07L22 4.5V16.5682L20.7046 18H16V22.5682L14.5682 24H2.5L1 22.5682L1 7.50001L2.5 6.00001L7.00001 5.99999V1.5L8.50001 0ZM16 1.5V6.00001H20.5L20.5 16.5H8.50001L8.50001 1.5L16 1.5ZM19.8787 4.5L17.5 2.12132V4.5H19.8787ZM7.00001 7.50001V16.5682L8.50001 18H14.5V22.5H2.5L2.5 7.50001H7.00001Z" fill="white"/>
</svg>

Before

Width:  |  Height:  |  Size: 477 B

View file

@ -1,13 +0,0 @@
<svg width="24" height="24" viewBox="0 0 24 24" fill="none"
xmlns="http://www.w3.org/2000/svg">
<g clip-path="url(#clip0)">
<path fill-rule="evenodd" clip-rule="evenodd" d="M1.34375 2.125H21.6562L22.4375 2.90625V11.5048C21.9519 11.1401 21.4272 10.8346 20.875 10.593V3.6875H2.125V17.75H9.9375C9.9375 18.2593 9.9873 18.7698 10.0876 19.2741C10.3167 20.4256 10.8012 21.5058 11.5 22.4375H5.25V20.875H9.9375V19.3125H1.34375L0.5625 18.5312V2.90625L1.34375 2.125Z" fill="white"/>
<path fill-rule="evenodd" clip-rule="evenodd" d="M18.1998 17.1526L20.3527 19.3056L21 18.6591L19.4935 17.1526L21 15.6465L20.3527 15L18.1998 17.1526ZM16.5065 18.7528L15 17.2464L15.6473 16.5998L17.7999 18.7528L15.6473 20.9062L15 20.2593L16.5065 18.7528Z" fill="white"/>
<circle cx="17.75" cy="17.75" r="5.625" stroke="white" stroke-width="1.25"/>
</g>
<defs>
<clipPath id="clip0">
<rect width="24" height="24" fill="white"/>
</clipPath>
</defs>
</svg>

Before

Width:  |  Height:  |  Size: 939 B

View file

@ -461,7 +461,7 @@ Registry.as<ViewletRegistry>(ViewletExtensions.Viewlets).registerViewlet(new Vie
RemoteViewlet,
VIEWLET_ID,
nls.localize('remote.explorer', "Remote Explorer"),
'remote',
'codicon-remote-explorer',
4
));

View file

@ -3,10 +3,6 @@
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
.monaco-workbench .activitybar>.content .monaco-action-bar .action-label.remote {
-webkit-mask: url('remote-activity-bar.svg') no-repeat 50% 50%;
}
.remote-help-content .monaco-list .monaco-list-row .remote-help-tree-node-item {
display: flex;
height: 22px;

View file

@ -1,10 +0,0 @@
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
<g clip-path="url(#clip0)">
<path d="M21 8.25C21.0035 7.55379 20.8131 6.87035 20.4502 6.27622C20.0872 5.68209 19.566 5.20073 18.945 4.88605C18.3239 4.57137 17.6275 4.4358 16.9338 4.49451C16.24 4.55323 15.5764 4.80392 15.017 5.2185C14.4577 5.63308 14.0248 6.19518 13.7669 6.84186C13.509 7.48854 13.4361 8.19426 13.5566 8.87998C13.6771 9.5657 13.986 10.2044 14.4489 10.7244C14.9118 11.2445 15.5104 11.6254 16.1775 11.8245C15.9312 12.3251 15.5501 12.7472 15.0771 13.0431C14.6041 13.3391 14.058 13.4973 13.5 13.5H10.5C9.3894 13.5039 8.32 13.921 7.5 14.67V7.4235C8.41053 7.23764 9.21962 6.72031 9.7704 5.97181C10.3212 5.22331 10.5744 4.29696 10.481 3.37236C10.3876 2.44776 9.95422 1.59077 9.26486 0.96755C8.57551 0.344328 7.67931 -0.000732422 6.75 -0.000732422C5.82069 -0.000732422 4.92449 0.344328 4.23513 0.96755C3.54578 1.59077 3.11239 2.44776 3.01899 3.37236C2.92558 4.29696 3.17882 5.22331 3.7296 5.97181C4.28038 6.72031 5.08947 7.23764 6 7.4235V16.5735C5.09118 16.7473 4.27737 17.2477 3.71208 17.9802C3.14679 18.7128 2.8691 19.6269 2.93137 20.5501C2.99365 21.4733 3.39159 22.3418 4.05014 22.9917C4.70869 23.6417 5.58233 24.0283 6.50626 24.0785C7.4302 24.1287 8.34056 23.839 9.06564 23.2642C9.79073 22.6894 10.2804 21.8691 10.4423 20.9581C10.6042 20.047 10.4272 19.1083 9.94457 18.3188C9.46196 17.5293 8.70715 16.9437 7.8225 16.6725C8.06925 16.1724 8.4505 15.751 8.92346 15.4556C9.39642 15.1601 9.94236 15.0024 10.5 15H13.5C14.436 14.9957 15.3473 14.6996 16.1071 14.153C16.8669 13.6064 17.4373 12.8365 17.739 11.9505C18.6381 11.8323 19.4639 11.3922 20.0635 10.7118C20.6631 10.0314 20.9958 9.15685 21 8.25ZM4.5 3.75C4.5 3.30499 4.63196 2.86998 4.87919 2.49997C5.12643 2.12996 5.47783 1.84157 5.88896 1.67127C6.3001 1.50098 6.7525 1.45642 7.18895 1.54324C7.62541 1.63005 8.02632 1.84434 8.34099 2.15901C8.65566 2.47368 8.86995 2.87459 8.95677 3.31105C9.04358 3.74751 8.99903 4.19991 8.82873 4.61104C8.65843 5.02217 8.37004 5.37358 8.00003 5.62081C7.63002 5.86804 7.19501 6 6.75 6C6.15326 6 5.58097 5.76295 5.15901 5.34099C4.73705 4.91904 4.5 4.34674 4.5 3.75ZM9 20.25C9 20.695 8.86804 21.13 8.62081 21.5C8.37357 21.87 8.02217 22.1584 7.61104 22.3287C7.1999 22.499 6.7475 22.5436 6.31105 22.4568C5.87459 22.37 5.47368 22.1557 5.15901 21.841C4.84434 21.5263 4.63005 21.1254 4.54323 20.689C4.45642 20.2525 4.50097 19.8001 4.67127 19.389C4.84157 18.9778 5.12996 18.6264 5.49997 18.3792C5.86998 18.132 6.30499 18 6.75 18C7.34674 18 7.91903 18.2371 8.34099 18.659C8.76295 19.081 9 19.6533 9 20.25ZM17.25 10.5C16.805 10.5 16.37 10.368 16 10.1208C15.63 9.87358 15.3416 9.52217 15.1713 9.11104C15.001 8.69991 14.9564 8.24751 15.0432 7.81105C15.13 7.37459 15.3443 6.97368 15.659 6.65901C15.9737 6.34434 16.3746 6.13005 16.811 6.04323C17.2475 5.95642 17.6999 6.00098 18.111 6.17127C18.5222 6.34157 18.8736 6.62996 19.1208 6.99997C19.368 7.36998 19.5 7.80499 19.5 8.25C19.5 8.84674 19.2629 9.41904 18.841 9.84099C18.419 10.2629 17.8467 10.5 17.25 10.5Z" fill="white"/>
</g>
<defs>
<clipPath id="clip0">
<rect width="24" height="24" fill="white"/>
</clipPath>
</defs>
</svg>

Before

Width:  |  Height:  |  Size: 3.1 KiB

View file

@ -3,10 +3,6 @@
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
.monaco-workbench .activitybar > .content .monaco-action-bar .action-label.scm {
-webkit-mask: url('scm-activity-bar.svg') no-repeat 50% 50%;
}
.monaco-workbench .viewlet.scm-viewlet .collapsible.header .actions {
width: initial;
flex: 1;

View file

@ -42,7 +42,7 @@ Registry.as<ViewletRegistry>(ViewletExtensions.Viewlets).registerViewlet(new Vie
SCMViewlet,
VIEWLET_ID,
localize('source control', "Source Control"),
'scm',
'codicon-source-control',
2
));

View file

@ -1,3 +0,0 @@
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
<path fill-rule="evenodd" clip-rule="evenodd" d="M22 8.25C22 11.9779 18.9779 15 15.25 15C11.5221 15 8.5 11.9779 8.5 8.25C8.5 4.52208 11.5221 1.5 15.25 1.5C18.9779 1.5 22 4.52208 22 8.25ZM23.5 8.25C23.5 12.8063 19.8063 16.5 15.25 16.5C13.3323 16.5 11.5674 15.8457 10.1664 14.7481L2.12509 23.8677L1 22.8756L9.07353 13.7195C7.78334 12.2636 7 10.3483 7 8.25C7 3.69365 10.6937 0 15.25 0C19.8063 0 23.5 3.69365 23.5 8.25Z" fill="white"/>
</svg>

Before

Width:  |  Height:  |  Size: 535 B

View file

@ -1,9 +0,0 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
/* Activity Bar */
.monaco-workbench .activitybar .monaco-action-bar .action-label.search {
-webkit-mask: url('search-activity-bar.svg') no-repeat 50% 50%;
}

View file

@ -11,7 +11,6 @@ import * as objects from 'vs/base/common/objects';
import * as platform from 'vs/base/common/platform';
import { dirname } from 'vs/base/common/resources';
import { URI } from 'vs/base/common/uri';
import 'vs/css!./media/search.contribution';
import { registerLanguageCommand } from 'vs/editor/browser/editorExtensions';
import { ICodeEditorService } from 'vs/editor/browser/services/codeEditorService';
import { getSelectionSearchString } from 'vs/editor/contrib/find/findController';
@ -507,7 +506,7 @@ Registry.as<ViewletRegistry>(ViewletExtensions.Viewlets).registerViewlet(new Vie
SearchViewlet,
VIEWLET_ID,
nls.localize('name', "Search"),
'search',
'codicon-search',
1
));

View file

@ -67,4 +67,4 @@ export class SearchPanel extends Panel {
getSearchView(): SearchView {
return this.searchView;
}
}
}

View file

@ -80,6 +80,7 @@ class PartsSplash {
sideBarBackground: this._getThemeColor(themes.SIDE_BAR_BACKGROUND),
statusBarBackground: this._getThemeColor(themes.STATUS_BAR_BACKGROUND),
statusBarNoFolderBackground: this._getThemeColor(themes.STATUS_BAR_NO_FOLDER_BACKGROUND),
windowBorder: this._getThemeColor(themes.WINDOW_ACTIVE_BORDER) ?? this._getThemeColor(themes.WINDOW_INACTIVE_BORDER)
};
const layoutInfo = !this._shouldSaveLayoutInfo() ? undefined : {
sideBarSide: this._layoutService.getSideBarPosition() === Position.RIGHT ? 'right' : 'left',
@ -88,6 +89,8 @@ class PartsSplash {
activityBarWidth: this._layoutService.isVisible(Parts.ACTIVITYBAR_PART) ? getTotalWidth(assertIsDefined(this._layoutService.getContainer(Parts.ACTIVITYBAR_PART))) : 0,
sideBarWidth: this._layoutService.isVisible(Parts.SIDEBAR_PART) ? getTotalWidth(assertIsDefined(this._layoutService.getContainer(Parts.SIDEBAR_PART))) : 0,
statusBarHeight: this._layoutService.isVisible(Parts.STATUSBAR_PART) ? getTotalHeight(assertIsDefined(this._layoutService.getContainer(Parts.STATUSBAR_PART))) : 0,
windowBorder: this._layoutService.hasWindowBorder(),
windowBorderRadius: this._layoutService.getWindowBorderRadius()
};
this._textFileService.write(
URI.file(join(this._envService.userDataPath, 'rapid_render.json')),

View file

@ -83,6 +83,7 @@ import { CancellationToken, CancellationTokenSource } from 'vs/base/common/cance
const QUICKOPEN_HISTORY_LIMIT_CONFIG = 'task.quickOpen.history';
const QUICKOPEN_DETAIL_CONFIG = 'task.quickOpen.detail';
const PROBLEM_MATCHER_NEVER_CONFIG = 'task.problemMatchers.neverPrompt';
const QUICKOPEN_SKIP_CONFIG = 'task.quickOpen.skip';
export namespace ConfigureTaskAction {
export const ID = 'workbench.action.tasks.configureTaskRunner';
@ -1355,7 +1356,7 @@ export abstract class AbstractTaskService extends Disposable implements ITaskSer
this.notificationService.prompt(Severity.Warning, nls.localize('TaskSystem.slowProvider', "The {0} task provider is slow. The extension that provides {0} tasks may provide a setting to disable it, or you can disable all tasks providers", type),
[settings, disableAll, dontShow]);
}
}, 2000);
}, 4000);
}
});
}
@ -1997,7 +1998,7 @@ export abstract class AbstractTaskService extends Disposable implements ITaskSer
for (let task of tasks) {
let key = task.getRecentlyUsedKey();
if (!key || !recentlyUsedTasks.has(key)) {
if (task._source.kind === TaskSourceKind.Workspace) {
if ((task._source.kind === TaskSourceKind.Workspace) || (task._source.kind === TaskSourceKind.User)) {
configured.push(task);
} else {
detected.push(task);
@ -2022,6 +2023,8 @@ export abstract class AbstractTaskService extends Disposable implements ITaskSer
}
private showQuickPick(tasks: Promise<Task[]> | Task[], placeHolder: string, defaultEntry?: TaskQuickPickEntry, group: boolean = false, sort: boolean = false, selectedEntry?: TaskQuickPickEntry, additionalEntries?: TaskQuickPickEntry[]): Promise<TaskQuickPickEntry | undefined | null> {
const tokenSource = new CancellationTokenSource();
const cancellationToken: CancellationToken = tokenSource.token;
let _createEntries = (): Promise<QuickPickInput<TaskQuickPickEntry>[]> => {
if (Array.isArray(tasks)) {
return Promise.resolve(this.createTaskQuickPickEntries(tasks, group, sort, selectedEntry));
@ -2029,15 +2032,18 @@ export abstract class AbstractTaskService extends Disposable implements ITaskSer
return tasks.then((tasks) => this.createTaskQuickPickEntries(tasks, group, sort, selectedEntry));
}
};
return this.quickInputService.pick(_createEntries().then((entries) => {
if ((entries.length === 0) && defaultEntry) {
const pickEntries = _createEntries().then((entries) => {
if ((entries.length === 1) && this.configurationService.getValue<boolean>(QUICKOPEN_SKIP_CONFIG)) {
tokenSource.cancel();
} else if ((entries.length === 0) && defaultEntry) {
entries.push(defaultEntry);
} else if (entries.length > 1 && additionalEntries && additionalEntries.length > 0) {
entries.push({ type: 'separator', label: '' });
entries.push(additionalEntries[0]);
}
return entries;
}), {
});
return this.quickInputService.pick(pickEntries, {
placeHolder,
matchOnDescription: true,
onDidTriggerItemButton: context => {
@ -2049,6 +2055,18 @@ export abstract class AbstractTaskService extends Disposable implements ITaskSer
this.openConfig(task);
}
}
}, cancellationToken).then(async (selection) => {
if (cancellationToken.isCancellationRequested) {
// canceled when there's only one task
const task = (await pickEntries)[0];
if ((<any>task).task) {
selection = <TaskQuickPickEntry>task;
}
}
if (!selection) {
return;
}
return selection;
});
}

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