Merge branch 'master' into joh/electron4tests

This commit is contained in:
Johannes Rieken 2017-02-20 09:54:31 +01:00
commit c3c6520f83
250 changed files with 8529 additions and 4302 deletions

1
.vscode/launch.json vendored
View file

@ -47,6 +47,7 @@
"protocol": "legacy",
"port": 5870,
"sourceMaps": true,
"restart": true,
"outFiles": [
"${workspaceRoot}/out/**/*.js"
]

View file

@ -40,7 +40,7 @@ const nodeModules = ['electron', 'original-fs']
// Build
const builtInExtensions = [
{ name: 'ms-vscode.node-debug', version: '1.10.11' },
{ name: 'ms-vscode.node-debug', version: '1.10.14' },
{ name: 'ms-vscode.node-debug2', version: '1.10.0' }
];

View file

@ -169,14 +169,11 @@ function prepareRpmPackage(arch) {
function buildRpmPackage(arch) {
const rpmArch = getRpmPackageArch(arch);
const rpmBuildPath = getRpmBuildPath(rpmArch);
const rpmOut = rpmBuildPath + '/RPMS/' + rpmArch;
const destination = '.build/linux/rpm/' + rpmArch;
return shell.task([
'mkdir -p ' + destination,
'HOME="$(pwd)/' + destination + '" fakeroot rpmbuild -bb ' + rpmBuildPath + '/SPECS/' + product.applicationName + '.spec --target=' + rpmArch,
'cp "' + rpmOut + '/$(ls ' + rpmOut + ')" ' + destination + '/',
'createrepo ' + destination
'HOME="$(pwd)/' + destination + '" fakeroot rpmbuild -bb ' + rpmBuildPath + '/SPECS/' + product.applicationName + '.spec --target=' + rpmArch
]);
}

View file

@ -3,24 +3,24 @@
"version": "0.1.0",
"dependencies": {
"vscode-jsonrpc": {
"version": "3.0.2-beta.5",
"from": "vscode-jsonrpc@>=3.0.2-beta.5 <4.0.0",
"resolved": "https://registry.npmjs.org/vscode-jsonrpc/-/vscode-jsonrpc-3.0.2-beta.5.tgz"
"version": "3.1.0-alpha.1",
"from": "vscode-jsonrpc@>=3.1.0-alpha.1 <4.0.0",
"resolved": "https://registry.npmjs.org/vscode-jsonrpc/-/vscode-jsonrpc-3.1.0-alpha.1.tgz"
},
"vscode-languageclient": {
"version": "3.0.2-beta.5",
"version": "3.1.0-alpha.1",
"from": "vscode-languageclient@next",
"resolved": "https://registry.npmjs.org/vscode-languageclient/-/vscode-languageclient-3.0.2-beta.5.tgz"
"resolved": "https://registry.npmjs.org/vscode-languageclient/-/vscode-languageclient-3.1.0-alpha.1.tgz"
},
"vscode-languageserver-types": {
"version": "3.0.2-beta.5",
"from": "vscode-languageserver-types@>=3.0.2-beta.5 <4.0.0",
"resolved": "https://registry.npmjs.org/vscode-languageserver-types/-/vscode-languageserver-types-3.0.2-beta.5.tgz"
"version": "3.0.3",
"from": "vscode-languageserver-types@>=3.0.3 <4.0.0",
"resolved": "https://registry.npmjs.org/vscode-languageserver-types/-/vscode-languageserver-types-3.0.3.tgz"
},
"vscode-nls": {
"version": "2.0.1",
"from": "vscode-nls@>=2.0.1 <3.0.0",
"resolved": "https://registry.npmjs.org/vscode-nls/-/vscode-nls-2.0.1.tgz"
"version": "2.0.2",
"from": "vscode-nls@2.0.2",
"resolved": "https://registry.npmjs.org/vscode-nls/-/vscode-nls-2.0.2.tgz"
}
}
}

View file

@ -17,8 +17,8 @@
"postinstall": "cd server && npm install",
"install-client-next": "npm install vscode-languageclient@next -f -S",
"install-client-local": "npm install ../../../vscode-languageserver-node/client -f -S",
"update-grammar": "node ../../build/npm/update-grammar.js atom/language-css grammars/css.cson ./syntaxes/css.tmLanguage.json"
},
"update-grammar": "node ../../build/npm/update-grammar.js atom/language-css grammars/css.cson ./syntaxes/css.tmLanguage.json"
},
"contributes": {
"languages": [
{
@ -657,7 +657,7 @@
}
},
"dependencies": {
"vscode-languageclient": "^3.0.2-beta.5",
"vscode-languageclient": "^3.1.0-alpha.1",
"vscode-nls": "^2.0.2"
},
"devDependencies": {

View file

@ -3,24 +3,24 @@
"version": "1.0.0",
"dependencies": {
"vscode-css-languageservice": {
"version": "2.0.0-next.9",
"version": "2.0.0",
"from": "vscode-css-languageservice@next",
"resolved": "https://registry.npmjs.org/vscode-css-languageservice/-/vscode-css-languageservice-2.0.0-next.9.tgz"
"resolved": "https://registry.npmjs.org/vscode-css-languageservice/-/vscode-css-languageservice-2.0.0.tgz"
},
"vscode-jsonrpc": {
"version": "3.0.2-beta.5",
"from": "vscode-jsonrpc@>=3.0.2-beta.5 <4.0.0",
"resolved": "https://registry.npmjs.org/vscode-jsonrpc/-/vscode-jsonrpc-3.0.2-beta.5.tgz"
"version": "3.1.0-alpha.1",
"from": "vscode-jsonrpc@>=3.1.0-alpha.1 <4.0.0",
"resolved": "https://registry.npmjs.org/vscode-jsonrpc/-/vscode-jsonrpc-3.1.0-alpha.1.tgz"
},
"vscode-languageserver": {
"version": "3.0.2-beta.5",
"version": "3.1.0-alpha.1",
"from": "vscode-languageserver@next",
"resolved": "https://registry.npmjs.org/vscode-languageserver/-/vscode-languageserver-3.0.2-beta.5.tgz"
"resolved": "https://registry.npmjs.org/vscode-languageserver/-/vscode-languageserver-3.1.0-alpha.1.tgz"
},
"vscode-languageserver-types": {
"version": "3.0.2-beta.5",
"from": "vscode-languageserver-types@3.0.2-beta.5",
"resolved": "https://registry.npmjs.org/vscode-languageserver-types/-/vscode-languageserver-types-3.0.2-beta.5.tgz"
"version": "3.0.3",
"from": "vscode-languageserver-types@>=3.0.3 <4.0.0",
"resolved": "https://registry.npmjs.org/vscode-languageserver-types/-/vscode-languageserver-types-3.0.3.tgz"
},
"vscode-nls": {
"version": "2.0.2",

View file

@ -8,8 +8,8 @@
"node": "*"
},
"dependencies": {
"vscode-css-languageservice": "^2.0.0-next.9",
"vscode-languageserver": "^3.0.2-beta.5"
"vscode-css-languageservice": "^2.0.0",
"vscode-languageserver": "^3.1.0-alpha.1"
},
"devDependencies": {
"@types/node": "^6.0.51"

View file

@ -21,6 +21,15 @@
},
"contributes": {
"commands": [
{
"command": "git.init",
"title": "%command.init%",
"category": "Git",
"icon": {
"light": "resources/icons/light/git.svg",
"dark": "resources/icons/dark/git.svg"
}
},
{
"command": "git.refresh",
"title": "%command.refresh%",
@ -66,6 +75,16 @@
"dark": "resources/icons/dark/stage.svg"
}
},
{
"command": "git.stageSelectedRanges",
"title": "%command.stageSelectedRanges%",
"category": "Git"
},
{
"command": "git.revertSelectedRanges",
"title": "%command.revertSelectedRanges%",
"category": "Git"
},
{
"command": "git.unstage",
"title": "%command.unstage%",
@ -84,6 +103,11 @@
"dark": "resources/icons/dark/unstage.svg"
}
},
{
"command": "git.unstageSelectedRanges",
"title": "%command.unstageSelectedRanges%",
"category": "Git"
},
{
"command": "git.clean",
"title": "%command.clean%",
@ -191,189 +215,296 @@
}
],
"menus": {
"commandPalette": [
{
"command": "git.init",
"when": "scmProvider == git && scmProviderState == norepo"
},
{
"command": "git.refresh",
"when": "scmProvider == git && scmProviderState == idle"
},
{
"command": "git.openChange",
"when": "scmProvider == git && scmProviderState == idle"
},
{
"command": "git.openFile",
"when": "scmProvider == git && scmProviderState == idle"
},
{
"command": "git.stage",
"when": "scmProvider == git && scmProviderState == idle"
},
{
"command": "git.stageAll",
"when": "scmProvider == git && scmProviderState == idle"
},
{
"command": "git.unstage",
"when": "scmProvider == git && scmProviderState == idle"
},
{
"command": "git.unstageAll",
"when": "scmProvider == git && scmProviderState == idle"
},
{
"command": "git.clean",
"when": "scmProvider == git && scmProviderState == idle"
},
{
"command": "git.cleanAll",
"when": "scmProvider == git && scmProviderState == idle"
},
{
"command": "git.commit",
"when": "scmProvider == git && scmProviderState == idle"
},
{
"command": "git.commitStaged",
"when": "scmProvider == git && scmProviderState == idle"
},
{
"command": "git.commitStagedSigned",
"when": "scmProvider == git && scmProviderState == idle"
},
{
"command": "git.commitAll",
"when": "scmProvider == git && scmProviderState == idle"
},
{
"command": "git.commitAllSigned",
"when": "scmProvider == git && scmProviderState == idle"
},
{
"command": "git.undoCommit",
"when": "scmProvider == git && scmProviderState == idle"
},
{
"command": "git.checkout",
"when": "scmProvider == git && scmProviderState == idle"
},
{
"command": "git.branch",
"when": "scmProvider == git && scmProviderState == idle"
},
{
"command": "git.pull",
"when": "scmProvider == git && scmProviderState == idle"
},
{
"command": "git.pullRebase",
"when": "scmProvider == git && scmProviderState == idle"
},
{
"command": "git.push",
"when": "scmProvider == git && scmProviderState == idle"
},
{
"command": "git.pushTo",
"when": "scmProvider == git && scmProviderState == idle"
},
{
"command": "git.sync",
"when": "scmProvider == git && scmProviderState == idle"
},
{
"command": "git.publish",
"when": "scmProvider == git && scmProviderState == idle"
},
{
"command": "git.showOutput",
"when": "scmProvider == git && scmProviderState == idle"
}
],
"scm/title": [
{
"command": "git.init",
"group": "navigation",
"when": "scmProvider == git && scmProviderState == norepo"
},
{
"command": "git.commit",
"group": "navigation",
"when": "scmProvider == git"
"when": "scmProvider == git && scmProviderState == idle"
},
{
"command": "git.refresh",
"group": "navigation",
"when": "scmProvider == git"
"when": "scmProvider == git && scmProviderState == idle"
},
{
"command": "git.sync",
"group": "1_sync",
"when": "scmProvider == git"
"when": "scmProvider == git && scmProviderState == idle"
},
{
"command": "git.pull",
"group": "1_sync",
"when": "scmProvider == git"
"when": "scmProvider == git && scmProviderState == idle"
},
{
"command": "git.pullRebase",
"group": "1_sync",
"when": "scmProvider == git"
"when": "scmProvider == git && scmProviderState == idle"
},
{
"command": "git.push",
"group": "1_sync",
"when": "scmProvider == git"
"when": "scmProvider == git && scmProviderState == idle"
},
{
"command": "git.pushTo",
"group": "1_sync",
"when": "scmProvider == git"
"when": "scmProvider == git && scmProviderState == idle"
},
{
"command": "git.publish",
"group": "2_publish",
"when": "scmProvider == git"
"when": "scmProvider == git && scmProviderState == idle"
},
{
"command": "git.commitStaged",
"group": "3_commit",
"when": "scmProvider == git"
"when": "scmProvider == git && scmProviderState == idle"
},
{
"command": "git.commitStagedSigned",
"group": "3_commit",
"when": "scmProvider == git"
"when": "scmProvider == git && scmProviderState == idle"
},
{
"command": "git.commitAll",
"group": "3_commit",
"when": "scmProvider == git"
"when": "scmProvider == git && scmProviderState == idle"
},
{
"command": "git.commitAllSigned",
"group": "3_commit",
"when": "scmProvider == git"
"when": "scmProvider == git && scmProviderState == idle"
},
{
"command": "git.undoCommit",
"group": "3_commit",
"when": "scmProvider == git"
"when": "scmProvider == git && scmProviderState == idle"
},
{
"command": "git.unstageAll",
"group": "4_stage",
"when": "scmProvider == git"
"when": "scmProvider == git && scmProviderState == idle"
},
{
"command": "git.cleanAll",
"group": "4_stage",
"when": "scmProvider == git"
"when": "scmProvider == git && scmProviderState == idle"
},
{
"command": "git.showOutput",
"group": "5_output",
"when": "scmProvider == git"
"when": "scmProvider == git && scmProviderState == idle"
}
],
"scm/resourceGroup/context": [
{
"command": "git.stageAll",
"when": "scmProvider == git && scmResourceGroup == merge",
"when": "scmProvider == git && scmProviderState == idle && scmResourceGroup == merge",
"group": "1_modification"
},
{
"command": "git.stageAll",
"when": "scmProvider == git && scmResourceGroup == merge",
"when": "scmProvider == git && scmProviderState == idle && scmResourceGroup == merge",
"group": "inline"
},
{
"command": "git.unstageAll",
"when": "scmProvider == git && scmResourceGroup == index",
"when": "scmProvider == git && scmProviderState == idle && scmResourceGroup == index",
"group": "1_modification"
},
{
"command": "git.unstageAll",
"when": "scmProvider == git && scmResourceGroup == index",
"when": "scmProvider == git && scmProviderState == idle && scmResourceGroup == index",
"group": "inline"
},
{
"command": "git.cleanAll",
"when": "scmProvider == git && scmResourceGroup == workingTree",
"when": "scmProvider == git && scmProviderState == idle && scmResourceGroup == workingTree",
"group": "1_modification"
},
{
"command": "git.stageAll",
"when": "scmProvider == git && scmResourceGroup == workingTree",
"when": "scmProvider == git && scmProviderState == idle && scmResourceGroup == workingTree",
"group": "1_modification"
},
{
"command": "git.cleanAll",
"when": "scmProvider == git && scmResourceGroup == workingTree",
"when": "scmProvider == git && scmProviderState == idle && scmResourceGroup == workingTree",
"group": "inline"
},
{
"command": "git.stageAll",
"when": "scmProvider == git && scmResourceGroup == workingTree",
"when": "scmProvider == git && scmProviderState == idle && scmResourceGroup == workingTree",
"group": "inline"
}
],
"scm/resource/context": [
{
"command": "git.stage",
"when": "scmProvider == git && scmResourceGroup == merge",
"when": "scmProvider == git && scmProviderState == idle && scmResourceGroup == merge",
"group": "1_modification"
},
{
"command": "git.stage",
"when": "scmProvider == git && scmResourceGroup == merge",
"when": "scmProvider == git && scmProviderState == idle && scmResourceGroup == merge",
"group": "inline"
},
{
"command": "git.openChange",
"when": "scmProvider == git && scmResourceGroup == index",
"when": "scmProvider == git && scmProviderState == idle && scmResourceGroup == index",
"group": "navigation"
},
{
"command": "git.openFile",
"when": "scmProvider == git && scmResourceGroup == index",
"when": "scmProvider == git && scmProviderState == idle && scmResourceGroup == index",
"group": "navigation"
},
{
"command": "git.unstage",
"when": "scmProvider == git && scmResourceGroup == index",
"when": "scmProvider == git && scmProviderState == idle && scmResourceGroup == index",
"group": "1_modification"
},
{
"command": "git.unstage",
"when": "scmProvider == git && scmResourceGroup == index",
"when": "scmProvider == git && scmProviderState == idle && scmResourceGroup == index",
"group": "inline"
},
{
"command": "git.openChange",
"when": "scmProvider == git && scmResourceGroup == workingTree",
"when": "scmProvider == git && scmProviderState == idle && scmResourceGroup == workingTree",
"group": "navigation"
},
{
"command": "git.openFile",
"when": "scmProvider == git && scmResourceGroup == workingTree",
"when": "scmProvider == git && scmProviderState == idle && scmResourceGroup == workingTree",
"group": "navigation"
},
{
"command": "git.stage",
"when": "scmProvider == git && scmResourceGroup == workingTree",
"when": "scmProvider == git && scmProviderState == idle && scmResourceGroup == workingTree",
"group": "1_modification"
},
{
"command": "git.clean",
"when": "scmProvider == git && scmResourceGroup == workingTree",
"when": "scmProvider == git && scmProviderState == idle && scmResourceGroup == workingTree",
"group": "1_modification"
},
{
"command": "git.clean",
"when": "scmProvider == git && scmResourceGroup == workingTree",
"when": "scmProvider == git && scmProviderState == idle && scmResourceGroup == workingTree",
"group": "inline"
},
{
"command": "git.stage",
"when": "scmProvider == git && scmResourceGroup == workingTree",
"when": "scmProvider == git && scmProviderState == idle && scmResourceGroup == workingTree",
"group": "inline"
}
],

View file

@ -1,11 +1,15 @@
{
"command.init": "Initialize Git Repository",
"command.refresh": "Refresh",
"command.openChange": "Open Change",
"command.openFile": "Open File",
"command.stage": "Stage",
"command.stageAll": "Stage All",
"command.stageSelectedRanges": "Stage Selected Ranges",
"command.revertSelectedRanges": "Revert Selected Ranges",
"command.unstage": "Unstage",
"command.unstageAll": "Unstage All",
"command.unstageSelectedRanges": "Unstage Selected Ranges",
"command.clean": "Clean",
"command.cleanAll": "Clean All",
"command.commit": "Commit",

View file

@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" width="32" height="32"><path d="M27.459 14.902l-10.439-10.439c-.296-.294-.672-.452-1.089-.452-.417 0-.793.157-1.089.452l-2.248 2.247 2.549 2.549c.249-.112.522-.177.813-.177 1.106 0 2.002.896 2.002 2.002 0 .291-.064.565-.176.814l2.311 2.336c.25-.111.633-.234.923-.234 1.106 0 2 .911 2 2.016s-.894 1.969-2 1.969c-1.105-.001-2.016-.751-2.016-1.985 0-.28.016-.462.119-.704l-2.373-2.374-.023.007v6.274c.747.295 1.277 1.026 1.277 1.875 0 1.105-.878 2.016-1.984 2.016-1.104 0-2.031-.926-2.031-2.031 0-.846.535-1.564 1.28-1.857l.001-6.25c-.762-.282-1.309-1.009-1.309-1.871 0-.28.059-.546.162-.788l-2.555-2.557-7.115 7.114c-.599.601-.601 1.576.001 2.178l10.44 10.518c.296.295.671.45 1.089.45.415 0 .796-.159 1.089-.45l10.391-10.471c.601-.599.599-1.576 0-2.177z" fill="#fff"/></svg>

After

Width:  |  Height:  |  Size: 812 B

View file

@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" width="32" height="32"><defs><clipPath><path d="M.06 91.886h91.828v-91.886h-91.828v91.886z"/></clipPath><clipPath id="a"><path d="M0 0h92v92h-92v-92z"/></clipPath></defs><path d="M28.497 14.84l-11.354-11.353c-.653-.654-1.714-.654-2.368 0l-2.357 2.358 2.99 2.991c.695-.235 1.492-.077 2.046.477.557.558.713 1.361.473 2.059l2.882 2.882c.698-.241 1.502-.085 2.059.473.778.778.778 2.039 0 2.818-.779.779-2.04.779-2.819 0-.586-.586-.73-1.446-.434-2.167l-2.688-2.688v7.074c.19.094.369.219.527.377.778.778.778 2.039 0 2.819-.778.778-2.04.778-2.818 0-.778-.779-.778-2.04 0-2.819.192-.192.415-.338.653-.435v-7.14c-.237-.097-.46-.241-.653-.435-.589-.589-.731-1.455-.429-2.179l-2.948-2.949-7.785 7.785c-.654.655-.654 1.715 0 2.369l11.354 11.353c.654.654 1.714.654 2.369 0l11.3-11.301c.654-.654.654-1.715 0-2.369" fill="#424242" clip-path="url(#a)"/></svg>

After

Width:  |  Height:  |  Size: 883 B

View file

@ -5,9 +5,10 @@
'use strict';
import { Uri, commands, scm, Disposable, SCMResourceGroup, SCMResource, window, workspace, QuickPickItem, OutputChannel } from 'vscode';
import { Uri, commands, scm, Disposable, SCMResourceGroup, SCMResource, window, workspace, QuickPickItem, OutputChannel, computeDiff, Range, WorkspaceEdit, Position } from 'vscode';
import { Ref, RefType } from './git';
import { Model, Resource, Status, CommitOptions } from './model';
import * as staging from './staging';
import * as path from 'path';
import * as nls from 'vscode-nls';
@ -133,14 +134,7 @@ export class CommandCenter {
return resource.original.with({ scheme: 'git', query: 'HEAD' });
case Status.MODIFIED:
const uriString = resource.original.toString();
const [indexStatus] = this.model.indexGroup.resources.filter(r => r.original.toString() === uriString);
if (indexStatus) {
return resource.uri.with({ scheme: 'git' });
}
return resource.uri.with({ scheme: 'git', query: 'HEAD' });
return resource.uri.with({ scheme: 'git', query: '~' });
}
}
@ -190,6 +184,11 @@ export class CommandCenter {
return '';
}
@command('git.init')
async init(): Promise<void> {
await this.model.init();
}
@command('git.openFile')
async openFile(uri: Uri): Promise<void> {
const scmResource = resolveGitResource(uri);
@ -228,12 +227,93 @@ export class CommandCenter {
return;
}
return await this.model.stage(resource);
return await this.model.add(resource);
}
@command('git.stageAll')
async stageAll(): Promise<void> {
return await this.model.stage();
return await this.model.add();
}
@command('git.stageSelectedRanges')
async stageSelectedRanges(): Promise<void> {
const textEditor = window.activeTextEditor;
if (!textEditor) {
return;
}
const modifiedDocument = textEditor.document;
const modifiedUri = modifiedDocument.uri;
if (modifiedUri.scheme !== 'file') {
return;
}
const originalUri = modifiedUri.with({ scheme: 'git', query: '~' });
const originalDocument = await workspace.openTextDocument(originalUri);
const diffs = await computeDiff(originalDocument, modifiedDocument);
const selections = textEditor.selections;
const selectedDiffs = diffs.filter(diff => {
const modifiedRange = diff.modifiedEndLineNumber === 0
? new Range(modifiedDocument.lineAt(diff.modifiedStartLineNumber - 1).range.end, modifiedDocument.lineAt(diff.modifiedStartLineNumber).range.start)
: new Range(modifiedDocument.lineAt(diff.modifiedStartLineNumber - 1).range.start, modifiedDocument.lineAt(diff.modifiedEndLineNumber - 1).range.end);
return selections.some(selection => !!selection.intersection(modifiedRange));
});
if (!selectedDiffs.length) {
return;
}
const result = staging.applyChanges(originalDocument, modifiedDocument, selectedDiffs);
await this.model.stage(modifiedUri, result);
}
@command('git.revertSelectedRanges')
async revertSelectedRanges(): Promise<void> {
const textEditor = window.activeTextEditor;
if (!textEditor) {
return;
}
const modifiedDocument = textEditor.document;
const modifiedUri = modifiedDocument.uri;
if (modifiedUri.scheme !== 'file') {
return;
}
const originalUri = modifiedUri.with({ scheme: 'git', query: '~' });
const originalDocument = await workspace.openTextDocument(originalUri);
const diffs = await computeDiff(originalDocument, modifiedDocument);
const selections = textEditor.selections;
const selectedDiffs = diffs.filter(diff => {
const modifiedRange = diff.modifiedEndLineNumber === 0
? new Range(modifiedDocument.lineAt(diff.modifiedStartLineNumber - 1).range.end, modifiedDocument.lineAt(diff.modifiedStartLineNumber).range.start)
: new Range(modifiedDocument.lineAt(diff.modifiedStartLineNumber - 1).range.start, modifiedDocument.lineAt(diff.modifiedEndLineNumber - 1).range.end);
return selections.every(selection => !selection.intersection(modifiedRange));
});
if (selectedDiffs.length === diffs.length) {
return;
}
const basename = path.basename(modifiedUri.fsPath);
const message = localize('confirm revert', "Are you sure you want to revert the selected changes in {0}?", basename);
const yes = localize('revert', "Revert Changes");
const pick = await window.showWarningMessage(message, { modal: true }, yes);
if (pick !== yes) {
return;
}
const result = staging.applyChanges(originalDocument, modifiedDocument, selectedDiffs);
const edit = new WorkspaceEdit();
edit.replace(modifiedUri, new Range(new Position(0, 0), modifiedDocument.lineAt(modifiedDocument.lineCount - 1).range.end), result);
workspace.applyEdit(edit);
}
@command('git.unstage')
@ -244,12 +324,54 @@ export class CommandCenter {
return;
}
return await this.model.unstage(resource);
return await this.model.revertFiles(resource);
}
@command('git.unstageAll')
async unstageAll(): Promise<void> {
return await this.model.unstage();
return await this.model.revertFiles();
}
@command('git.unstageSelectedRanges')
async unstageSelectedRanges(): Promise<void> {
const textEditor = window.activeTextEditor;
if (!textEditor) {
return;
}
const modifiedDocument = textEditor.document;
const modifiedUri = modifiedDocument.uri;
if (modifiedUri.scheme !== 'git' || modifiedUri.query !== '') {
return;
}
const originalUri = modifiedUri.with({ scheme: 'git', query: 'HEAD' });
const originalDocument = await workspace.openTextDocument(originalUri);
const diffs = await computeDiff(originalDocument, modifiedDocument);
const selections = textEditor.selections;
const selectedDiffs = diffs.filter(diff => {
const modifiedRange = diff.modifiedEndLineNumber === 0
? new Range(diff.modifiedStartLineNumber - 1, 0, diff.modifiedStartLineNumber - 1, 0)
: new Range(modifiedDocument.lineAt(diff.modifiedStartLineNumber - 1).range.start, modifiedDocument.lineAt(diff.modifiedEndLineNumber - 1).range.end);
return selections.some(selection => !!selection.intersection(modifiedRange));
});
if (!selectedDiffs.length) {
return;
}
const invertedDiffs = selectedDiffs.map(c => ({
modifiedStartLineNumber: c.originalStartLineNumber,
modifiedEndLineNumber: c.originalEndLineNumber,
originalStartLineNumber: c.modifiedStartLineNumber,
originalEndLineNumber: c.modifiedEndLineNumber
}));
const result = staging.applyChanges(modifiedDocument, originalDocument, invertedDiffs);
await this.model.stage(modifiedUri, result);
}
@command('git.clean')

View file

@ -6,7 +6,6 @@
'use strict';
import { workspace, window, languages, Disposable, Uri, HoverProvider, Hover, TextEditor, Position, TextDocument, Range, TextEditorDecorationType, WorkspaceEdit } from 'vscode';
import { Model } from './model';
import { filterEvent } from './util';
import * as nls from 'vscode-nls';
@ -22,7 +21,7 @@ interface Diagnostic {
message: string;
}
// TODO@Joao: hover dissapears if editor is scrolled
// TODO@Joao: hover disappears if editor is scrolled
export class CommitController implements HoverProvider {
private visibleTextEditorsDisposable: Disposable;
@ -53,7 +52,7 @@ export class CommitController implements HoverProvider {
workspace.applyEdit(edit);
}
constructor(private model: Model) {
constructor() {
this.visibleTextEditorsDisposable = window.onDidChangeVisibleTextEditors(this.onVisibleTextEditors, this);
this.onVisibleTextEditors(window.visibleTextEditors);

View file

@ -6,8 +6,8 @@
'use strict';
import { workspace, Uri, Disposable, Event, EventEmitter } from 'vscode';
import * as path from 'path';
import { Git } from './git';
import { debounce } from './decorators';
import { Model } from './model';
export class GitContentProvider {
@ -16,37 +16,38 @@ export class GitContentProvider {
private onDidChangeEmitter = new EventEmitter<Uri>();
get onDidChange(): Event<Uri> { return this.onDidChangeEmitter.event; }
private uris = new Set<Uri>();
private uris: { [uri: string]: Uri } = Object.create(null) as { [uri: string]: Uri };
constructor(private git: Git, private rootPath: string, onGitChange: Event<Uri>) {
constructor(private model: Model) {
this.disposables.push(
onGitChange(this.fireChangeEvents, this),
model.onDidChangeRepository(this.fireChangeEvents, this),
workspace.registerTextDocumentContentProvider('git', this)
);
}
@debounce(300)
private fireChangeEvents(): void {
for (let uri of this.uris) {
this.onDidChangeEmitter.fire(uri);
}
Object.keys(this.uris).forEach(key => {
this.onDidChangeEmitter.fire(this.uris[key]);
});
}
async provideTextDocumentContent(uri: Uri): Promise<string> {
const treeish = uri.query;
const relativePath = path.relative(this.rootPath, uri.fsPath).replace(/\\/g, '/');
let ref = uri.query;
if (ref === '~') {
const fileUri = uri.with({ scheme: 'file', query: '' });
const uriString = fileUri.toString();
const [indexStatus] = this.model.indexGroup.resources.filter(r => r.original.toString() === uriString);
ref = indexStatus ? '' : 'HEAD';
}
try {
const result = await this.git.exec(this.rootPath, ['show', `${treeish}:${relativePath}`]);
if (result.exitCode !== 0) {
this.uris.delete(uri);
return '';
}
this.uris.add(uri);
return result.stdout;
const result = await this.model.show(ref, uri);
this.uris[uri.toString()] = uri;
return result;
} catch (err) {
this.uris.delete(uri);
delete this.uris[uri.toString()];
return '';
}
}

View file

@ -289,6 +289,11 @@ export class Git {
return new Repository(this, repository, env);
}
async getRepositoryRoot(path: string): Promise<string> {
const result = await this.exec(path, ['rev-parse', '--show-toplevel']);
return result.stdout.trim();
}
async exec(cwd: string, args: string[], options: any = {}): Promise<IExecutionResult> {
options = assign({ cwd }, options || {});
return await this._exec(args, options);
@ -380,7 +385,7 @@ export class Repository {
constructor(
private _git: Git,
private repository: string,
private repositoryRoot: string,
private env: any = {}
) { }
@ -388,8 +393,8 @@ export class Repository {
return this._git;
}
get path(): string {
return this.repository;
get root(): string {
return this.repositoryRoot;
}
// TODO@Joao: rename to exec
@ -397,14 +402,14 @@ export class Repository {
options.env = assign({}, options.env || {});
options.env = assign(options.env, this.env);
return await this.git.exec(this.repository, args, options);
return await this.git.exec(this.repositoryRoot, args, options);
}
stream(args: string[], options: any = {}): cp.ChildProcess {
options.env = assign({}, options.env || {});
options.env = assign(options.env, this.env);
return this.git.stream(this.repository, args, options);
return this.git.stream(this.repositoryRoot, args, options);
}
spawn(args: string[], options: any = {}): cp.ChildProcess {
@ -709,11 +714,6 @@ export class Repository {
await this.push();
}
async getRoot(): Promise<string> {
const result = await this.run(['rev-parse', '--show-toplevel']);
return result.stdout.trim();
}
async getStatus(): Promise<IFileStatus[]> {
const executionResult = await this.run(['status', '-z', '-u']);
const status = executionResult.stdout;
@ -861,7 +861,7 @@ export class Repository {
.replace(/^~([^\/]*)\//, (_, user) => `${user ? path.join(path.dirname(homedir), user) : homedir}/`);
if (!path.isAbsolute(templatePath)) {
templatePath = path.join(this.repository, templatePath);
templatePath = path.join(this.repositoryRoot, templatePath);
}
const raw = await readfile(templatePath, 'utf8');

View file

@ -5,13 +5,12 @@
'use strict';
import { ExtensionContext, workspace, window, Disposable } from 'vscode';
import { ExtensionContext, workspace, window, Disposable, commands, Uri } from 'vscode';
import { findGit, Git } from './git';
import { Model } from './model';
import { GitSCMProvider } from './scmProvider';
import { CommandCenter } from './commands';
import { CheckoutStatusBar, SyncStatusBar } from './statusbar';
import { filterEvent, anyEvent } from './util';
import { GitContentProvider } from './contentProvider';
import { AutoFetcher } from './autofetch';
import { MergeDecorator } from './merge';
@ -34,24 +33,18 @@ async function init(disposables: Disposable[]): Promise<void> {
return;
}
const fsWatcher = workspace.createFileSystemWatcher('**');
const onWorkspaceChange = anyEvent(fsWatcher.onDidChange, fsWatcher.onDidCreate, fsWatcher.onDidDelete);
const onGitChange = filterEvent(onWorkspaceChange, uri => /^\.git\//.test(workspace.asRelativePath(uri)));
const pathHint = workspace.getConfiguration('git').get<string>('path');
const info = await findGit(pathHint);
const git = new Git({ gitPath: info.path, version: info.version });
const repository = git.open(rootPath);
const repositoryRoot = await repository.getRoot();
const model = new Model(repositoryRoot, repository, onWorkspaceChange);
const model = new Model(git, rootPath);
outputChannel.appendLine(localize('using git', "Using git {0} from {1}", info.version, info.path));
git.onOutput(str => outputChannel.append(str), null, disposables);
const commitHandler = new CommitController(model);
const commitHandler = new CommitController();
const commandCenter = new CommandCenter(model, outputChannel);
const provider = new GitSCMProvider(model, commandCenter);
const contentProvider = new GitContentProvider(git, rootPath, onGitChange);
const contentProvider = new GitContentProvider(model);
const checkoutStatusBar = new CheckoutStatusBar(model);
const syncStatusBar = new SyncStatusBar(model);
const autoFetcher = new AutoFetcher(model);
@ -62,12 +55,21 @@ async function init(disposables: Disposable[]): Promise<void> {
commandCenter,
provider,
contentProvider,
fsWatcher,
checkoutStatusBar,
syncStatusBar,
autoFetcher,
mergeDecorator
mergeDecorator,
model
);
if (/^[01]/.test(info.version)) {
const update = localize('updateGit', "Update Git");
const choice = await window.showWarningMessage(localize('git20', "You seem to have git {0} installed. Code works best with git >= 2", info.version), update);
if (choice === update) {
commands.executeCommand('vscode.open', Uri.parse('https://git-scm.com/'));
}
}
}
export function activate(context: ExtensionContext): any {

View file

@ -6,8 +6,8 @@
'use strict';
import { Uri, EventEmitter, Event, SCMResource, SCMResourceDecorations, SCMResourceGroup, Disposable, window, workspace } from 'vscode';
import { Repository, Ref, Branch, Remote, PushOptions, Commit } from './git';
import { anyEvent, eventToPromise, filterEvent, mapEvent } from './util';
import { Git, Repository, Ref, Branch, Remote, PushOptions, Commit, GitErrorCodes, GitError } from './git';
import { anyEvent, eventToPromise, filterEvent, mapEvent, EmptyDisposable, combinedDisposable, dispose } from './util';
import { memoize, throttle, debounce } from './decorators';
import { watch } from './watch';
import * as path from 'path';
@ -20,6 +20,12 @@ function getIconUri(iconName: string, theme: string): Uri {
return Uri.file(path.join(iconsRootPath, theme, `${iconName}.svg`));
}
export enum State {
Uninitialized,
Idle,
NotAGitRepository
}
export enum Status {
INDEX_MODIFIED,
INDEX_ADDED,
@ -139,7 +145,7 @@ export class MergeGroup extends ResourceGroup {
static readonly ID = 'merge';
constructor(resources: Resource[]) {
constructor(resources: Resource[] = []) {
super(MergeGroup.ID, localize('merge changes', "Merge Changes"), resources);
}
}
@ -148,7 +154,7 @@ export class IndexGroup extends ResourceGroup {
static readonly ID = 'index';
constructor(resources: Resource[]) {
constructor(resources: Resource[] = []) {
super(IndexGroup.ID, localize('staged changes', "Staged Changes"), resources);
}
}
@ -157,15 +163,15 @@ export class WorkingTreeGroup extends ResourceGroup {
static readonly ID = 'workingTree';
constructor(resources: Resource[]) {
constructor(resources: Resource[] = []) {
super(WorkingTreeGroup.ID, localize('changes', "Changes"), resources);
}
}
export enum Operation {
Status = 1 << 0,
Stage = 1 << 1,
Unstage = 1 << 2,
Add = 1 << 1,
RevertFiles = 1 << 2,
Commit = 1 << 3,
Clean = 1 << 4,
Branch = 1 << 5,
@ -175,6 +181,9 @@ export enum Operation {
Pull = 1 << 9,
Push = 1 << 10,
Sync = 1 << 11,
Init = 1 << 12,
Show = 1 << 13,
Stage = 1 << 13
}
export interface Operations {
@ -211,10 +220,21 @@ export interface CommitOptions {
signoff?: boolean;
}
export class Model {
export class Model implements Disposable {
private _onDidChange = new EventEmitter<SCMResourceGroup[]>();
readonly onDidChange: Event<SCMResourceGroup[]> = this._onDidChange.event;
private _onDidChangeRepository = new EventEmitter<Uri>();
readonly onDidChangeRepository: Event<Uri> = this._onDidChangeRepository.event;
private _onDidChangeState = new EventEmitter<State>();
readonly onDidChangeState: Event<State> = this._onDidChangeState.event;
private _onDidChangeResources = new EventEmitter<SCMResourceGroup[]>();
readonly onDidChangeResources: Event<SCMResourceGroup[]> = this._onDidChangeResources.event;
@memoize
get onDidChange(): Event<void> {
return anyEvent<any>(this.onDidChangeState, this.onDidChangeResources);
}
private _onRunOperation = new EventEmitter<Operation>();
readonly onRunOperation: Event<Operation> = this._onRunOperation.event;
@ -252,38 +272,6 @@ export class Model {
return result;
}
private _operations = new OperationsImpl();
get operations(): Operations { return this._operations; }
private disposables: Disposable[] = [];
constructor(
private _repositoryRoot: string,
private repository: Repository,
onWorkspaceChange: Event<Uri>
) {
/* We use the native Node `watch` for faster, non debounced events.
* That way we hopefully get the events during the operations we're
* performing, thus sparing useless `git status` calls to refresh
* the model's state.
*/
const gitPath = path.join(_repositoryRoot, '.git');
const { event, disposable } = watch(gitPath);
const onGitChange = mapEvent(event, ({ filename }) => Uri.file(path.join(gitPath, filename)));
const onRelevantGitChange = filterEvent(onGitChange, uri => !/\/\.git\/index\.lock$/.test(uri.fsPath));
onRelevantGitChange(this.onFSChange, this, this.disposables);
this.disposables.push(disposable);
const onNonGitChange = filterEvent(onWorkspaceChange, uri => !/\/\.git\//.test(uri.fsPath));
onNonGitChange(this.onFSChange, this, this.disposables);
this.status();
}
get repositoryRoot(): string {
return this._repositoryRoot;
}
private _HEAD: Branch | undefined;
get HEAD(): Branch | undefined {
return this._HEAD;
@ -299,19 +287,70 @@ export class Model {
return this._remotes;
}
private _operations = new OperationsImpl();
get operations(): Operations { return this._operations; }
private repository: Repository;
private _state = State.Uninitialized;
get state(): State { return this._state; }
set state(state: State) {
this._state = state;
this._onDidChangeState.fire(state);
this._HEAD = undefined;
this._refs = [];
this._remotes = [];
this._mergeGroup = new MergeGroup();
this._indexGroup = new IndexGroup();
this._workingTreeGroup = new WorkingTreeGroup();
this._onDidChangeResources.fire(this.resources);
}
private onWorkspaceChange: Event<Uri>;
private repositoryDisposable: Disposable = EmptyDisposable;
private disposables: Disposable[] = [];
constructor(
private git: Git,
private rootPath: string,
) {
const fsWatcher = workspace.createFileSystemWatcher('**');
this.onWorkspaceChange = anyEvent(fsWatcher.onDidChange, fsWatcher.onDidCreate, fsWatcher.onDidDelete);
this.disposables.push(fsWatcher);
this.status();
}
@throttle
async init(): Promise<void> {
if (this.state !== State.NotAGitRepository) {
return;
}
await this.repository.init();
await this.status();
}
@throttle
async status(): Promise<void> {
await this.run(Operation.Status);
}
@throttle
async stage(...resources: Resource[]): Promise<void> {
await this.run(Operation.Stage, () => this.repository.add(resources.map(r => r.uri.fsPath)));
async add(...resources: Resource[]): Promise<void> {
await this.run(Operation.Add, () => this.repository.add(resources.map(r => r.uri.fsPath)));
}
@throttle
async unstage(...resources: Resource[]): Promise<void> {
await this.run(Operation.Unstage, () => this.repository.revertFiles('HEAD', resources.map(r => r.uri.fsPath)));
async stage(uri: Uri, contents: string): Promise<void> {
const relativePath = path.relative(this.repository.root, uri.fsPath).replace(/\\/g, '/');
await this.run(Operation.Stage, () => this.repository.stage(relativePath, contents));
}
@throttle
async revertFiles(...resources: Resource[]): Promise<void> {
await this.run(Operation.RevertFiles, () => this.repository.revertFiles('HEAD', resources.map(r => r.uri.fsPath)));
}
@throttle
@ -398,14 +437,39 @@ export class Model {
await this.run(Operation.Sync, () => this.repository.sync());
}
private async run(operation: Operation, fn: () => Promise<void> = () => Promise.resolve()): Promise<void> {
async show(ref: string, uri: Uri): Promise<string> {
return await this.run(Operation.Show, async () => {
const relativePath = path.relative(this.repository.root, uri.fsPath).replace(/\\/g, '/');
const result = await this.repository.git.exec(this.repository.root, ['show', `${ref}:${relativePath}`]);
if (result.exitCode !== 0) {
throw new GitError({
message: localize('cantshow', "Could not show object"),
exitCode: result.exitCode
});
}
return result.stdout;
});
}
private async run<T>(operation: Operation, runOperation: () => Promise<T> = () => Promise.resolve<any>(null)): Promise<T> {
return window.withScmProgress(async () => {
this._operations = this._operations.start(operation);
this._onRunOperation.fire(operation);
try {
await fn();
await this.assertIdleState();
const result = await runOperation();
await this.update();
return result;
} catch (err) {
if (err.gitErrorCode === GitErrorCodes.NotAGitRepository) {
this.repositoryDisposable.dispose();
this.state = State.NotAGitRepository;
}
throw err;
} finally {
this._operations = this._operations.end(operation);
this._onDidRunOperation.fire(operation);
@ -413,6 +477,38 @@ export class Model {
});
}
/* We use the native Node `watch` for faster, non debounced events.
* That way we hopefully get the events during the operations we're
* performing, thus sparing useless `git status` calls to refresh
* the model's state.
*/
private async assertIdleState(): Promise<void> {
if (this.state === State.Idle) {
return;
}
this.repositoryDisposable.dispose();
const disposables: Disposable[] = [];
const repositoryRoot = await this.git.getRepositoryRoot(this.rootPath);
this.repository = this.git.open(repositoryRoot);
const dotGitPath = path.join(repositoryRoot, '.git');
const { event: onRawGitChange, disposable: watcher } = watch(dotGitPath);
disposables.push(watcher);
const onGitChange = mapEvent(onRawGitChange, ({ filename }) => Uri.file(path.join(dotGitPath, filename)));
const onRelevantGitChange = filterEvent(onGitChange, uri => !/\/\.git\/index\.lock$/.test(uri.fsPath));
onRelevantGitChange(this.onFSChange, this, disposables);
onRelevantGitChange(this._onDidChangeRepository.fire, this._onDidChangeRepository, disposables);
const onNonGitChange = filterEvent(this.onWorkspaceChange, uri => !/\/\.git\//.test(uri.fsPath));
onNonGitChange(this.onFSChange, this, disposables);
this.repositoryDisposable = combinedDisposable(disposables);
this.state = State.Idle;
}
@throttle
private async update(): Promise<void> {
const status = await this.repository.getStatus();
@ -443,8 +539,8 @@ export class Model {
const merge: Resource[] = [];
status.forEach(raw => {
const uri = Uri.file(path.join(this.repositoryRoot, raw.path));
const renameUri = raw.rename ? Uri.file(path.join(this.repositoryRoot, raw.rename)) : undefined;
const uri = Uri.file(path.join(this.repository.root, raw.path));
const renameUri = raw.rename ? Uri.file(path.join(this.repository.root, raw.rename)) : undefined;
switch (raw.x + raw.y) {
case '??': return workingTree.push(new Resource(uri, Status.UNTRACKED));
@ -477,8 +573,7 @@ export class Model {
this._mergeGroup = new MergeGroup(merge);
this._indexGroup = new IndexGroup(index);
this._workingTreeGroup = new WorkingTreeGroup(workingTree);
this._onDidChange.fire(this.resources);
this._onDidChangeResources.fire(this.resources);
}
private onFSChange(uri: Uri): void {
@ -513,4 +608,9 @@ export class Model {
await eventToPromise(this.onDidRunOperation);
}
}
dispose(): void {
this.repositoryDisposable.dispose();
this.disposables = dispose(this.disposables);
}
}

View file

@ -6,17 +6,31 @@
'use strict';
import { scm, Uri, Disposable, SCMProvider, SCMResourceGroup, Event, ProviderResult, workspace } from 'vscode';
import { Model, Resource, ResourceGroup } from './model';
import { Model, Resource, ResourceGroup, State } from './model';
import { CommandCenter } from './commands';
import { mapEvent } from './util';
export class GitSCMProvider implements SCMProvider {
private disposables: Disposable[] = [];
get resources(): SCMResourceGroup[] { return this.model.resources; }
get onDidChange(): Event<SCMResourceGroup[]> { return this.model.onDidChange; }
get onDidChange(): Event<SCMResourceGroup[]> {
return mapEvent(this.model.onDidChange, () => this.model.resources);
}
get label(): string { return 'Git'; }
get state(): string {
switch (this.model.state) {
case State.Uninitialized: return 'uninitialized';
case State.Idle: return 'idle';
case State.NotAGitRepository: return 'norepo';
default: return '';
}
}
get count(): number {
const countBadge = workspace.getConfiguration('git').get<string>('countBadge');

View file

@ -0,0 +1,38 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
'use strict';
import { TextDocument, Range, LineChange } from 'vscode';
export function applyChanges(original: TextDocument, modified: TextDocument, diffs: LineChange[]): string {
const result: string[] = [];
let currentLine = 0;
for (let diff of diffs) {
const isInsertion = diff.originalEndLineNumber === 0;
const isDeletion = diff.modifiedEndLineNumber === 0;
result.push(original.getText(new Range(currentLine, 0, isInsertion ? diff.originalStartLineNumber : diff.originalStartLineNumber - 1, 0)));
if (!isDeletion) {
let fromLine = diff.modifiedStartLineNumber - 1;
let fromCharacter = 0;
if (isInsertion && diff.originalStartLineNumber === original.lineCount) {
fromLine = original.lineCount - 1;
fromCharacter = original.lineAt(fromLine).range.end.character;
}
result.push(modified.getText(new Range(fromLine, fromCharacter, diff.modifiedEndLineNumber, 0)));
}
currentLine = isInsertion ? diff.originalStartLineNumber : diff.originalEndLineNumber;
}
result.push(original.getText(new Range(currentLine, 0, original.lineCount, 0)));
return result.join('');
}

View file

@ -30,9 +30,7 @@ export class CheckoutStatusBar {
const HEAD = this.model.HEAD;
if (!HEAD) {
this.raw.command = '';
this.raw.color = 'rgb(100, 100, 100)';
this.raw.text = 'unknown';
this.raw.hide();
return;
}
@ -48,6 +46,7 @@ export class CheckoutStatusBar {
(this.model.workingTreeGroup.resources.length > 0 ? '*' : '') +
(this.model.indexGroup.resources.length > 0 ? '+' : '') +
(this.model.mergeGroup.resources.length > 0 ? '!' : '');
this.raw.show();
}
dispose(): void {

View file

@ -28,6 +28,8 @@ export function combinedDisposable(disposables: IDisposable[]): IDisposable {
return toDisposable(() => dispose(disposables));
}
export const EmptyDisposable = toDisposable(() => null);
export function mapEvent<I, O>(event: Event<I>, map: (i: I) => O): Event<O> {
return (listener, thisArgs = null, disposables?) => event(i => listener.call(thisArgs, map(i)), null, disposables);
}

View file

@ -57,7 +57,7 @@ export function activate(context: ExtensionContext) {
};
// Create the language client and start the client.
let client = new LanguageClient('html', localize('htmlserver.name', 'HTML Language Server'), serverOptions, clientOptions, true);
let client = new LanguageClient('html', localize('htmlserver.name', 'HTML Language Server'), serverOptions, clientOptions);
let disposable = client.start();
context.subscriptions.push(disposable);
client.onReady().then(() => {

View file

@ -13,24 +13,24 @@
"resolved": "https://registry.npmjs.org/vscode-extension-telemetry/-/vscode-extension-telemetry-0.0.5.tgz"
},
"vscode-jsonrpc": {
"version": "3.0.2-beta.5",
"from": "vscode-jsonrpc@>=3.0.2-beta.5 <4.0.0",
"resolved": "https://registry.npmjs.org/vscode-jsonrpc/-/vscode-jsonrpc-3.0.2-beta.5.tgz"
"version": "3.1.0-alpha.1",
"from": "vscode-jsonrpc@>=3.1.0-alpha.1 <4.0.0",
"resolved": "https://registry.npmjs.org/vscode-jsonrpc/-/vscode-jsonrpc-3.1.0-alpha.1.tgz"
},
"vscode-languageclient": {
"version": "3.0.2-beta.5",
"version": "3.1.0-alpha.1",
"from": "vscode-languageclient@next",
"resolved": "https://registry.npmjs.org/vscode-languageclient/-/vscode-languageclient-3.0.2-beta.5.tgz"
"resolved": "https://registry.npmjs.org/vscode-languageclient/-/vscode-languageclient-3.1.0-alpha.1.tgz"
},
"vscode-languageserver-types": {
"version": "3.0.2-beta.5",
"from": "vscode-languageserver-types@next",
"resolved": "https://registry.npmjs.org/vscode-languageserver-types/-/vscode-languageserver-types-3.0.2-beta.5.tgz"
"version": "3.0.3",
"from": "vscode-languageserver-types@>=3.0.2-beta.5 <4.0.0",
"resolved": "https://registry.npmjs.org/vscode-languageserver-types/-/vscode-languageserver-types-3.0.3.tgz"
},
"vscode-nls": {
"version": "2.0.1",
"from": "vscode-nls@>=2.0.1 <3.0.0",
"resolved": "https://registry.npmjs.org/vscode-nls/-/vscode-nls-2.0.1.tgz"
"version": "2.0.2",
"from": "vscode-nls@>=2.0.2 <3.0.0",
"resolved": "https://registry.npmjs.org/vscode-nls/-/vscode-nls-2.0.2.tgz"
},
"winreg": {
"version": "0.0.13",

View file

@ -191,9 +191,9 @@
},
"dependencies": {
"vscode-extension-telemetry": "0.0.5",
"vscode-languageclient": "^3.0.2-beta.5",
"vscode-languageserver-types": "^3.0.2-beta.5",
"vscode-nls": "^2.0.1"
"vscode-languageclient": "^3.1.0-alpha.1",
"vscode-languageserver-types": "^3.0.3",
"vscode-nls": "^2.0.2"
},
"devDependencies": {
"@types/node": "^6.0.51",

View file

@ -3,34 +3,34 @@
"version": "1.0.0",
"dependencies": {
"vscode-css-languageservice": {
"version": "2.0.0-next.8",
"version": "2.0.0",
"from": "vscode-css-languageservice@next",
"resolved": "https://registry.npmjs.org/vscode-css-languageservice/-/vscode-css-languageservice-2.0.0-next.8.tgz"
"resolved": "https://registry.npmjs.org/vscode-css-languageservice/-/vscode-css-languageservice-2.0.0.tgz"
},
"vscode-html-languageservice": {
"version": "2.0.0-next.6",
"version": "2.0.0",
"from": "vscode-html-languageservice@next",
"resolved": "https://registry.npmjs.org/vscode-html-languageservice/-/vscode-html-languageservice-2.0.0-next.6.tgz"
"resolved": "https://registry.npmjs.org/vscode-html-languageservice/-/vscode-html-languageservice-2.0.0.tgz"
},
"vscode-jsonrpc": {
"version": "3.0.2-beta.5",
"from": "vscode-jsonrpc@>=3.0.2-beta.5 <4.0.0",
"resolved": "https://registry.npmjs.org/vscode-jsonrpc/-/vscode-jsonrpc-3.0.2-beta.5.tgz"
"version": "3.1.0-alpha.1",
"from": "vscode-jsonrpc@>=3.1.0-alpha.1 <4.0.0",
"resolved": "https://registry.npmjs.org/vscode-jsonrpc/-/vscode-jsonrpc-3.1.0-alpha.1.tgz"
},
"vscode-languageserver": {
"version": "3.0.2-beta.5",
"version": "3.1.0-alpha.1",
"from": "vscode-languageserver@next",
"resolved": "https://registry.npmjs.org/vscode-languageserver/-/vscode-languageserver-3.0.2-beta.5.tgz"
"resolved": "https://registry.npmjs.org/vscode-languageserver/-/vscode-languageserver-3.1.0-alpha.1.tgz"
},
"vscode-languageserver-types": {
"version": "3.0.2-beta.5",
"from": "vscode-languageserver-types@>=3.0.2-beta.5 <4.0.0",
"resolved": "https://registry.npmjs.org/vscode-languageserver-types/-/vscode-languageserver-types-3.0.2-beta.5.tgz"
"version": "3.0.3",
"from": "vscode-languageserver-types@>=3.0.3 <4.0.0",
"resolved": "https://registry.npmjs.org/vscode-languageserver-types/-/vscode-languageserver-types-3.0.3.tgz"
},
"vscode-nls": {
"version": "2.0.1",
"version": "2.0.2",
"from": "vscode-nls@>=2.0.1 <3.0.0",
"resolved": "https://registry.npmjs.org/vscode-nls/-/vscode-nls-2.0.1.tgz"
"resolved": "https://registry.npmjs.org/vscode-nls/-/vscode-nls-2.0.2.tgz"
},
"vscode-uri": {
"version": "1.0.0",
@ -38,4 +38,4 @@
"resolved": "https://registry.npmjs.org/vscode-uri/-/vscode-uri-1.0.0.tgz"
}
}
}
}

View file

@ -8,10 +8,10 @@
"node": "*"
},
"dependencies": {
"vscode-css-languageservice": "^2.0.0-next.8",
"vscode-html-languageservice": "^2.0.0-next.6",
"vscode-languageserver": "^3.0.2-beta.5",
"vscode-nls": "^2.0.1",
"vscode-css-languageservice": "^2.0.0",
"vscode-html-languageservice": "^2.0.0",
"vscode-languageserver": "^3.1.0-alpha.1",
"vscode-nls": "^2.0.2",
"vscode-uri": "^1.0.0"
},
"devDependencies": {

View file

@ -21,7 +21,7 @@ const JS_WORD_REGEX = /(-?\d*\.\d\w*)|([^\`\~\!\@\#\%\^\&\*\(\)\-\=\+\[\{\]\}\\\
export function getJavascriptMode(documentRegions: LanguageModelCache<HTMLDocumentRegions>): LanguageMode {
let jsDocuments = getLanguageModelCache<TextDocument>(10, 60, document => documentRegions.get(document).getEmbeddedDocument('javascript'));
let compilerOptions: ts.CompilerOptions = { allowNonTsExtensions: true, allowJs: true, target: ts.ScriptTarget.Latest, moduleResolution: ts.ModuleResolutionKind.Classic };
let compilerOptions: ts.CompilerOptions = { allowNonTsExtensions: true, allowJs: true, lib: ['lib.es6.d.ts'], target: ts.ScriptTarget.Latest, moduleResolution: ts.ModuleResolutionKind.Classic };
let currentTextDocument: TextDocument;
let scriptFileVersion: number = 0;
function updateCurrentTextDocument(doc: TextDocument) {

View file

@ -13,19 +13,19 @@
"resolved": "https://registry.npmjs.org/vscode-extension-telemetry/-/vscode-extension-telemetry-0.0.5.tgz"
},
"vscode-jsonrpc": {
"version": "3.0.2-beta.5",
"from": "vscode-jsonrpc@>=3.0.2-beta.5 <4.0.0",
"resolved": "https://registry.npmjs.org/vscode-jsonrpc/-/vscode-jsonrpc-3.0.2-beta.5.tgz"
"version": "3.1.0-alpha.1",
"from": "vscode-jsonrpc@>=3.1.0-alpha.1 <4.0.0",
"resolved": "https://registry.npmjs.org/vscode-jsonrpc/-/vscode-jsonrpc-3.1.0-alpha.1.tgz"
},
"vscode-languageclient": {
"version": "3.0.2-beta.5",
"version": "3.1.0-alpha.1",
"from": "vscode-languageclient@next",
"resolved": "https://registry.npmjs.org/vscode-languageclient/-/vscode-languageclient-3.0.2-beta.5.tgz"
"resolved": "https://registry.npmjs.org/vscode-languageclient/-/vscode-languageclient-3.1.0-alpha.1.tgz"
},
"vscode-languageserver-types": {
"version": "3.0.2-beta.5",
"from": "vscode-languageserver-types@>=3.0.2-beta.5 <4.0.0",
"resolved": "https://registry.npmjs.org/vscode-languageserver-types/-/vscode-languageserver-types-3.0.2-beta.5.tgz"
"version": "3.0.3",
"from": "vscode-languageserver-types@>=3.0.3 <4.0.0",
"resolved": "https://registry.npmjs.org/vscode-languageserver-types/-/vscode-languageserver-types-3.0.3.tgz"
},
"vscode-nls": {
"version": "2.0.2",

View file

@ -113,7 +113,7 @@
},
"dependencies": {
"vscode-extension-telemetry": "^0.0.5",
"vscode-languageclient": "^3.0.2-beta.5",
"vscode-languageclient": "^3.1.0-alpha.1",
"vscode-nls": "^2.0.2"
},
"devDependencies": {

View file

@ -29,7 +29,8 @@
},
"jsonc-parser": {
"version": "0.3.1",
"from": "jsonc-parser@>=0.3.0 <0.4.0"
"from": "jsonc-parser@0.3.1",
"resolved": "https://registry.npmjs.org/jsonc-parser/-/jsonc-parser-0.3.1.tgz"
},
"ms": {
"version": "0.7.2",
@ -42,24 +43,24 @@
"resolved": "https://registry.npmjs.org/request-light/-/request-light-0.2.0.tgz"
},
"vscode-json-languageservice": {
"version": "2.0.0-next.12",
"version": "2.0.0",
"from": "vscode-json-languageservice@next",
"resolved": "https://registry.npmjs.org/vscode-json-languageservice/-/vscode-json-languageservice-2.0.0-next.12.tgz"
"resolved": "https://registry.npmjs.org/vscode-json-languageservice/-/vscode-json-languageservice-2.0.0.tgz"
},
"vscode-jsonrpc": {
"version": "3.0.2-beta.5",
"from": "vscode-jsonrpc@>=3.0.2-beta.5 <4.0.0",
"resolved": "https://registry.npmjs.org/vscode-jsonrpc/-/vscode-jsonrpc-3.0.2-beta.5.tgz"
"version": "3.1.0-alpha.1",
"from": "vscode-jsonrpc@>=3.1.0-alpha.1 <4.0.0",
"resolved": "https://registry.npmjs.org/vscode-jsonrpc/-/vscode-jsonrpc-3.1.0-alpha.1.tgz"
},
"vscode-languageserver": {
"version": "3.0.2-beta.5",
"version": "3.1.0-alpha.1",
"from": "vscode-languageserver@next",
"resolved": "https://registry.npmjs.org/vscode-languageserver/-/vscode-languageserver-3.0.2-beta.5.tgz"
"resolved": "https://registry.npmjs.org/vscode-languageserver/-/vscode-languageserver-3.1.0-alpha.1.tgz"
},
"vscode-languageserver-types": {
"version": "3.0.2-beta.5",
"from": "vscode-languageserver-types@>=3.0.2-beta.5 <4.0.0",
"resolved": "https://registry.npmjs.org/vscode-languageserver-types/-/vscode-languageserver-types-3.0.2-beta.5.tgz"
"version": "3.0.3",
"from": "vscode-languageserver-types@>=3.0.3 <4.0.0",
"resolved": "https://registry.npmjs.org/vscode-languageserver-types/-/vscode-languageserver-types-3.0.3.tgz"
},
"vscode-nls": {
"version": "2.0.2",

View file

@ -10,8 +10,8 @@
"dependencies": {
"jsonc-parser": "^0.3.1",
"request-light": "^0.2.0",
"vscode-json-languageservice": "^2.0.0-next.12",
"vscode-languageserver": "^3.0.2-beta.5",
"vscode-json-languageservice": "^2.0.0",
"vscode-languageserver": "^3.1.0-alpha.1",
"vscode-nls": "^2.0.2"
},
"devDependencies": {

View file

@ -17,7 +17,6 @@ import URI from './utils/uri';
import * as URL from 'url';
import Strings = require('./utils/strings');
import { JSONDocument, JSONSchema, LanguageSettings, getLanguageService } from 'vscode-json-languageservice';
import { ProjectJSONContribution } from './jsoncontributions/projectJSONContribution';
import { getLanguageModelCache } from './languageModelCache';
import * as nls from 'vscode-nls';
@ -119,9 +118,7 @@ let schemaRequestService = (uri: string): Thenable<string> => {
let languageService = getLanguageService({
schemaRequestService,
workspaceContext,
contributions: [
new ProjectJSONContribution()
]
contributions: []
});
// The settings interface describes the server relevant settings part

View file

@ -1,281 +0,0 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
'use strict';
import { MarkedString, CompletionItemKind, CompletionItem, InsertTextFormat } from 'vscode-languageserver';
import Strings = require('../utils/strings');
import { XHRResponse, getErrorStatusDescription, xhr } from 'request-light';
import { JSONWorkerContribution, JSONPath, CompletionsCollector } from 'vscode-json-languageservice';
import * as nls from 'vscode-nls';
const localize = nls.loadMessageBundle();
const FEED_INDEX_URL = 'https://api.nuget.org/v3/index.json';
const LIMIT = 30;
const RESOLVE_ID = 'ProjectJSONContribution-';
const CACHE_EXPIRY = 1000 * 60 * 5; // 5 minutes
interface NugetServices {
'SearchQueryService'?: string;
'SearchAutocompleteService'?: string;
'PackageBaseAddress/3.0.0'?: string;
[key: string]: string;
}
export class ProjectJSONContribution implements JSONWorkerContribution {
private cachedProjects: { [id: string]: { version: string, description: string, time: number } } = {};
private cacheSize: number = 0;
private nugetIndexPromise: Thenable<NugetServices>;
public constructor() {
}
private isProjectJSONFile(resource: string): boolean {
return Strings.endsWith(resource, '/project.json');
}
private completeWithCache(id: string, item: CompletionItem): boolean {
let entry = this.cachedProjects[id];
if (entry) {
if (new Date().getTime() - entry.time > CACHE_EXPIRY) {
delete this.cachedProjects[id];
this.cacheSize--;
return false;
}
let insertTextValue = item.insertText;
item.detail = entry.version;
item.documentation = entry.description;
item.insertText = insertTextValue.replace(/\$1/, '${1:' + entry.version + '}');
return true;
}
return false;
}
private addCached(id: string, version: string, description: string) {
this.cachedProjects[id] = { version, description, time: new Date().getTime() };
this.cacheSize++;
if (this.cacheSize > 50) {
let currentTime = new Date().getTime();
for (let id in this.cachedProjects) {
let entry = this.cachedProjects[id];
if (currentTime - entry.time > CACHE_EXPIRY) {
delete this.cachedProjects[id];
this.cacheSize--;
}
}
}
}
private getNugetIndex(): Thenable<NugetServices> {
if (!this.nugetIndexPromise) {
this.nugetIndexPromise = this.makeJSONRequest<any>(FEED_INDEX_URL).then(indexContent => {
let services: NugetServices = {};
if (indexContent && Array.isArray(indexContent.resources)) {
let resources = <any[]>indexContent.resources;
for (let i = resources.length - 1; i >= 0; i--) {
let type = resources[i]['@type'];
let id = resources[i]['@id'];
if (type && id) {
services[type] = id;
}
}
}
return services;
});
}
return this.nugetIndexPromise;
}
private getNugetService(serviceType: string): Thenable<string> {
return this.getNugetIndex().then(services => {
let serviceURL = services[serviceType];
if (!serviceURL) {
return Promise.reject<string>(localize('json.nugget.error.missingservice', 'NuGet index document is missing service {0}', serviceType));
}
return serviceURL;
});
}
public collectDefaultCompletions(resource: string, result: CompletionsCollector): Thenable<any> {
if (this.isProjectJSONFile(resource)) {
let insertText = JSON.stringify({
'version': '${1:1.0.0-*}',
'dependencies': {},
'frameworks': {
'net461': {},
'netcoreapp1.0': {}
}
}, null, '\t');
result.add({ kind: CompletionItemKind.Class, label: localize('json.project.default', 'Default project.json'), insertText, insertTextFormat: InsertTextFormat.Snippet, documentation: '' });
}
return null;
}
private makeJSONRequest<T>(url: string): Thenable<T> {
return xhr({
url: url
}).then(success => {
if (success.status === 200) {
try {
return <T>JSON.parse(success.responseText);
} catch (e) {
return Promise.reject<T>(localize('json.nugget.error.invalidformat', '{0} is not a valid JSON document', url));
}
}
return Promise.reject<T>(localize('json.nugget.error.indexaccess', 'Request to {0} failed: {1}', url, success.responseText));
}, (error: XHRResponse) => {
return Promise.reject<T>(localize('json.nugget.error.access', 'Request to {0} failed: {1}', url, getErrorStatusDescription(error.status)));
});
}
public collectPropertyCompletions(resource: string, location: JSONPath, currentWord: string, addValue: boolean, isLast: boolean, result: CompletionsCollector): Thenable<any> {
if (this.isProjectJSONFile(resource) && (matches(location, ['dependencies']) || matches(location, ['frameworks', '*', 'dependencies']) || matches(location, ['frameworks', '*', 'frameworkAssemblies']))) {
return this.getNugetService('SearchAutocompleteService').then(service => {
let queryUrl: string;
if (currentWord.length > 0) {
queryUrl = service + '?q=' + encodeURIComponent(currentWord) + '&take=' + LIMIT;
} else {
queryUrl = service + '?take=' + LIMIT;
}
return this.makeJSONRequest<any>(queryUrl).then(resultObj => {
if (Array.isArray(resultObj.data)) {
let results = <any[]>resultObj.data;
for (let i = 0; i < results.length; i++) {
let name = results[i];
let insertText = JSON.stringify(name);
if (addValue) {
insertText += ': "$1"';
if (!isLast) {
insertText += ',';
}
}
let item: CompletionItem = { kind: CompletionItemKind.Property, label: name, insertText: insertText, insertTextFormat: InsertTextFormat.Snippet, filterText: JSON.stringify(name) };
if (!this.completeWithCache(name, item)) {
item.data = RESOLVE_ID + name;
}
result.add(item);
}
if (results.length === LIMIT) {
result.setAsIncomplete();
}
}
}, error => {
result.error(error);
});
}, error => {
result.error(error);
});
};
return null;
}
public collectValueCompletions(resource: string, location: JSONPath, currentKey: string, result: CompletionsCollector): Thenable<any> {
if (this.isProjectJSONFile(resource) && (matches(location, ['dependencies']) || matches(location, ['frameworks', '*', 'dependencies']) || matches(location, ['frameworks', '*', 'frameworkAssemblies']))) {
return this.getNugetService('PackageBaseAddress/3.0.0').then(service => {
let queryUrl = service + currentKey + '/index.json';
return this.makeJSONRequest<any>(queryUrl).then(obj => {
if (Array.isArray(obj.versions)) {
let results = <any[]>obj.versions;
for (let i = 0; i < results.length; i++) {
let curr = results[i];
let name = JSON.stringify(curr);
let label = name;
let documentation = '';
result.add({ kind: CompletionItemKind.Class, label: label, insertText: name, documentation: documentation });
}
if (results.length === LIMIT) {
result.setAsIncomplete();
}
}
}, error => {
result.error(error);
});
}, error => {
result.error(error);
});
}
return null;
}
public getInfoContribution(resource: string, location: JSONPath): Thenable<MarkedString[]> {
if (this.isProjectJSONFile(resource) && (matches(location, ['dependencies', '*']) || matches(location, ['frameworks', '*', 'dependencies', '*']) || matches(location, ['frameworks', '*', 'frameworkAssemblies', '*']))) {
let pack = <string>location[location.length - 1];
return this.getNugetService('SearchQueryService').then(service => {
let queryUrl = service + '?q=' + encodeURIComponent(pack) + '&take=' + 5;
return this.makeJSONRequest<any>(queryUrl).then(resultObj => {
let htmlContent: MarkedString[] = [];
htmlContent.push(localize('json.nugget.package.hover', '{0}', pack));
if (Array.isArray(resultObj.data)) {
let results = <any[]>resultObj.data;
for (let i = 0; i < results.length; i++) {
let res = results[i];
this.addCached(res.id, res.version, res.description);
if (res.id === pack) {
if (res.description) {
htmlContent.push(MarkedString.fromPlainText(res.description));
}
if (res.version) {
htmlContent.push(MarkedString.fromPlainText(localize('json.nugget.version.hover', 'Latest version: {0}', res.version)));
}
break;
}
}
}
return htmlContent;
}, (error) => {
return null;
});
}, (error) => {
return null;
});
}
return null;
}
public resolveSuggestion(item: CompletionItem): Thenable<CompletionItem> {
if (item.data && Strings.startsWith(item.data, RESOLVE_ID)) {
let pack = item.data.substring(RESOLVE_ID.length);
if (this.completeWithCache(pack, item)) {
return Promise.resolve(item);
}
return this.getNugetService('SearchQueryService').then(service => {
let queryUrl = service + '?q=' + encodeURIComponent(pack) + '&take=' + 10;
return this.makeJSONRequest<CompletionItem>(queryUrl).then(resultObj => {
let itemResolved = false;
if (Array.isArray(resultObj.data)) {
let results = <any[]>resultObj.data;
for (let i = 0; i < results.length; i++) {
let curr = results[i];
this.addCached(curr.id, curr.version, curr.description);
if (curr.id === pack) {
this.completeWithCache(pack, item);
itemResolved = true;
}
}
}
return itemResolved ? item : null;
});
});
};
return null;
}
}
function matches(segments: JSONPath, pattern: string[]) {
let k = 0;
for (let i = 0; k < pattern.length && i < segments.length; i++) {
if (pattern[k] === segments[i] || pattern[k] === '*') {
k++;
} else if (pattern[k] !== '**') {
return false;
}
}
return k === pattern.length;
}

File diff suppressed because it is too large Load diff

View file

@ -13,9 +13,9 @@
"resolved": "https://registry.npmjs.org/semver/-/semver-4.3.6.tgz"
},
"typescript": {
"version": "typescript@2.2.1-insiders.20170209",
"from": "typescript@typescript@2.2.1-insiders.20170209",
"resolved": "https://registry.npmjs.org/typescript/-/typescript-2.2.1-insiders.20170209.tgz"
"version": "typescript@2.2.1-insiders.20170217",
"from": "typescript@typescript@2.2.1-insiders.20170217",
"resolved": "https://registry.npmjs.org/typescript/-/typescript-2.2.1-insiders.20170217.tgz"
},
"vscode-extension-telemetry": {
"version": "0.0.5",

View file

@ -14,7 +14,7 @@
"semver": "4.3.6",
"vscode-extension-telemetry": "^0.0.5",
"vscode-nls": "^2.0.1",
"typescript": "typescript@2.2.1-insiders.20170209"
"typescript": "typescript@2.2.1-insiders.20170217"
},
"devDependencies": {
"@types/node": "^7.0.4",
@ -90,10 +90,20 @@
"command": "_typescript.tryCompleteJsDoc",
"when": "editorTextFocus && !suggestWidgetVisible && editorLangId == 'typescript'"
},
{
{
"key": "enter",
"command": "_typescript.tryCompleteJsDoc",
"when": "editorTextFocus && !suggestWidgetVisible && editorLangId == 'typescriptreact'"
},
{
"key": "enter",
"command": "_typescript.tryCompleteJsDoc",
"when": "editorTextFocus && !suggestWidgetVisible && editorLangId == 'javascript'"
},
{
"key": "enter",
"command": "_typescript.tryCompleteJsDoc",
"when": "editorTextFocus && !suggestWidgetVisible && editorLangId == 'javascriptreact'"
}
],
"configuration": {

View file

@ -27,10 +27,10 @@ export default class TypeScriptCodeActionProvider implements CodeActionProvider
private supportedCodeActions: Promise<NumberSet>;
constructor(
private client: ITypescriptServiceClient,
modeId: string
private readonly client: ITypescriptServiceClient,
mode: string
) {
this.commandId = `typescript.codeActions.${modeId}`;
this.commandId = `_typescript.applyCodeAction.${mode}`;
this.supportedCodeActions = client.execute('getSupportedCodeFixes', null, undefined)
.then(response => response.body || [])
.then(codes => codes.map(code => +code).filter(code => !isNaN(code)))

View file

@ -70,40 +70,41 @@ export default class TypeScriptReferencesCodeLensProvider implements CodeLensPro
resolveCodeLens(inputCodeLens: CodeLens, token: CancellationToken): Promise<CodeLens> {
const codeLens = inputCodeLens as ReferencesCodeLens;
if (!codeLens.document) {
return Promise.reject<CodeLens>(codeLens);
}
const args: Proto.FileLocationRequestArgs = {
file: codeLens.file,
line: codeLens.range.start.line + 1,
offset: codeLens.range.start.character + 1
};
return this.client.execute('references', args, token).then(response => {
if (response && response.body) {
// Exclude original definition from references
const locations = response.body.refs
.filter(reference =>
!(reference.start.line === codeLens.range.start.line + 1
&& reference.start.offset === codeLens.range.start.character + 1))
.map(reference =>
new Location(this.client.asUrl(reference.file),
new Range(
new Position(reference.start.line - 1, reference.start.offset - 1),
new Position(reference.end.line - 1, reference.end.offset - 1))));
codeLens.command = {
title: locations.length + ' ' + (locations.length === 1 ? localize('oneReferenceLabel', 'reference') : localize('manyReferenceLabel', 'references')),
command: 'editor.action.showReferences',
arguments: [codeLens.document, codeLens.range.start, locations]
};
return Promise.resolve(codeLens);
if (!response || !response.body) {
throw codeLens;
}
return Promise.reject<CodeLens>(codeLens);
// Exclude original definition from references
const locations = response.body.refs
.filter(reference =>
!(reference.start.line === codeLens.range.start.line + 1
&& reference.start.offset === codeLens.range.start.character + 1))
.map(reference =>
new Location(this.client.asUrl(reference.file),
new Range(
reference.start.line - 1, reference.start.offset - 1,
reference.end.line - 1, reference.end.offset - 1)));
codeLens.command = {
title: locations.length === 1
? localize('oneReferenceLabel', '1 reference')
: localize('manyReferenceLabel', '{0} references', locations.length),
command: 'editor.action.showReferences',
arguments: [codeLens.document, codeLens.range.start, locations]
};
return codeLens;
}).catch(() => {
codeLens.command = {
title: localize('referenceErrorLabel', 'Could not determine references'),
command: ''
};
return Promise.resolve(codeLens);
return codeLens;
});
}
@ -115,8 +116,8 @@ export default class TypeScriptReferencesCodeLensProvider implements CodeLensPro
const span = item.spans && item.spans[0];
if (span) {
const range = new Range(
new Position(span.start.line - 1, span.start.offset - 1),
new Position(span.end.line - 1, span.end.offset - 1));
span.start.line - 1, span.start.offset - 1,
span.end.line - 1, span.end.offset - 1);
// TODO: TS currently requires the position for 'references 'to be inside of the identifer
// Massage the range to make sure this is the case

View file

@ -9,7 +9,7 @@
* ------------------------------------------------------------------------------------------ */
'use strict';
import { env, languages, commands, workspace, window, ExtensionContext, Memento, IndentAction, Diagnostic, DiagnosticCollection, Range, DocumentFilter, Disposable, Uri, MessageItem, TextEditor } from 'vscode';
import { env, languages, commands, workspace, window, ExtensionContext, Memento, IndentAction, Diagnostic, DiagnosticCollection, Range, Disposable, Uri, MessageItem, TextEditor, FileSystemWatcher } from 'vscode';
// This must be the first statement otherwise modules might got loaded with
// the wrong locale.
@ -45,7 +45,6 @@ import * as BuildStatus from './utils/buildStatus';
import * as ProjectStatus from './utils/projectStatus';
import TypingsStatus, { AtaProgressReporter } from './utils/typingsStatus';
import * as VersionStatus from './utils/versionStatus';
import ProjectConfigStatus from './utils/projectConfigStatus';
interface LanguageDescription {
id: string;
@ -87,6 +86,7 @@ export function activate(context: ExtensionContext): void {
configFile: 'jsconfig.json'
}
], context.storagePath, context.globalState, context.workspaceState);
context.subscriptions.push(clientHost);
const client = clientHost.serviceClient;
@ -126,9 +126,7 @@ export function activate(context: ExtensionContext): void {
context.subscriptions.push(commands.registerCommand('javascript.goToProjectConfig', goToProjectConfig.bind(null, false)));
window.onDidChangeActiveTextEditor(VersionStatus.showHideStatus, null, context.subscriptions);
client.onReady().then(() => {
context.subscriptions.push(new ProjectConfigStatus(client));
context.subscriptions.push(ProjectStatus.create(client,
path => new Promise(resolve => setTimeout(() => resolve(clientHost.handles(path)), 750)),
context.workspaceState));
@ -142,10 +140,10 @@ const validateSetting = 'validate.enable';
class LanguageProvider {
private extensions: ObjectMap<boolean>;
private readonly extensions: ObjectMap<boolean>;
private syntaxDiagnostics: ObjectMap<Diagnostic[]>;
private currentDiagnostics: DiagnosticCollection;
private bufferSyncSupport: BufferSyncSupport;
private readonly currentDiagnostics: DiagnosticCollection;
private readonly bufferSyncSupport: BufferSyncSupport;
private completionItemProvider: CompletionItemProvider;
private formattingProvider: FormattingProvider;
@ -153,15 +151,16 @@ class LanguageProvider {
private typingsStatus: TypingsStatus;
private referenceCodeLensProvider: ReferenceCodeLensProvider;
private _validate: boolean;
private _validate: boolean = true;
private readonly disposables: Disposable[] = [];
constructor(
private client: TypeScriptServiceClient,
private description: LanguageDescription
private readonly client: TypeScriptServiceClient,
private readonly description: LanguageDescription
) {
this.extensions = Object.create(null);
description.extensions.forEach(extension => this.extensions[extension] = true);
this._validate = true;
this.bufferSyncSupport = new BufferSyncSupport(client, description.modeIds, {
delete: (file: string) => {
@ -174,7 +173,7 @@ class LanguageProvider {
this.typingsStatus = new TypingsStatus(client);
new AtaProgressReporter(client);
workspace.onDidChangeConfiguration(this.configurationChanged, this);
workspace.onDidChangeConfiguration(this.configurationChanged, this, this.disposables);
this.configurationChanged();
client.onReady().then(() => {
@ -185,57 +184,68 @@ class LanguageProvider {
});
}
public dispose(): void {
if (this.formattingProviderRegistration) {
this.formattingProviderRegistration.dispose();
}
while (this.disposables.length) {
const obj = this.disposables.pop();
if (obj) {
obj.dispose();
}
}
this.typingsStatus.dispose();
this.currentDiagnostics.dispose();
this.bufferSyncSupport.dispose();
}
private registerProviders(client: TypeScriptServiceClient): void {
const selector = this.description.modeIds;
const config = workspace.getConfiguration(this.id);
this.completionItemProvider = new CompletionItemProvider(client, this.typingsStatus);
this.completionItemProvider.updateConfiguration();
this.disposables.push(languages.registerCompletionItemProvider(selector, this.completionItemProvider, '.'));
let hoverProvider = new HoverProvider(client);
let definitionProvider = new DefinitionProvider(client);
let implementationProvider = new ImplementationProvider(client);
const typeDefinitionProvider = new TypeDefintionProvider(client);
let documentHighlightProvider = new DocumentHighlightProvider(client);
let referenceProvider = new ReferenceProvider(client);
let documentSymbolProvider = new DocumentSymbolProvider(client);
let signatureHelpProvider = new SignatureHelpProvider(client);
let renameProvider = new RenameProvider(client);
this.formattingProvider = new FormattingProvider(client);
this.formattingProvider.updateConfiguration(config);
this.disposables.push(languages.registerOnTypeFormattingEditProvider(selector, this.formattingProvider, ';', '}', '\n'));
if (this.formattingProvider.isEnabled()) {
this.formattingProviderRegistration = languages.registerDocumentRangeFormattingEditProvider(this.description.modeIds, this.formattingProvider);
this.formattingProviderRegistration = languages.registerDocumentRangeFormattingEditProvider(selector, this.formattingProvider);
}
this.referenceCodeLensProvider = new ReferenceCodeLensProvider(client);
this.referenceCodeLensProvider.updateConfiguration();
this.disposables.push(languages.registerHoverProvider(selector, new HoverProvider(client)));
this.disposables.push(languages.registerDefinitionProvider(selector, new DefinitionProvider(client)));
this.disposables.push(languages.registerDocumentHighlightProvider(selector, new DocumentHighlightProvider(client)));
this.disposables.push(languages.registerReferenceProvider(selector, new ReferenceProvider(client)));
this.disposables.push(languages.registerDocumentSymbolProvider(selector, new DocumentSymbolProvider(client)));
this.disposables.push(languages.registerSignatureHelpProvider(selector, new SignatureHelpProvider(client), '(', ','));
this.disposables.push(languages.registerRenameProvider(selector, new RenameProvider(client)));
if (client.apiVersion.has206Features()) {
languages.registerCodeLensProvider(this.description.modeIds, this.referenceCodeLensProvider);
this.referenceCodeLensProvider = new ReferenceCodeLensProvider(client);
this.referenceCodeLensProvider.updateConfiguration();
this.disposables.push(languages.registerCodeLensProvider(selector, this.referenceCodeLensProvider));
}
if (client.apiVersion.has213Features()) {
this.disposables.push(languages.registerCodeActionsProvider(selector, new CodeActionProvider(client, this.description.id)));
}
if (client.apiVersion.has220Features()) {
this.disposables.push(languages.registerImplementationProvider(selector, new ImplementationProvider(client)));
}
if (client.apiVersion.has213Features()) {
this.disposables.push(languages.registerTypeDefinitionProvider(selector, new TypeDefintionProvider(client)));
}
this.description.modeIds.forEach(modeId => {
const selector: DocumentFilter = modeId;
languages.registerCompletionItemProvider(selector, this.completionItemProvider, '.');
languages.registerHoverProvider(selector, hoverProvider);
languages.registerDefinitionProvider(selector, definitionProvider);
if (client.apiVersion.has220Features()) {
// TODO: TS 2.1.5 returns incorrect results for implementation locations.
languages.registerImplementationProvider(selector, implementationProvider);
}
if (client.apiVersion.has213Features()) {
languages.registerTypeDefinitionProvider(selector, typeDefinitionProvider);
}
languages.registerDocumentHighlightProvider(selector, documentHighlightProvider);
languages.registerReferenceProvider(selector, referenceProvider);
languages.registerDocumentSymbolProvider(selector, documentSymbolProvider);
languages.registerSignatureHelpProvider(selector, signatureHelpProvider, '(', ',');
languages.registerRenameProvider(selector, renameProvider);
languages.registerOnTypeFormattingEditProvider(selector, this.formattingProvider, ';', '}', '\n');
languages.registerWorkspaceSymbolProvider(new WorkspaceSymbolProvider(client, modeId));
if (client.apiVersion.has213Features()) {
languages.registerCodeActionsProvider(selector, new CodeActionProvider(client, modeId));
}
this.disposables.push(languages.registerWorkspaceSymbolProvider(new WorkspaceSymbolProvider(client, modeId)));
languages.setLanguageConfiguration(modeId, {
this.disposables.push(languages.setLanguageConfiguration(modeId, {
indentationRules: {
// ^(.*\*/)?\s*\}.*$
decreaseIndentPattern: /^(.*\*\/)?\s*\}.*$/,
@ -249,18 +259,15 @@ class LanguageProvider {
beforeText: /^\s*\/\*\*(?!\/)([^\*]|\*(?!\/))*$/,
afterText: /^\s*\*\/$/,
action: { indentAction: IndentAction.IndentOutdent, appendText: ' * ' }
},
{
}, {
// e.g. /** ...|
beforeText: /^\s*\/\*\*(?!\/)([^\*]|\*(?!\/))*$/,
action: { indentAction: IndentAction.None, appendText: ' * ' }
},
{
}, {
// e.g. * ...|
beforeText: /^(\t|(\ \ ))*\ \*(\ ([^\*]|\*(?!\/))*)?$/,
action: { indentAction: IndentAction.None, appendText: '* ' }
},
{
}, {
// e.g. */|
beforeText: /^(\t|(\ \ ))*\ \*\/\s*$/,
action: { indentAction: IndentAction.None, removeText: 1 }
@ -271,11 +278,11 @@ class LanguageProvider {
action: { indentAction: IndentAction.None, removeText: 1 }
}
]
});
}));
const EMPTY_ELEMENTS: string[] = ['area', 'base', 'br', 'col', 'embed', 'hr', 'img', 'input', 'keygen', 'link', 'menuitem', 'meta', 'param', 'source', 'track', 'wbr'];
languages.setLanguageConfiguration('jsx-tags', {
this.disposables.push(languages.setLanguageConfiguration('jsx-tags', {
wordPattern: /(-?\d*\.\d\w*)|([^\`\~\!\@\$\^\&\*\(\)\=\+\[\{\]\}\\\|\;\:\'\"\,\.\<\>\/\s]+)/g,
onEnterRules: [
{
@ -288,7 +295,7 @@ class LanguageProvider {
action: { indentAction: IndentAction.Indent }
}
],
});
}));
});
}
@ -377,30 +384,49 @@ class TypeScriptServiceClientHost implements ITypescriptServiceClientHost {
private client: TypeScriptServiceClient;
private languages: LanguageProvider[];
private languagePerId: ObjectMap<LanguageProvider>;
private configFileWatcher: FileSystemWatcher;
private readonly disposables: Disposable[] = [];
constructor(descriptions: LanguageDescription[], storagePath: string | undefined, globalState: Memento, workspaceState: Memento) {
let handleProjectCreateOrDelete = () => {
constructor(
descriptions: LanguageDescription[],
storagePath: string | undefined,
globalState: Memento,
workspaceState: Memento
) {
const handleProjectCreateOrDelete = () => {
this.client.execute('reloadProjects', null, false);
this.triggerAllDiagnostics();
};
let handleProjectChange = () => {
const handleProjectChange = () => {
setTimeout(() => {
this.triggerAllDiagnostics();
}, 1500);
};
let watcher = workspace.createFileSystemWatcher('**/[tj]sconfig.json');
watcher.onDidCreate(handleProjectCreateOrDelete);
watcher.onDidDelete(handleProjectCreateOrDelete);
watcher.onDidChange(handleProjectChange);
const configFileWatcher = workspace.createFileSystemWatcher('**/[tj]sconfig.json');
this.disposables.push(configFileWatcher);
configFileWatcher.onDidCreate(handleProjectCreateOrDelete, this, this.disposables);
configFileWatcher.onDidDelete(handleProjectCreateOrDelete, this, this.disposables);
configFileWatcher.onDidChange(handleProjectChange, this, this.disposables);
this.client = new TypeScriptServiceClient(this, storagePath, globalState, workspaceState);
this.languages = [];
this.languagePerId = Object.create(null);
descriptions.forEach(description => {
let manager = new LanguageProvider(this.client, description);
for (const description of descriptions) {
const manager = new LanguageProvider(this.client, description);
this.languages.push(manager);
this.disposables.push(manager);
this.languagePerId[description.id] = manager;
});
}
}
public dispose(): void {
while (this.disposables.length) {
const obj = this.disposables.pop();
if (obj) {
obj.dispose();
}
}
this.configFileWatcher.dispose();
}
public get serviceClient(): TypeScriptServiceClient {

View file

@ -124,6 +124,7 @@ export default class TypeScriptServiceClient implements ITypescriptServiceClient
private _apiVersion: API;
private telemetryReporter: TelemetryReporter;
constructor(host: ITypescriptServiceClientHost, storagePath: string | undefined, globalState: Memento, private workspaceState: Memento) {
this.host = host;
this.storagePath = storagePath;

View file

@ -9,7 +9,7 @@ import { TextEditor, Position, Range, Selection } from 'vscode';
import { ITypescriptServiceClient } from '../typescriptService';
import { FileLocationRequestArgs } from '../protocol';
import { FileLocationRequestArgs, DocCommandTemplateResponse } from '../protocol';
export default class JsDocCompletionHelper {
@ -51,51 +51,47 @@ export default class JsDocCompletionHelper {
return false;
}
let cancelled = false;
const timer = setTimeout(() => {
cancelled = true;
}, 250);
const args: FileLocationRequestArgs = {
file: file,
line: start.line + 1,
offset: start.character + 1
};
return this.client.execute('docCommentTemplate', args)
.then(res => {
clearTimeout(timer);
if (cancelled || !res || !res.body) {
return false;
}
const commentText = res.body.newText;
return editor.edit(
edits => edits.insert(start, commentText),
{ undoStopBefore: false, undoStopAfter: true });
}, () => {
clearTimeout(timer);
return false;
return Promise.race([
this.client.execute('docCommentTemplate', args),
new Promise((_, reject) => {
setTimeout(reject, 250);
})
.then(didInsertComment => {
if (didInsertComment) {
const newCursorPosition = new Position(start.line + 1, editor.document.lineAt(start.line + 1).text.length);
editor.selection = new Selection(newCursorPosition, newCursorPosition);
return true;
}
]).then((res: DocCommandTemplateResponse) => {
if (!res || !res.body) {
return false;
}
const commentText = res.body.newText;
return editor.edit(
edits => edits.insert(start, commentText),
{ undoStopBefore: false, undoStopAfter: true });
}, () => {
return false;
}).then(didInsertComment => {
if (didInsertComment) {
const newCursorPosition = new Position(start.line + 1, editor.document.lineAt(start.line + 1).text.length);
editor.selection = new Selection(newCursorPosition, newCursorPosition);
return true;
}
// Revert to the original line content and restore position
return editor.edit(
edits => {
edits.insert(start, prefix[1] + suffix[0]);
}, {
undoStopBefore: false,
undoStopAfter: true
}
).then(() => {
editor.selection = new Selection(position, position);
return false;
});
// Revert to the original line content and restore position
return editor.edit(
edits => {
edits.insert(start, prefix[1] + suffix[0]);
}, {
undoStopBefore: false,
undoStopAfter: true
}
).then(() => {
editor.selection = new Selection(position, position);
return false;
});
});
});
}
}

View file

@ -1,84 +0,0 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
'use strict';
import * as vscode from 'vscode';
import { ITypescriptServiceClient } from '../typescriptService';
import { loadMessageBundle } from 'vscode-nls';
const localize = loadMessageBundle();
export default class ProjectConfigStatus implements vscode.Disposable {
private entry: vscode.StatusBarItem;
private subscription: vscode.Disposable;
constructor(private client: ITypescriptServiceClient) {
this.entry = vscode.window.createStatusBarItem(vscode.StatusBarAlignment.Right, Number.MIN_VALUE);
this.entry.color = 'white';
this.entry.command = 'typescript.goToProjectConfig';
this.subscription = vscode.window.onDidChangeActiveTextEditor(editor => this.showHideStatus(editor));
if (vscode.window.activeTextEditor) {
this.showHideStatus(vscode.window.activeTextEditor);
}
}
private showHideStatus(editor: vscode.TextEditor | undefined) {
editor = editor || vscode.window.activeTextEditor;
if (!editor || !vscode.workspace.rootPath) {
this.hide();
return;
}
const doc = editor.document;
const isTypeScript = !!(vscode.languages.match('typescript', doc) || vscode.languages.match('typescriptreact', doc));
if (isTypeScript || vscode.languages.match('javascript', doc) || vscode.languages.match('javascriptreact', doc)) {
this.showStatusForResource(doc.uri, isTypeScript);
} else {
this.hide();
}
}
private showStatusForResource(resource: vscode.Uri, isTypeScript: boolean) {
const file = this.client.normalizePath(resource);
if (!file) {
this.hide();
return;
}
return this.client.execute('projectInfo', { file, needFileNameList: false }).then(res => {
if (!res || !res.body || !res.body.configFileName) {
this.hide();
return;
}
const { configFileName } = res.body;
this.entry.tooltip = configFileName;
this.entry.command = isTypeScript ? 'typescript.goToProjectConfig' : 'javascript.goToProjectConfig';
if (configFileName.toLowerCase().endsWith('tsconfig.json')) {
this.entry.text = 'tsconfig';
} else if (configFileName.toLowerCase().endsWith('jsconfig.json')) {
this.entry.text = 'jsconfig';
} else {
this.entry.text = isTypeScript
? localize('typescript.projectConfigStatus.noTypeScriptProject', 'No TS Project')
: localize('typescript.projectConfigStatus.noJavaScriptProject', 'No JS Project');
}
this.entry.show();
});
}
private hide() {
this.entry.hide();
this.entry.text = '';
this.entry.tooltip = '';
}
dispose() {
this.entry.dispose();
this.subscription.dispose();
}
}

View file

@ -7,7 +7,7 @@
import vscode = require('vscode');
const versionBarEntry = vscode.window.createStatusBarItem(vscode.StatusBarAlignment.Right, Number.MIN_VALUE + 1);
const versionBarEntry = vscode.window.createStatusBarItem(vscode.StatusBarAlignment.Right, Number.MIN_VALUE);
export function showHideStatus() {
if (!versionBarEntry) {

View file

@ -4,7 +4,11 @@
*--------------------------------------------------------------------------------------------*/
// Do not edit this file. It is machine generated.
{
"noExecutable": "无法验证,因为未设置任何 PHP 可执行文件。单击“路径”状态栏项目以配置可执行文件。",
"noExecutable": "无法验证,因为未设置任何 PHP 可执行文件。请使用设置 \"php.validate.executablePath\" 配置 PHP 可执行文件。",
"php.more": "了解详细信息",
"php.no": "否",
"php.useExecutablePath": "是否允许执行 {0} 以进行 PHP 文件的 lint 操作?",
"php.yes": "是",
"unknownReason": "使用路径运行 php 失败: {0}。原因未知。",
"wrongExecutable": "无法验证,因为 {0} 不是有效的 PHP 可执行文件。单击“路径”状态栏项目以配置可执行文件。"
"wrongExecutable": "无法验证,因为 {0} 不是有效的 PHP 可执行文件。请使用设置 \"php.validate.executablePath\" 配置 PHP 可执行文件。"
}

View file

@ -6,17 +6,17 @@
{
"activeVersion": "当前处于活动状态",
"channelName": "TypeScript",
"later": "稍后",
"learnMore": "了解详细信息",
"noServerFound": "路径 {0} 未指向有效的 tsserver 安装。请回退到捆绑的 TypeScript 版本。",
"reloadBlurb": "重新加载窗口以应用更改",
"reloadTitle": "重新加载",
"selectTsVersion": "选择用语言功能的 TypeScript 版本",
"selectTsVersion": "选择用于 JavaScript 和 TypeScript 语言功能的 TypeScript 版本",
"serverCouldNotBeStarted": "无法启动 TypeScript 语言服务器。错误消息为: {0}",
"serverDied": "在过去 5 分钟内TypeScript 语言服务意外中止了 5 次。",
"serverDiedAfterStart": "TypeScript 语言服务在其启动后已中止 5 次。将不会重启该服务。",
"serverDiedReportIssue": "报告问题",
"useVSCodeVersionOption": "使用 VSCode 的版本",
"useWorkspaceVersionOption": "使用工作区版本",
"versionCheckUsingBundledTS": "对 Typescript 语言功能使用 VSCode 的 TypeScript 版本 {0}",
"versionNumber.custom": "自定义"
}

View file

@ -4,5 +4,6 @@
*--------------------------------------------------------------------------------------------*/
// Do not edit this file. It is machine generated.
{
"git": "GIT"
"git": "GIT",
"toggleSCMViewlet": "显示 SCM"
}

View file

@ -4,7 +4,11 @@
*--------------------------------------------------------------------------------------------*/
// Do not edit this file. It is machine generated.
{
"noExecutable": "因為未設定 PHP 可執行檔,所以無法進行驗證。請按一下 [路徑] 狀態列項目以設定可執行檔。",
"noExecutable": "因為未設定任何 PHP 可執行檔,所以無法驗證。您可以使用 'php.validate.executablePath' 設定可執行檔。",
"php.more": "深入了解",
"php.no": "否",
"php.useExecutablePath": "要允許 {0} 執行,以使用 lint 標記 PHP 檔案嗎?",
"php.yes": "是",
"unknownReason": "無法使用路徑 {0} 執行 PHP。原因不明。",
"wrongExecutable": "因為 {0} 不是有效的 PHP 可執行檔,所以無法進行驗證。請按一下 [路徑] 狀態列項目以設定可執行檔。"
"wrongExecutable": "因為 {0} 不是有效的 PHP 可執行檔,所以無法驗證。您可以使用設定 'php.validate.executablePath' 設定 PHP 可執行檔。"
}

View file

@ -6,17 +6,17 @@
{
"activeVersion": "目前使用中",
"channelName": "TypeScript",
"later": "稍後",
"learnMore": "深入了解",
"noServerFound": "路徑 {0} 未指向有效的 tsserver 安裝。即將回復為配套的 TypeScript 版本。",
"reloadBlurb": "重新載入視窗以套用變更",
"reloadTitle": "重新載入",
"selectTsVersion": "選取用於語言功能的 TypeScript 版本",
"selectTsVersion": "選取 JavaScript 與 TypeScript 功能使用的 TypeScript 版本",
"serverCouldNotBeStarted": "無法啟動 TypeScript 語言伺服器。錯誤訊息為: {0}",
"serverDied": "TypeScript 語言服務在過去 5 分鐘內意外中止 5 次。",
"serverDiedAfterStart": "TypeScript 語言服務在啟動後立即中止 5 次。服務將不會重新啟動。",
"serverDiedReportIssue": "回報問題",
"useVSCodeVersionOption": "使用 VSCode 的版本",
"useWorkspaceVersionOption": "使用工作區版本",
"versionCheckUsingBundledTS": "對 TypeScript 語言功能使用 VSCode 的 TypeScript 版本 {0}",
"versionNumber.custom": "自訂"
}

View file

@ -4,5 +4,6 @@
*--------------------------------------------------------------------------------------------*/
// Do not edit this file. It is machine generated.
{
"git": "Git"
"git": "Git",
"toggleSCMViewlet": "顯示 SCM"
}

View file

@ -4,7 +4,10 @@
*--------------------------------------------------------------------------------------------*/
// Do not edit this file. It is machine generated.
{
"noExecutable": "Eine Überprüfung ist nicht möglich, da keine ausführbare PHP-Datei festgelegt ist. Klicken Sie auf das Pfad-Statusleistenelement, um die ausführbare Datei zu konfigurieren.",
"noExecutable": "Eine Überprüfung ist nicht möglich, da keine ausführbare PHP-Datei festgelegt ist. Verwenden Sie die Einstellung \"php.validate.executablePath\", um die ausführbare PHP-Datei zu konfigurieren.",
"php.more": "Weitere Informationen",
"php.no": "Nein",
"php.yes": "Ja",
"unknownReason": "Fehler beim Ausführen von PHP mithilfe des Pfads \"{0}\". Die Ursache ist unbekannt.",
"wrongExecutable": "Eine Überprüfung ist nicht möglich, da {0} keine ausführbare PHP-Datei ist. Klicken Sie auf das Pfad-Statusleistenelement, um die ausführbare Datei zu konfigurieren."
"wrongExecutable": "Eine Überprüfung ist nicht möglich, da {0} keine gültige ausführbare PHP-Datei ist. Verwenden Sie die Einstellung \"'php.validate.executablePath\", um die ausführbare PHP-Datei zu konfigurieren."
}

View file

@ -6,17 +6,17 @@
{
"activeVersion": "Aktuell aktiv",
"channelName": "TypeScript",
"later": "Später",
"learnMore": "Weitere Informationen",
"noServerFound": "Der Pfad \"{0}\" zeigt nicht auf eine gültige tsserver-Installation. Fallback auf gebündelte TypeScript-Version wird durchgeführt.",
"reloadBlurb": "Fenster erneut laden, um die Änderungen anzuwenden",
"reloadTitle": "Erneut laden",
"selectTsVersion": "Wählen Sie die für die Sprachfunktionen verwendete TypeScript-Version aus.",
"selectTsVersion": "Wählen Sie die für die JavaScript- und TypeScript-Sprachfunktionen verwendete TypeScript-Version aus.",
"serverCouldNotBeStarted": "Der TypeScript-Sprachserver konnte nicht gestartet werden. Fehlermeldung: {0}",
"serverDied": "Der TypeScript-Sprachdienst wurde während der letzten fünf Minuten fünfmal unerwartet beendet.",
"serverDiedAfterStart": "Der TypeScript-Sprachdienst wurde direkt nach seinem Start fünfmal beendet. Der Dienst wird nicht neu gestartet.",
"serverDiedReportIssue": "Problem melden",
"useVSCodeVersionOption": "Version von VSCode verwenden",
"useWorkspaceVersionOption": "Arbeitsbereichsversion verwenden",
"versionCheckUsingBundledTS": "TypeScript-Version {0} von VSCode für die TypeScript-Sprachfunktionen verwenden",
"versionNumber.custom": "benutzerdefiniert"
}

View file

@ -101,7 +101,7 @@
"miSelectAll": "&&Alles auswählen",
"miSelectColorTheme": "&&Farbdesign",
"miSelectHighlights": "Alle V&&orkommen auswählen",
"miSelectIconTheme": "Datei- &&Symboldesign",
"miSelectIconTheme": "Datei-&&Symboldesign",
"miShowActivityBar": "&&Aktivitätsleiste anzeigen",
"miShowEmmetCommands": "E&&mmet...",
"miShowStatusbar": "&&Statusleiste anzeigen",

View file

@ -13,6 +13,7 @@
"enablePreviewFromQuickOpen": "Steuert, ob geöffnete Editoren aus Quick Open als Vorschau angezeigt werden. Vorschau-Editoren werden wiederverwendet, bis sie gespeichert werden (z. B. über Doppelklicken oder Bearbeiten).",
"file": "Datei",
"help": "Hilfe",
"menuBarVisibility": "Steuert die Sichtbarkeit der Menüleiste. Die Einstellung \"Umschalten\" bedeutet, dass die Menüleiste durch einfaches Betätigen der ALT-Taste angezeigt und ausgeblendet wird. Die Menüleite wird standardmäßig angezeigt, sofern sich das Fenster nicht im Vollbildmodus befindet.",
"newWindowDimensions": "Steuert die Abmessungen beim Öffnen eines neuen Fensters. Standardmäßig wird in der Mitte des Bildschirms ein neues Fenster mit kleinen Abmessungen geöffnet. Bei der Einstellung \"Erben\", erhält das Fenster die gleichen Abmessungen wie das letzte aktive Fenster. Bei der Einstellung \"Maximiert\" wird das Fenster maximiert geöffnet, und bei \"Vollbild\" wird es im Vollbildmodus geöffnet.",
"openDefaultSettings": "Steuert, ob beim Öffnen der Einstellungen auch ein Editor geöffnet wird, der alle Standardeinstellungen anzeigt.",
"openFilesInNewWindow": "Steuert, ob Dateien in einem neuen Fenster oder im letzten aktiven Fenster geöffnet werden.\n- Standard: Die Dateien werden im letzten aktiven Fenster geöffnet, sofern sie nicht über das Dock oder den Finder geöffnet werden (nur macOS).\n- Ein: Die Dateien werden in einem neuen Fenster geöffnet.\n- Aus: Die Dateien werden im letzten aktiven Fenster geöffnet.\nIn einigen Fällen wird diese Einstellung unter Umständen ignoriert (z. B. bei der Befehlszeilenoption \"-new-window\" oder \"-reuse-window\").",

View file

@ -4,5 +4,6 @@
*--------------------------------------------------------------------------------------------*/
// Do not edit this file. It is machine generated.
{
"git": "Git"
"git": "Git",
"toggleSCMViewlet": "SCM anzeigen"
}

View file

@ -4,7 +4,10 @@
*--------------------------------------------------------------------------------------------*/
// Do not edit this file. It is machine generated.
{
"noExecutable": "No se puede validar porque no hay ningún ejecutable PHP establecido. Haga clic en el elemento de la barra de estado Ruta de acceso para configurar el ejecutable.",
"noExecutable": "No se puede validar porque no hay ningún ejecutable PHP establecido. Use el ajuste \"php.validate.executablePath\" para configurar el ejecutable de PHP.",
"php.more": "Más información",
"php.no": "No",
"php.yes": "Sí",
"unknownReason": "No se pudo ejecutar el archivo PHP con la ruta de acceso: {0}. Se desconoce el motivo.",
"wrongExecutable": "No se puede validar porque {0} no es un ejecutable PHP válido. Haga clic en el elemento de la barra de estado Ruta de acceso para configurar el ejecutable."
"wrongExecutable": "No se puede validar porque {0} no es un ejecutable PHP válido. Use el ajuste \"php.validate.executablePath\" para configurar el ejecutable PHP."
}

View file

@ -6,17 +6,17 @@
{
"activeVersion": "Activa actualmente",
"channelName": "TypeScript",
"later": "Más tarde",
"learnMore": "Más información",
"noServerFound": "La ruta de acceso {0} no apunta a una instalación válida de tsserver. Se usará la versión de TypeScript del paquete.",
"reloadBlurb": "Recargar ventana para aplicar cambios",
"reloadTitle": "Recargar",
"selectTsVersion": "Seleccionar la versión de TypeScript usada para las características del lenguaje",
"selectTsVersion": "Seleccionar la versión de TypeScript usada para las características del lenguaje de JavaScript y TypeScript",
"serverCouldNotBeStarted": "El servidor de lenguaje TypeScript no se pudo iniciar. El mensaje de error es: {0}",
"serverDied": "El servicio de lenguaje Typescript finalizó de forma inesperada cinco veces en los últimos cinco minutos.",
"serverDiedAfterStart": "El servicio de lenguaje TypeScript finalizó de forma inesperada cinco veces después de haberse iniciado y no se reiniciará.",
"serverDiedReportIssue": "Notificar problema",
"useVSCodeVersionOption": "Usar versión de VSCode",
"useWorkspaceVersionOption": "Usar versión del área de trabajo",
"versionCheckUsingBundledTS": "Se usa la versión de TypeScript {0} de VSCode para las características del lenguaje Typescript",
"versionNumber.custom": "personalizada"
}

View file

@ -4,5 +4,6 @@
*--------------------------------------------------------------------------------------------*/
// Do not edit this file. It is machine generated.
{
"git": "GIT"
"git": "GIT",
"toggleSCMViewlet": "Mostrar SCM"
}

View file

@ -4,7 +4,11 @@
*--------------------------------------------------------------------------------------------*/
// Do not edit this file. It is machine generated.
{
"noExecutable": "Impossible d'effectuer la validation, car aucun exécutable PHP n'est défini. Cliquez sur l'élément Chemin de la barre d'état pour configurer l'exécutable.",
"noExecutable": "Impossible d'effectuer la validation, car aucun exécutable PHP n'est défini. Utilisez le paramètre 'php.validate.executablePath' pour configurer l'exécutable PHP.",
"php.more": "En savoir plus",
"php.no": "Non",
"php.useExecutablePath": "Autorisez-vous l'exécution de {0} pour effectuer une validation lint sur les fichiers PHP ?",
"php.yes": "Oui",
"unknownReason": "Échec de l'exécution de php avec le chemin : {0}. Raison inconnue.",
"wrongExecutable": "Impossible d'effectuer la validation, car {0} n'est pas un exécutable PHP valide. Cliquez sur l'élément Chemin de la barre d'état pour configurer l'exécutable."
"wrongExecutable": "Impossible d'effectuer la validation, car {0} n'est pas un exécutable PHP valide. Utilisez le paramètre 'php.validate.executablePath' pour configurer l'exécutable PHP."
}

View file

@ -6,17 +6,17 @@
{
"activeVersion": "En cours",
"channelName": "TypeScript",
"later": "Plus tard",
"learnMore": "En savoir plus",
"noServerFound": "Le chemin {0} ne pointe pas vers une installation tsserver valide. Utilisation par défaut de la version TypeScript groupée.",
"reloadBlurb": "Recharger la fenêtre pour appliquer les changements",
"reloadTitle": "Recharger",
"selectTsVersion": "Sélectionner la version TypeScript utilisée pour les fonctionnalités de langage",
"selectTsVersion": "Sélectionner la version TypeScript utilisée pour les fonctionnalités de langage JavaScript et TypeScript",
"serverCouldNotBeStarted": "Impossible de démarrer le serveur de langage TypeScript. Message d'erreur : {0}",
"serverDied": "Le service de langage TypeScript s'est subitement arrêté 5 fois au cours des 5 dernières minutes.",
"serverDiedAfterStart": "Le service de langage TypeScript s'est subitement arrêté 5 fois juste après avoir démarré. Il n'y aura pas d'autres redémarrages.",
"serverDiedReportIssue": "Signaler un problème",
"useVSCodeVersionOption": "Utiliser la version de VSCode",
"useWorkspaceVersionOption": "Utiliser la version de l'espace de travail",
"versionCheckUsingBundledTS": "Utilisation de la version TypeScript {0} de VSCode pour les fonctionnalités de langage TypeScript",
"versionNumber.custom": "personnalisé"
}

View file

@ -4,5 +4,6 @@
*--------------------------------------------------------------------------------------------*/
// Do not edit this file. It is machine generated.
{
"git": "Git"
"git": "Git",
"toggleSCMViewlet": "Afficher SCM"
}

View file

@ -4,7 +4,11 @@
*--------------------------------------------------------------------------------------------*/
// Do not edit this file. It is machine generated.
{
"noExecutable": "PHP 実行可能ファイルが設定されていないため、検証できません。[パス] ステータス バー項目をクリックし、実行可能ファイルを設定してください。",
"noExecutable": "PHP 実行可能ファイルが設定されていないため、検証できません。設定 'php.validate.executablePath' を使用して PHP 実行可能ファイルを構成してください。",
"php.more": "詳細情報",
"php.no": "いいえ",
"php.useExecutablePath": "PHP ファイルを lint するために {0} を実行することを許可しますか?",
"php.yes": "はい",
"unknownReason": "パス {0} を使用して php を実行できませんでした。理由は不明です。",
"wrongExecutable": "{0} が有効な PHP 実行可能ファイルではないため、検証できません。[パス] ステータス バー項目をクリックし、実行可能ファイルを設定してください。"
"wrongExecutable": "{0} が有効な PHP 実行可能ファイルではないため、検証できません。設定 'php.validate.executablePath' を使用して PHP 実行可能ファイルを構成してください。"
}

View file

@ -6,17 +6,17 @@
{
"activeVersion": "現在有効",
"channelName": "TypeScript",
"later": "後続",
"learnMore": "詳細情報",
"noServerFound": "パス {0} は、有効な tsserver インストールを指していません。バンドルされている TypeScript バージョンにフォールバックしています。",
"reloadBlurb": "ウィンドウを再度読み込んで、変更を適用します",
"reloadTitle": "再読み込む",
"selectTsVersion": "言語機能に使用する TypeScript バージョンを選択します",
"selectTsVersion": "JavaScript および TypeScript 言語機能に使用する TypeScript バージョンを選択します",
"serverCouldNotBeStarted": "TypeScript 言語サーバーを起動できません。エラー メッセージ: {0}",
"serverDied": "TypeScript 言語サービスは、直前の 5 分間に 5 回、予期せずに停止しました。",
"serverDiedAfterStart": "TypeScript 言語サービスは、開始直後に 5 回停止しました。サービスは再開されません。",
"serverDiedReportIssue": "問題の報告",
"useVSCodeVersionOption": "VSCode のバージョンの使用",
"useWorkspaceVersionOption": "ワークスペース バージョンの使用",
"versionCheckUsingBundledTS": "Typescript 言語機能に VSCode の TypeScript バージョン {0} を使用しています",
"versionNumber.custom": "カスタム"
}

View file

@ -4,5 +4,6 @@
*--------------------------------------------------------------------------------------------*/
// Do not edit this file. It is machine generated.
{
"git": "Git"
"git": "Git",
"toggleSCMViewlet": "SCM を表示"
}

View file

@ -4,7 +4,11 @@
*--------------------------------------------------------------------------------------------*/
// Do not edit this file. It is machine generated.
{
"noExecutable": "PHP 실행 파일이 설정되지 않았기 때문에 유효성을 검사할 수 없습니다. [경로] 상태 표시줄 항목을 클릭하여 실행 파일을 구성하세요.",
"noExecutable": "PHP 실행 파일이 설정되지 않았기 때문에 유효성을 검사할 수 없습니다. 'php.validate.executablePath' 설정을 사용하여 PHP 실행 파일을 구성하세요.",
"php.more": "자세한 정보",
"php.no": "아니요",
"php.useExecutablePath": "PHP 파일을 lint하기 위해 {0}을(를) 실행하도록 허용하시겠습니까?",
"php.yes": "예",
"unknownReason": "{0} 경로를 사용하여 php를 실행하지 못했습니다. 이유를 알 수 없습니다.",
"wrongExecutable": "{0}은(는) 유효한 PHP 실행 파일이 아니기 때문에 유효성을 검사할 수 없습니다. [경로] 상태 표시줄 항목을 클릭하여 실행 파일을 구성하세요."
"wrongExecutable": "{0}은(는) 유효한 PHP 실행 파일이 아니기 때문에 유효성을 검사할 수 없습니다. 'php.validate.executablePath' 설정을 사용하여 PHP 실행 파일을 구성하세요."
}

View file

@ -6,17 +6,17 @@
{
"activeVersion": "현재 활성",
"channelName": "TypeScript",
"later": "이상",
"learnMore": "자세한 정보",
"noServerFound": "경로 {0}이(가) 올바른 tsserver 설치를 가리키지 않습니다. 포함된 TypeScript 버전을 대신 사용합니다.",
"reloadBlurb": "창을 다시 로드하여 변경 내용 적용",
"reloadTitle": "다시 로드",
"selectTsVersion": "언어 기능에 사용되는 TypeScript 버전 선택",
"selectTsVersion": "JavaScript 및 TypeScript 언어 기능에 사용되는 TypeScript 버전 선택",
"serverCouldNotBeStarted": "TypeScript 언어 서버를 시작할 수 없습니다. 오류 메시지: {0}",
"serverDied": "TypeScript 언어 서비스가 지난 5분 동안 예기치 않게 5번 종료되었습니다.",
"serverDiedAfterStart": "TypeScript 언어 서비스가 시작된 직후 5번 종료되었습니다. 서비스가 다시 시작되지 않습니다.",
"serverDiedReportIssue": "문제 보고",
"useVSCodeVersionOption": "VSCode의 버전 사용",
"useWorkspaceVersionOption": "작업 영역 버전 사용",
"versionCheckUsingBundledTS": "Typescript 언어 기능에 대해 VSCode의 TypeScript 버전 {0} 사용",
"versionNumber.custom": "사용자 지정"
}

View file

@ -16,8 +16,8 @@
"menuBarVisibility": "메뉴 모음의 표시 여부를 제어합니다. '설정/해제'를 설정함으로써 메뉴 모음이 숨겨지고 <Alt> 키를 누를 때마다 메뉴 모음이 표시됩니다. 기본값으로, 창이 전체 화면이 아닌 이상 메뉴 모음이 표시됩니다.",
"newWindowDimensions": "새 창을 열 때 크기를 제어합니다. 기본적으로 새 창은 화면 가운데에 작은 크기로 열립니다. '상속'으로 설정할 경우 마지막 활성 창과 동일한 크기로 창이 열립니다. '최대화'로 설정할 경우 창이 최대화되어 열리고 '전체 화면'으로 구성할 경우 전체 화면으로 열립니다.",
"openDefaultSettings": "설정을 열면 모든 기본 설정을 표시하는 편집기도 열리는지 여부를 제어합니다.",
"openFilesInNewWindow": "파일을 새 창에서 열지 마지막 활성 창에서 열지를 제어합니다.\n- 기본값: 도크 혹은 파인더(macOS 전용)를 통해 파일을 열지 않는 이상, 파일은 마지막 활성 창에서 열립니다.\n- 켜기: 파일이 새 창에서 열립니다.\n- 끄기: 파일이 마지막 활성 창에서 열립니다.\n이 설정이 무시되는 경우도 있을 수 있습니다(예: -new-window 또는 -reuse-window 명령줄 옵션을 사용할 경우).",
"openFoldersInNewWindow": "폴더를 새 창에서 열지, 마지막 활성 창과 바꿀지를 제어합니다.\n- 기본값: 폴더를 응용 프로그램 내에서 [파일] 메뉴 등을 통해 선택하지 않는 이상 폴더는 새 창에서 열립니다.\n- 켜기: 폴더가 새 창에서 열립니다.\n- 끄기: 폴더가 마지막 활성 창을 대체합니다.\n이 설정이 무시되는 경우도 있을 수 있습니다(예: -new-window 또는 -reuse-window 명령줄 옵션을 사용할 경우).",
"openFilesInNewWindow": "파일을 새 창에서 열지 마지막 활성 창에서 열지를 제어합니다.\n- 기본값: 도크 혹은 파인더(macOS 전용)를 통해 파일을 열지 않는 이상, 파일은 마지막 활성 창에서 열립니다.\n- 켬: 파일이 새 창에서 열립니다.\n- 끔: 파일이 마지막 활성 창에서 열립니다.\n이 설정이 무시되는 경우도 있을 수 있습니다(예: -new-window 또는 -reuse-window 명령줄 옵션을 사용할 경우).",
"openFoldersInNewWindow": "폴더를 새 창에서 열지, 마지막 활성 창과 바꿀지를 제어합니다.\n- 기본값: 폴더를 응용 프로그램 내에서 [파일] 메뉴 등을 통해 선택하지 않는 이상 폴더는 새 창에서 열립니다.\n- 켬: 폴더가 새 창에서 열립니다.\n- 끔: 폴더가 마지막 활성 창을 대체합니다.\n이 설정이 무시되는 경우도 있을 수 있습니다(예: -new-window 또는 -reuse-window 명령줄 옵션을 사용할 경우).",
"reopenFolders": "다시 시작한 이후에 폴더를 다시 여는 방법을 제어합니다. 폴더를 다시 열지 않으려면 'none'을 선택하고, 마지막으로 작업한 폴더를 다시 열려면 'one'을 선택하고, 마지막 세션의 모든 폴더를 다시 열려면 'all'을 선택합니다.",
"restoreFullscreen": "창이 전체 화면 모드에서 종료된 경우 창을 전체 화면 모드로 복원할지 여부를 제어합니다.",
"showEditorTabs": "열려 있는 편집기를 탭에서 표시할지 여부를 제어합니다.",

View file

@ -4,5 +4,6 @@
*--------------------------------------------------------------------------------------------*/
// Do not edit this file. It is machine generated.
{
"git": "Git"
"git": "Git",
"toggleSCMViewlet": "SCM 표시"
}

View file

@ -4,7 +4,11 @@
*--------------------------------------------------------------------------------------------*/
// Do not edit this file. It is machine generated.
{
"noExecutable": "Не удается проверить, так как не задан исполняемый PHP-файл. Щелкните элемент строки состояния \"Путь\", чтобы настроить его.",
"noExecutable": "Не удается проверить, так как не задан исполняемый PHP-файл. Используйте параметр php.validate.executablePath, чтобы настроить исполняемый PHP-файл.",
"php.more": "Подробнее",
"php.no": "Нет",
"php.useExecutablePath": "Разрешить выполнять {0} для обработки PHP-файлов через lint?",
"php.yes": "Да",
"unknownReason": "Не удалось запустить PHP-файл, используя путь {0}. Причина неизвестна.",
"wrongExecutable": "Не удается проверить, так как {0} не является допустимым исполняемым PHP-файлом. Щелкните элемент строки состояния \"Путь\", чтобы настроить его."
"wrongExecutable": "Не удается проверить, так как {0} не является допустимым исполняемым PHP-файлом. Используйте параметр php.validate.executablePath, чтобы настроить исполняемый PHP-файл."
}

View file

@ -6,17 +6,17 @@
{
"activeVersion": "Сейчас активно.",
"channelName": "TypeScript",
"later": "Позже",
"learnMore": "Подробнее...",
"noServerFound": "Путь {0} не указывает на допустимый файл программы установки tsserver. Выполняется откат до пакетной версии TypeScript.",
"reloadBlurb": "Перезагрузите окно, чтобы применить изменения.",
"reloadTitle": "Перезагрузка",
"selectTsVersion": "Выберите версию TypeScript, используемую для языковых функций.",
"selectTsVersion": "Выберите версию TypeScript, используемую для языковых функций JavaScript и TypeScript.",
"serverCouldNotBeStarted": "Не удалось запустить языковой сервер TypeScript. Сообщение об ошибке: \"{0}\".",
"serverDied": "Языковая служба TypeScript пять раз непредвиденно завершила работу за последние пять минут.",
"serverDiedAfterStart": "Языковая служба TypeScript пять раз завершила работу сразу после запуска. Служба не будет перезапущена.",
"serverDiedReportIssue": "Сообщить об ошибке",
"useVSCodeVersionOption": "Использовать версию VSCode",
"useWorkspaceVersionOption": "Использовать версию рабочей области",
"versionCheckUsingBundledTS": "Используется версия TypeScript VSCode {0} для языковых функций Typescript.",
"versionNumber.custom": "пользовательский"
}

View file

@ -4,5 +4,6 @@
*--------------------------------------------------------------------------------------------*/
// Do not edit this file. It is machine generated.
{
"git": "Git"
"git": "Git",
"toggleSCMViewlet": "Показать SCM"
}

4
npm-shrinkwrap.json generated
View file

@ -425,9 +425,9 @@
"resolved": "https://registry.npmjs.org/winreg/-/winreg-1.2.0.tgz"
},
"xterm": {
"version": "2.3.0",
"version": "2.3.2",
"from": "Tyriar/xterm.js#vscode-release/1.10",
"resolved": "git+https://github.com/Tyriar/xterm.js.git#5513303451202b0135601a2f026602ed391b3906"
"resolved": "git+https://github.com/Tyriar/xterm.js.git#631e4a2d7480affeb359de9f2fa14a82e4f9f748"
},
"yauzl": {
"version": "2.3.1",

View file

@ -2,7 +2,7 @@
"name": "code-oss-dev",
"version": "1.10.0",
"electronVersion": "1.4.6",
"distro": "4d6820ed4c9ffeac4febc40ac77bc391c8700a0d",
"distro": "fdc80c6b4d95e5f961bd3f85b927693915550942",
"author": {
"name": "Microsoft Corporation"
},

View file

@ -31,8 +31,38 @@ if [ "@@NAME@@" != "code-oss" ]; then
APT_DIR=$(get_apt_config_value Dir)
APT_ETC=$APT_DIR$(get_apt_config_value Dir::Etc)
APT_SOURCE_PARTS=$APT_ETC/$(get_apt_config_value Dir::Etc::sourceparts)
CODE_SOURCE_LIST=$APT_SOURCE_PARTS/vscode.list
CODE_SOURCE_PART=$APT_SOURCE_PARTS/vscode.list
rm -f $CODE_SOURCE_LIST
# echo "deb [arch=amd64] https://packages.microsoft.com/repos/vscode stable main" > $CODE_SOURCE_LIST
fi
APT_TRUSTED_PARTS=$APT_ETC/$(get_apt_config_value Dir::Etc::trustedparts)
CODE_TRUSTED_PART=$APT_TRUSTED_PARTS/microsoft.gpg
# Sourced from https://packages.microsoft.com/keys/microsoft.asc
if [ ! -f $CODE_TRUSTED_PART ]; then
echo "-----BEGIN PGP PUBLIC KEY BLOCK-----
Version: GnuPG v1.4.7 (GNU/Linux)
mQENBFYxWIwBCADAKoZhZlJxGNGWzqV+1OG1xiQeoowKhssGAKvd+buXCGISZJwT
LXZqIcIiLP7pqdcZWtE9bSc7yBY2MalDp9Liu0KekywQ6VVX1T72NPf5Ev6x6DLV
7aVWsCzUAF+eb7DC9fPuFLEdxmOEYoPjzrQ7cCnSV4JQxAqhU4T6OjbvRazGl3ag
OeizPXmRljMtUUttHQZnRhtlzkmwIrUivbfFPD+fEoHJ1+uIdfOzZX8/oKHKLe2j
H632kvsNzJFlROVvGLYAk2WRcLu+RjjggixhwiB+Mu/A8Tf4V6b+YppS44q8EvVr
M+QvY7LNSOffSO6Slsy9oisGTdfE39nC7pVRABEBAAG0N01pY3Jvc29mdCAoUmVs
ZWFzZSBzaWduaW5nKSA8Z3Bnc2VjdXJpdHlAbWljcm9zb2Z0LmNvbT6JATUEEwEC
AB8FAlYxWIwCGwMGCwkIBwMCBBUCCAMDFgIBAh4BAheAAAoJEOs+lK2+EinPGpsH
/32vKy29Hg51H9dfFJMx0/a/F+5vKeCeVqimvyTM04C+XENNuSbYZ3eRPHGHFLqe
MNGxsfb7C7ZxEeW7J/vSzRgHxm7ZvESisUYRFq2sgkJ+HFERNrqfci45bdhmrUsy
7SWw9ybxdFOkuQoyKD3tBmiGfONQMlBaOMWdAsic965rvJsd5zYaZZFI1UwTkFXV
KJt3bp3Ngn1vEYXwijGTa+FXz6GLHueJwF0I7ug34DgUkAFvAs8Hacr2DRYxL5RJ
XdNgj4Jd2/g6T9InmWT0hASljur+dJnzNiNCkbn9KbX7J/qK1IbR8y560yRmFsU+
NdCFTW7wY0Fb1fWJ+/KTsC4=
=J6gs
-----END PGP PUBLIC KEY BLOCK-----
" | gpg --dearmor > microsoft.gpg
mv microsoft.gpg $CODE_TRUSTED_PART
fi
# Install repository source list if it does not already exist
if [ ! -f $CODE_SOURCE_PART ]; then
echo "deb [arch=amd64] https://packages.microsoft.com/repos/vscode stable main" > $CODE_SOURCE_PART
fi
fi

View file

@ -34,6 +34,10 @@ set ELECTRON_ENABLE_LOGGING=1
set ELECTRON_ENABLE_STACK_DUMPING=1
:: Launch Code
:: Use the following to get v8 tracing:
:: %CODE% --js-flags="--trace-hydrogen --trace-phase=Z --trace-deopt --code-comments --hydrogen-track-positions --redirect-code-traces" . %*
%CODE% . %*
popd

View file

@ -10,7 +10,7 @@ import { onUnexpectedError } from 'vs/base/common/errors';
import { EventEmitter } from 'vs/base/common/eventEmitter';
import { Disposable, IDisposable } from 'vs/base/common/lifecycle';
import { isObject } from 'vs/base/common/types';
import { isChrome, isWebKit } from 'vs/base/browser/browser';
import * as browser from 'vs/base/browser/browser';
import { IKeyboardEvent, StandardKeyboardEvent } from 'vs/base/browser/keyboardEvent';
import { IMouseEvent, StandardMouseEvent } from 'vs/base/browser/mouseEvent';
import { CharCode } from 'vs/base/common/charCode';
@ -211,6 +211,7 @@ export function addDisposableListener(node: Element | Window | Document, type: s
export interface IAddStandardDisposableListenerSignature {
(node: HTMLElement, type: 'click', handler: (event: IMouseEvent) => void, useCapture?: boolean): IDisposable;
(node: HTMLElement, type: 'mousedown', handler: (event: IMouseEvent) => void, useCapture?: boolean): IDisposable;
(node: HTMLElement, type: 'keydown', handler: (event: IKeyboardEvent) => void, useCapture?: boolean): IDisposable;
(node: HTMLElement, type: 'keypress', handler: (event: IKeyboardEvent) => void, useCapture?: boolean): IDisposable;
(node: HTMLElement, type: 'keyup', handler: (event: IKeyboardEvent) => void, useCapture?: boolean): IDisposable;
@ -229,7 +230,7 @@ function _wrapAsStandardKeyboardEvent(handler: (e: IKeyboardEvent) => void): (e:
export let addStandardDisposableListener: IAddStandardDisposableListenerSignature = function addStandardDisposableListener(node: HTMLElement, type: string, handler: (event: any) => void, useCapture?: boolean): IDisposable {
let wrapHandler = handler;
if (type === 'click') {
if (type === 'click' || type === 'mousedown') {
wrapHandler = _wrapAsStandardMouseEvent(handler);
} else if (type === 'keydown' || type === 'keypress' || type === 'keyup') {
wrapHandler = _wrapAsStandardKeyboardEvent(handler);
@ -377,21 +378,7 @@ class AnimationFrameQueueItem implements IDisposable {
if (!animFrameRequested) {
animFrameRequested = true;
// TODO@Alex: also check if it is electron
if (isChrome) {
let handle: number;
_animationFrame.request(function () {
clearTimeout(handle);
animationFrameRunner();
});
// This is a fallback in-case chrome dropped
// the request for an animation frame. This
// is sick but was spotted in the wild
handle = setTimeout(animationFrameRunner, 1000);
} else {
_animationFrame.request(animationFrameRunner);
}
_animationFrame.request(animationFrameRunner);
}
return item;
@ -797,9 +784,9 @@ export const EventType = {
DROP: 'drop',
DRAG_END: 'dragend',
// Animation
ANIMATION_START: isWebKit ? 'webkitAnimationStart' : 'animationstart',
ANIMATION_END: isWebKit ? 'webkitAnimationEnd' : 'animationend',
ANIMATION_ITERATION: isWebKit ? 'webkitAnimationIteration' : 'animationiteration'
ANIMATION_START: browser.isWebKit ? 'webkitAnimationStart' : 'animationstart',
ANIMATION_END: browser.isWebKit ? 'webkitAnimationEnd' : 'animationend',
ANIMATION_ITERATION: browser.isWebKit ? 'webkitAnimationIteration' : 'animationiteration'
};
export interface EventLike {

View file

@ -6,9 +6,9 @@
import * as dom from 'vs/base/browser/dom';
export abstract class FastDomNode {
export abstract class FastDomNode<T extends HTMLElement> {
private _domNode: HTMLElement;
private _domNode: T;
private _maxWidth: number;
private _width: number;
private _height: number;
@ -26,11 +26,11 @@ export abstract class FastDomNode {
private _visibility: string;
private _transform: string;
public get domNode(): HTMLElement {
public get domNode(): T {
return this._domNode;
}
constructor(domNode: HTMLElement) {
constructor(domNode: T) {
this._domNode = domNode;
this._maxWidth = -1;
this._width = -1;
@ -183,21 +183,21 @@ export abstract class FastDomNode {
this._setTransform(this._domNode, this._transform);
}
protected abstract _setTransform(domNode: HTMLElement, transform: string): void;
protected abstract _setTransform(domNode: T, transform: string): void;
public setAttribute(name: string, value: string): void {
this._domNode.setAttribute(name, value);
}
}
class WebKitFastDomNode extends FastDomNode {
protected _setTransform(domNode: HTMLElement, transform: string): void {
class WebKitFastDomNode<T extends HTMLElement> extends FastDomNode<T> {
protected _setTransform(domNode: T, transform: string): void {
(<any>domNode.style).webkitTransform = transform;
}
}
class StandardFastDomNode extends FastDomNode {
protected _setTransform(domNode: HTMLElement, transform: string): void {
class StandardFastDomNode<T extends HTMLElement> extends FastDomNode<T> {
protected _setTransform(domNode: T, transform: string): void {
domNode.style.transform = transform;
}
}
@ -209,7 +209,7 @@ let useWebKitFastDomNode = false;
useWebKitFastDomNode = true;
}
})();
export function createFastDomNode(domNode: HTMLElement): FastDomNode {
export function createFastDomNode<T extends HTMLElement>(domNode: T): FastDomNode<T> {
if (useWebKitFastDomNode) {
return new WebKitFastDomNode(domNode);
} else {

View file

@ -48,12 +48,12 @@ export abstract class AbstractScrollbar extends Widget {
protected _host: ScrollbarHost;
protected _scrollable: Scrollable;
private _lazyRender: boolean;
private _scrollbarState: ScrollbarState;
protected _scrollbarState: ScrollbarState;
private _visibilityController: ScrollbarVisibilityController;
private _mouseMoveMonitor: GlobalMouseMoveMonitor<IStandardMouseMoveEventData>;
public domNode: FastDomNode;
public slider: FastDomNode;
public domNode: FastDomNode<HTMLElement>;
public slider: FastDomNode<HTMLElement>;
protected _shouldRender: boolean;

View file

@ -37,9 +37,9 @@ export class ScrollableElement extends Widget {
private _horizontalScrollbar: HorizontalScrollbar;
private _domNode: HTMLElement;
private _leftShadowDomNode: FastDomNode;
private _topShadowDomNode: FastDomNode;
private _topLeftShadowDomNode: FastDomNode;
private _leftShadowDomNode: FastDomNode<HTMLElement>;
private _topShadowDomNode: FastDomNode<HTMLElement>;
private _topLeftShadowDomNode: FastDomNode<HTMLElement>;
private _listenOnDomNode: HTMLElement;
@ -145,6 +145,10 @@ export class ScrollableElement extends Widget {
this._verticalScrollbar.delegateMouseDown(browserEvent);
}
public getVerticalSliderVerticalCenter(): number {
return this._verticalScrollbar.getVerticalSliderVerticalCenter();
}
public updateState(newState: INewScrollState): void {
this._scrollable.updateState(newState);
}
@ -365,7 +369,9 @@ export class ScrollableElement extends Widget {
}
private _scheduleHide(): void {
this._hideTimeout.cancelAndSet(() => this._hide(), HIDE_TIMEOUT);
if (!this._mouseIsOver && !this._isDragging) {
this._hideTimeout.cancelAndSet(() => this._hide(), HIDE_TIMEOUT);
}
}
}

View file

@ -171,6 +171,10 @@ export class ScrollbarState {
return this._computedSliderPosition;
}
public getSliderCenter(): number {
return (this._computedSliderPosition + this._computedSliderSize / 2);
}
public convertSliderPositionToScrollPosition(desiredSliderPosition: number): number {
return desiredSliderPosition / this._computedRatio;
}

View file

@ -13,7 +13,7 @@ export class ScrollbarVisibilityController extends Disposable {
private _visibility: ScrollbarVisibility;
private _visibleClassName: string;
private _invisibleClassName: string;
private _domNode: FastDomNode;
private _domNode: FastDomNode<HTMLElement>;
private _shouldBeVisible: boolean;
private _isNeeded: boolean;
private _isVisible: boolean;
@ -59,7 +59,7 @@ export class ScrollbarVisibilityController extends Disposable {
}
}
public setDomNode(domNode: FastDomNode): void {
public setDomNode(domNode: FastDomNode<HTMLElement>): void {
this._domNode = domNode;
this._domNode.setClassName(this._invisibleClassName);

View file

@ -60,6 +60,10 @@ export class VerticalScrollbar extends AbstractScrollbar {
this._createSlider(0, Math.floor((options.verticalScrollbarSize - options.verticalSliderSize) / 2), options.verticalSliderSize, null);
}
public getVerticalSliderVerticalCenter(): number {
return this._scrollbarState.getSliderCenter();
}
protected _updateSlider(sliderSize: number, sliderPosition: number): void {
this.slider.setHeight(sliderSize);
if (this._canUseTranslate3d) {

View file

@ -3,27 +3,161 @@
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import * as Object from 'vs/base/common/objects';
import { CharCode } from 'vs/base/common/charCode';
export interface RGBA { r: number; g: number; b: number; a: number; }
export interface HSLA { h: number; s: number; l: number; a: number; }
export class RGBA {
_rgbaBrand: void;
/**
* Red: integer in [0-255]
*/
public readonly r: number;
/**
* Green: integer in [0-255]
*/
public readonly g: number;
/**
* Blue: integer in [0-255]
*/
public readonly b: number;
/**
* Alpha: integer in [0-255]
*/
public readonly a: number;
constructor(r: number, g: number, b: number, a: number) {
this.r = RGBA._clampInt_0_255(r);
this.g = RGBA._clampInt_0_255(g);
this.b = RGBA._clampInt_0_255(b);
this.a = RGBA._clampInt_0_255(a);
}
public static equals(a: RGBA, b: RGBA): boolean {
return (
a.r === b.r
&& a.g === b.g
&& a.b === b.b
&& a.a === b.a
);
}
private static _clampInt_0_255(c: number): number {
if (c < 0) {
return 0;
}
if (c > 255) {
return 255;
}
return c | 0;
}
}
/**
* http://en.wikipedia.org/wiki/HSL_color_space
*/
export class HSLA {
_hslaBrand: void;
/**
* Hue: float in [0, 360]
*/
public readonly h: number;
/**
* Saturation: float in [0, 1]
*/
public readonly s: number;
/**
* Luminosity: float in [0, 1]
*/
public readonly l: number;
/**
* Alpha: float in [0, 1]
*/
public readonly a: number;
constructor(h: number, s: number, l: number, a: number) {
this.h = HSLA._clampFloat_0_360(h);
this.s = HSLA._clampFloat_0_1(s);
this.l = HSLA._clampFloat_0_1(l);
this.a = HSLA._clampFloat_0_1(a);
}
private static _clampFloat_0_360(hue: number): number {
if (hue < 0) {
return 0.0;
}
if (hue > 360) {
return 360.0;
}
return hue;
}
private static _clampFloat_0_1(n: number): number {
if (n < 0) {
return 0.0;
}
if (n > 1) {
return 1.0;
}
return n;
}
}
/**
* Converts an Hex color value to RGB.
* returns r, g, and b are contained in the set [0, 255]
* @param hex string (#RRGGBB or #RRGGBBAA).
*/
function hex2rgba(hex: string): RGBA {
function parseHex(str: string) {
return parseInt('0x' + str);
if (!hex) {
// Invalid color
return new RGBA(255, 0, 0, 255);
}
if (hex.charAt(0) === '#' && hex.length >= 7) {
let r = parseHex(hex.substr(1, 2));
let g = parseHex(hex.substr(3, 2));
let b = parseHex(hex.substr(5, 2));
let a = hex.length === 9 ? parseHex(hex.substr(7, 2)) / 0xff : 1;
return { r, g, b, a };
if (hex.length === 7 && hex.charCodeAt(0) === CharCode.Hash) {
// #RRGGBB format
const r = 16 * _parseHexDigit(hex.charCodeAt(1)) + _parseHexDigit(hex.charCodeAt(2));
const g = 16 * _parseHexDigit(hex.charCodeAt(3)) + _parseHexDigit(hex.charCodeAt(4));
const b = 16 * _parseHexDigit(hex.charCodeAt(5)) + _parseHexDigit(hex.charCodeAt(6));
return new RGBA(r, g, b, 255);
}
return { r: 255, g: 0, b: 0, a: 1 };
if (hex.length === 9 && hex.charCodeAt(0) === CharCode.Hash) {
// #RRGGBBAA format
const r = 16 * _parseHexDigit(hex.charCodeAt(1)) + _parseHexDigit(hex.charCodeAt(2));
const g = 16 * _parseHexDigit(hex.charCodeAt(3)) + _parseHexDigit(hex.charCodeAt(4));
const b = 16 * _parseHexDigit(hex.charCodeAt(5)) + _parseHexDigit(hex.charCodeAt(6));
const a = 16 * _parseHexDigit(hex.charCodeAt(7)) + _parseHexDigit(hex.charCodeAt(8));
return new RGBA(r, g, b, a);
}
// Invalid color
return new RGBA(255, 0, 0, 255);
}
function _parseHexDigit(charCode: CharCode): number {
switch (charCode) {
case CharCode.Digit0: return 0;
case CharCode.Digit1: return 1;
case CharCode.Digit2: return 2;
case CharCode.Digit3: return 3;
case CharCode.Digit4: return 4;
case CharCode.Digit5: return 5;
case CharCode.Digit6: return 6;
case CharCode.Digit7: return 7;
case CharCode.Digit8: return 8;
case CharCode.Digit9: return 9;
case CharCode.a: return 10;
case CharCode.A: return 10;
case CharCode.b: return 11;
case CharCode.B: return 11;
case CharCode.c: return 12;
case CharCode.C: return 12;
case CharCode.d: return 13;
case CharCode.D: return 13;
case CharCode.e: return 14;
case CharCode.E: return 14;
case CharCode.f: return 15;
case CharCode.F: return 15;
}
return 0;
}
/**
@ -33,13 +167,17 @@ function hex2rgba(hex: string): RGBA {
* returns h in the set [0, 360], s, and l in the set [0, 1].
*/
function rgba2hsla(rgba: RGBA): HSLA {
let r = rgba.r / 255;
let g = rgba.g / 255;
let b = rgba.b / 255;
let a = rgba.a === void 0 ? rgba.a : 1;
const r = rgba.r / 255;
const g = rgba.g / 255;
const b = rgba.b / 255;
const a = rgba.a / 255;
let max = Math.max(r, g, b), min = Math.min(r, g, b);
let h = 0, s = 0, l = Math.round(((min + max) / 2) * 1000) / 1000, chroma = max - min;
const max = Math.max(r, g, b);
const min = Math.min(r, g, b);
let h = 0;
let s = 0;
const l = Math.round(((min + max) / 2) * 1000) / 1000;
const chroma = max - min;
if (chroma > 0) {
s = Math.min(Math.round((l <= 0.5 ? chroma / (2 * l) : chroma / (2 - (2 * l))) * 1000) / 1000, 1);
@ -51,7 +189,7 @@ function rgba2hsla(rgba: RGBA): HSLA {
h *= 60;
h = Math.round(h);
}
return { h, s, l, a };
return new HSLA(h, s, l, a);
}
/**
@ -61,160 +199,53 @@ function rgba2hsla(rgba: RGBA): HSLA {
* returns r, g, and b in the set [0, 255].
*/
function hsla2rgba(hsla: HSLA): RGBA {
let h = hsla.h / 360;
let s = Math.min(hsla.s, 1);
let l = Math.min(hsla.l, 1);
let a = hsla.a === void 0 ? hsla.a : 1;
const h = hsla.h / 360;
const s = Math.min(hsla.s, 1);
const l = Math.min(hsla.l, 1);
const a = hsla.a;
let r: number, g: number, b: number;
if (s === 0) {
r = g = b = l; // achromatic
} else {
let hue2rgb = function hue2rgb(p: number, q: number, t: number) {
if (t < 0) {
t += 1;
}
if (t > 1) {
t -= 1;
}
if (t < 1 / 6) {
return p + (q - p) * 6 * t;
}
if (t < 1 / 2) {
return q;
}
if (t < 2 / 3) {
return p + (q - p) * (2 / 3 - t) * 6;
}
return p;
};
let q = l < 0.5 ? l * (1 + s) : l + s - l * s;
let p = 2 * l - q;
r = hue2rgb(p, q, h + 1 / 3);
g = hue2rgb(p, q, h);
b = hue2rgb(p, q, h - 1 / 3);
const q = l < 0.5 ? l * (1 + s) : l + s - l * s;
const p = 2 * l - q;
r = _hue2rgb(p, q, h + 1 / 3);
g = _hue2rgb(p, q, h);
b = _hue2rgb(p, q, h - 1 / 3);
}
return { r: Math.round(r * 255), g: Math.round(g * 255), b: Math.round(b * 255), a };
return new RGBA(Math.round(r * 255), Math.round(g * 255), Math.round(b * 255), Math.round(a * 255));
}
function _hue2rgb(p: number, q: number, t: number) {
if (t < 0) {
t += 1;
}
if (t > 1) {
t -= 1;
}
if (t < 1 / 6) {
return p + (q - p) * 6 * t;
}
if (t < 1 / 2) {
return q;
}
if (t < 2 / 3) {
return p + (q - p) * (2 / 3 - t) * 6;
}
return p;
}
export class Color {
private rgba: RGBA;
private hsla: HSLA;
private str: string;
constructor(arg: string | RGBA) {
this.rgba = typeof arg === 'string' ? hex2rgba(arg) : <RGBA>arg;
this.str = null;
}
/**
* http://www.w3.org/TR/WCAG20/#relativeluminancedef
* Returns the number in the set [0, 1]. O => Darkest Black. 1 => Lightest white.
*/
public getLuminosity(): number {
let luminosityFor = function (color: number): number {
let c = color / 255;
return (c <= 0.03928) ? c / 12.92 : Math.pow(((c + 0.055) / 1.055), 2.4);
};
let R = luminosityFor(this.rgba.r);
let G = luminosityFor(this.rgba.g);
let B = luminosityFor(this.rgba.b);
let luminosity = 0.2126 * R + 0.7152 * G + 0.0722 * B;
return Math.round(luminosity * 10000) / 10000;
}
/**
* http://www.w3.org/TR/WCAG20/#contrast-ratiodef
* Returns the contrast ration number in the set [1, 21].
*/
public getContrast(another: Color): number {
let lum1 = this.getLuminosity();
let lum2 = another.getLuminosity();
return lum1 > lum2 ? (lum1 + 0.05) / (lum2 + 0.05) : (lum2 + 0.05) / (lum1 + 0.05);
}
/**
* http://24ways.org/2010/calculating-color-contrast
* Return 'true' if darker color otherwise 'false'
*/
public isDarker(): boolean {
var yiq = (this.rgba.r * 299 + this.rgba.g * 587 + this.rgba.b * 114) / 1000;
return yiq < 128;
}
/**
* http://24ways.org/2010/calculating-color-contrast
* Return 'true' if lighter color otherwise 'false'
*/
public isLighter(): boolean {
var yiq = (this.rgba.r * 299 + this.rgba.g * 587 + this.rgba.b * 114) / 1000;
return yiq >= 128;
}
public isLighterThan(another: Color): boolean {
let lum1 = this.getLuminosity();
let lum2 = another.getLuminosity();
return lum1 > lum2;
}
public isDarkerThan(another: Color): boolean {
let lum1 = this.getLuminosity();
let lum2 = another.getLuminosity();
return lum1 < lum2;
}
public lighten(factor: number): Color {
let hsl = this.toHSLA();
hsl.l += hsl.l * factor;
return new Color(hsla2rgba(hsl));
}
public darken(factor: number): Color {
let hsl = this.toHSLA();
hsl.l -= hsl.l * factor;
return new Color(hsla2rgba(hsl));
}
public transparent(factor: number): Color {
let p = this.rgba;
return new Color({ r: p.r, g: p.g, b: p.b, a: p.a * factor });
}
public opposite(): Color {
return new Color({
r: 255 - this.rgba.r,
g: 255 - this.rgba.g,
b: 255 - this.rgba.b,
a: this.rgba.a
});
}
public toString(): string {
if (!this.str) {
let p = this.rgba;
this.str = `rgba(${p.r}, ${p.g}, ${p.b}, ${+p.a.toFixed(2)})`;
}
return this.str;
}
public toHSLA(): HSLA {
if (!this.hsla) {
this.hsla = rgba2hsla(this.rgba);
}
return Object.clone(this.hsla);
}
public toRGBA(): RGBA {
return Object.clone(this.rgba);
}
public static fromRGBA(rgba: RGBA): Color {
return new Color(rgba);
}
/**
* Creates a color from a hex string (#RRGGBB or #RRGGBBAA).
*/
public static fromHex(hex: string): Color {
return new Color(hex);
}
@ -223,12 +254,155 @@ export class Color {
return new Color(hsla2rgba(hsla));
}
private readonly rgba: RGBA;
private hsla: HSLA;
private constructor(arg: string | RGBA) {
if (arg instanceof RGBA) {
this.rgba = arg;
} else {
this.rgba = hex2rgba(arg);
}
this.hsla = null;
}
public equals(other: Color): boolean {
if (!other) {
return false;
}
return RGBA.equals(this.rgba, other.rgba);
}
/**
* http://www.w3.org/TR/WCAG20/#relativeluminancedef
* Returns the number in the set [0, 1]. O => Darkest Black. 1 => Lightest white.
*/
public getLuminosity(): number {
const R = Color._luminosityFor(this.rgba.r);
const G = Color._luminosityFor(this.rgba.g);
const B = Color._luminosityFor(this.rgba.b);
const luminosity = 0.2126 * R + 0.7152 * G + 0.0722 * B;
return Math.round(luminosity * 10000) / 10000;
}
private static _luminosityFor(color: number): number {
const c = color / 255;
return (c <= 0.03928) ? c / 12.92 : Math.pow(((c + 0.055) / 1.055), 2.4);
}
/**
* http://www.w3.org/TR/WCAG20/#contrast-ratiodef
* Returns the contrast ration number in the set [1, 21].
*/
public getContrast(another: Color): number {
const lum1 = this.getLuminosity();
const lum2 = another.getLuminosity();
return lum1 > lum2 ? (lum1 + 0.05) / (lum2 + 0.05) : (lum2 + 0.05) / (lum1 + 0.05);
}
/**
* http://24ways.org/2010/calculating-color-contrast
* Return 'true' if darker color otherwise 'false'
*/
public isDarker(): boolean {
const yiq = (this.rgba.r * 299 + this.rgba.g * 587 + this.rgba.b * 114) / 1000;
return yiq < 128;
}
/**
* http://24ways.org/2010/calculating-color-contrast
* Return 'true' if lighter color otherwise 'false'
*/
public isLighter(): boolean {
const yiq = (this.rgba.r * 299 + this.rgba.g * 587 + this.rgba.b * 114) / 1000;
return yiq >= 128;
}
public isLighterThan(another: Color): boolean {
const lum1 = this.getLuminosity();
const lum2 = another.getLuminosity();
return lum1 > lum2;
}
public isDarkerThan(another: Color): boolean {
const lum1 = this.getLuminosity();
const lum2 = another.getLuminosity();
return lum1 < lum2;
}
public lighten(factor: number): Color {
const hsl = this.toHSLA();
const result = new HSLA(hsl.h, hsl.s, hsl.l + hsl.l * factor, hsl.a);
return new Color(hsla2rgba(result));
}
public darken(factor: number): Color {
const hsl = this.toHSLA();
const result = new HSLA(hsl.h, hsl.s, hsl.l - hsl.l * factor, hsl.a);
return new Color(hsla2rgba(result));
}
public transparent(factor: number): Color {
const p = this.rgba;
return new Color(new RGBA(p.r, p.g, p.b, Math.round(p.a * factor)));
}
public opposite(): Color {
return new Color(new RGBA(
255 - this.rgba.r,
255 - this.rgba.g,
255 - this.rgba.b,
this.rgba.a
));
}
public toString(): string {
const rgba = this.rgba;
return `rgba(${rgba.r}, ${rgba.g}, ${rgba.b}, ${+(rgba.a / 255).toFixed(2)})`;
}
/**
* Prins the color as #RRGGBB
*/
public toRGBHex(): string {
const rgba = this.rgba;
return `#${Color._toTwoDigitHex(rgba.r)}${Color._toTwoDigitHex(rgba.g)}${Color._toTwoDigitHex(rgba.b)}`;
}
/**
* Prins the color as #RRGGBBAA
*/
public toRGBAHex(): string {
const rgba = this.rgba;
return `#${Color._toTwoDigitHex(rgba.r)}${Color._toTwoDigitHex(rgba.g)}${Color._toTwoDigitHex(rgba.b)}${Color._toTwoDigitHex(rgba.a)}`;
}
private static _toTwoDigitHex(n: number): string {
let r = n.toString(16);
if (r.length !== 2) {
return '0' + r;
}
return r;
}
public toHSLA(): HSLA {
if (this.hsla === null) {
this.hsla = rgba2hsla(this.rgba);
}
return this.hsla;
}
public toRGBA(): RGBA {
return this.rgba;
}
public static getLighterColor(of: Color, relative: Color, factor?: number): Color {
if (of.isLighterThan(relative)) {
return of;
}
factor = factor ? factor : 0.5;
let lum1 = of.getLuminosity(), lum2 = relative.getLuminosity();
const lum1 = of.getLuminosity();
const lum2 = relative.getLuminosity();
factor = factor * (lum2 - lum1) / lum2;
return of.lighten(factor);
}
@ -238,8 +412,9 @@ export class Color {
return of;
}
factor = factor ? factor : 0.5;
let lum1 = of.getLuminosity(), lum2 = relative.getLuminosity();
const lum1 = of.getLuminosity();
const lum2 = relative.getLuminosity();
factor = factor * (lum1 - lum2) / lum1;
return of.darken(factor);
}
}
}

View file

@ -63,7 +63,7 @@ export function setProperty(text: string, path: JSONPath, value: any, formatting
}
} else {
if (value === void 0) { // delete
throw new Error(`Property ${lastSegment} does not exist.`);
return []; // property does not exist, nothing to do
}
let newProperty = `${JSON.stringify(lastSegment)}: ${JSON.stringify(value)}`;
let index = getInsertionIndex ? getInsertionIndex(parent.children.map(p => p.children[0].value)) : parent.children.length;

View file

@ -88,42 +88,83 @@ export function shorten(paths: string[]): string[] {
// for every path
let match = false;
for (let pathIndex = 0; pathIndex < paths.length; pathIndex++) {
const path = paths[pathIndex];
let path = paths[pathIndex];
if (path === '') {
shortenedPaths[pathIndex] = '.';
continue;
}
if (!path) {
shortenedPaths[pathIndex] = path;
continue;
}
match = true;
let prefix = '';
const unc = nativeSep + nativeSep;
// trim for now and concatenate unc path (e.g. \\network) or root path (/etc) later
if (path.indexOf(unc) === 0) {
prefix = path.substr(0, path.indexOf(unc) + 2);
path = path.substr(path.indexOf(unc) + 2);
} else if (path.indexOf(nativeSep) === 0) {
prefix = path.substr(0, path.indexOf(nativeSep) + 1);
path = path.substr(path.indexOf(nativeSep) + 1);
}
// pick the first shortest subpath found
if (typeof path === 'string') { // protect against paths which are not provided if any
const segments: string[] = path.split(nativeSep);
for (let subpathLength = 1; match && subpathLength <= segments.length; subpathLength++) {
for (let start = segments.length - subpathLength; match && start >= 0; start--) {
match = false;
const subpath = segments.slice(start, start + subpathLength).join(nativeSep);
const segments: string[] = path.split(nativeSep);
for (let subpathLength = 1; match && subpathLength <= segments.length; subpathLength++) {
for (let start = segments.length - subpathLength; match && start >= 0; start--) {
match = false;
let subpath = segments.slice(start, start + subpathLength).join(nativeSep);
// that is unique to any other path
for (let otherPathIndex = 0; !match && otherPathIndex < paths.length; otherPathIndex++) {
// that is unique to any other path
for (let otherPathIndex = 0; !match && otherPathIndex < paths.length; otherPathIndex++) {
// suffix subpath treated specially as we consider no match 'x' and 'x/...'
if (otherPathIndex !== pathIndex && paths[otherPathIndex] && paths[otherPathIndex].indexOf(subpath) > -1) {
const isSubpathEnding: boolean = (start + subpathLength === segments.length);
const isOtherPathEnding: boolean = endsWith(paths[otherPathIndex], subpath);
// suffix subpath treated specially as we consider no match 'x' and 'x/...'
if (otherPathIndex !== pathIndex && paths[otherPathIndex] && paths[otherPathIndex].indexOf(subpath) > -1) {
const isSubpathEnding: boolean = (start + subpathLength === segments.length);
const isOtherPathEnding: boolean = endsWith(paths[otherPathIndex], subpath);
match = !isSubpathEnding || isOtherPathEnding;
}
match = !isSubpathEnding || isOtherPathEnding;
}
}
// found unique subpath
if (!match) {
let result = subpath;
if (start + subpathLength < segments.length) {
result = result + nativeSep + ellipsis;
// found unique subpath
if (!match) {
let result = '';
// preserve disk drive or root prefix
if (endsWith(segments[0], ':') || prefix !== '') {
if (start === 1) {
// extend subpath to include disk drive prefix
start = 0;
subpathLength++;
subpath = segments[0] + nativeSep + subpath;
}
if (start > 0) {
result = ellipsis + nativeSep + result;
result = segments[0] + nativeSep;
}
shortenedPaths[pathIndex] = result;
result = prefix + result;
}
// add ellipsis at the beginning if neeeded
if (start > 0) {
result = result + ellipsis + nativeSep;
}
result = result + subpath;
// add ellipsis at the end if needed
if (start + subpathLength < segments.length) {
result = result + nativeSep + ellipsis;
}
shortenedPaths[pathIndex] = result;
}
}
}

View file

@ -148,6 +148,8 @@ export class DefaultController implements _.IController {
this.downKeyBindingDispatcher.set(KeyCode.RightArrow, (t, e) => this.onRight(t, e));
if (platform.isMacintosh) {
this.downKeyBindingDispatcher.set(KeyMod.CtrlCmd | KeyCode.UpArrow, (t, e) => this.onLeft(t, e));
this.downKeyBindingDispatcher.set(KeyMod.WinCtrl | KeyCode.KEY_N, (t, e) => this.onDown(t, e));
this.downKeyBindingDispatcher.set(KeyMod.WinCtrl | KeyCode.KEY_P, (t, e) => this.onUp(t, e));
}
this.downKeyBindingDispatcher.set(KeyCode.PageUp, (t, e) => this.onPageUp(t, e));
this.downKeyBindingDispatcher.set(KeyCode.PageDown, (t, e) => this.onPageDown(t, e));

View file

@ -5,82 +5,112 @@
'use strict';
import { Color } from 'vs/base/common/color';
import * as assert from 'assert';
import { Color, RGBA, HSLA } from 'vs/base/common/color';
suite('Color', () => {
test('rgba2hsla', function () {
assert.deepEqual({ h: 0, s: 0, l: 0, a: 1 }, Color.fromRGBA({ r: 0, g: 0, b: 0, a: 1 }).toHSLA());
assert.deepEqual({ h: 0, s: 0, l: 1, a: 1 }, Color.fromRGBA({ r: 255, g: 255, b: 255, a: 1 }).toHSLA());
assert.deepEqual(new HSLA(0, 0, 0, 1), Color.fromRGBA(new RGBA(0, 0, 0, 255)).toHSLA());
assert.deepEqual(new HSLA(0, 0, 1, 1), Color.fromRGBA(new RGBA(255, 255, 255, 255)).toHSLA());
assert.deepEqual({ h: 0, s: 1, l: 0.5, a: 1 }, Color.fromRGBA({ r: 255, g: 0, b: 0, a: 1 }).toHSLA());
assert.deepEqual({ h: 120, s: 1, l: 0.5, a: 1 }, Color.fromRGBA({ r: 0, g: 255, b: 0, a: 1 }).toHSLA());
assert.deepEqual({ h: 240, s: 1, l: 0.5, a: 1 }, Color.fromRGBA({ r: 0, g: 0, b: 255, a: 1 }).toHSLA());
assert.deepEqual(new HSLA(0, 1, 0.5, 1), Color.fromRGBA(new RGBA(255, 0, 0, 255)).toHSLA());
assert.deepEqual(new HSLA(120, 1, 0.5, 1), Color.fromRGBA(new RGBA(0, 255, 0, 255)).toHSLA());
assert.deepEqual(new HSLA(240, 1, 0.5, 1), Color.fromRGBA(new RGBA(0, 0, 255, 255)).toHSLA());
assert.deepEqual({ h: 60, s: 1, l: 0.5, a: 1 }, Color.fromRGBA({ r: 255, g: 255, b: 0, a: 1 }).toHSLA());
assert.deepEqual({ h: 180, s: 1, l: 0.5, a: 1 }, Color.fromRGBA({ r: 0, g: 255, b: 255, a: 1 }).toHSLA());
assert.deepEqual({ h: 300, s: 1, l: 0.5, a: 1 }, Color.fromRGBA({ r: 255, g: 0, b: 255, a: 1 }).toHSLA());
assert.deepEqual(new HSLA(60, 1, 0.5, 1), Color.fromRGBA(new RGBA(255, 255, 0, 255)).toHSLA());
assert.deepEqual(new HSLA(180, 1, 0.5, 1), Color.fromRGBA(new RGBA(0, 255, 255, 255)).toHSLA());
assert.deepEqual(new HSLA(300, 1, 0.5, 1), Color.fromRGBA(new RGBA(255, 0, 255, 255)).toHSLA());
assert.deepEqual({ h: 0, s: 0, l: 0.753, a: 1 }, Color.fromRGBA({ r: 192, g: 192, b: 192, a: 1 }).toHSLA());
assert.deepEqual(new HSLA(0, 0, 0.753, 1), Color.fromRGBA(new RGBA(192, 192, 192, 255)).toHSLA());
assert.deepEqual({ h: 0, s: 0, l: 0.502, a: 1 }, Color.fromRGBA({ r: 128, g: 128, b: 128, a: 1 }).toHSLA());
assert.deepEqual({ h: 0, s: 1, l: 0.251, a: 1 }, Color.fromRGBA({ r: 128, g: 0, b: 0, a: 1 }).toHSLA());
assert.deepEqual({ h: 60, s: 1, l: 0.251, a: 1 }, Color.fromRGBA({ r: 128, g: 128, b: 0, a: 1 }).toHSLA());
assert.deepEqual({ h: 120, s: 1, l: 0.251, a: 1 }, Color.fromRGBA({ r: 0, g: 128, b: 0, a: 1 }).toHSLA());
assert.deepEqual({ h: 300, s: 1, l: 0.251, a: 1 }, Color.fromRGBA({ r: 128, g: 0, b: 128, a: 1 }).toHSLA());
assert.deepEqual({ h: 180, s: 1, l: 0.251, a: 1 }, Color.fromRGBA({ r: 0, g: 128, b: 128, a: 1 }).toHSLA());
assert.deepEqual({ h: 240, s: 1, l: 0.251, a: 1 }, Color.fromRGBA({ r: 0, g: 0, b: 128, a: 1 }).toHSLA());
assert.deepEqual(new HSLA(0, 0, 0.502, 1), Color.fromRGBA(new RGBA(128, 128, 128, 255)).toHSLA());
assert.deepEqual(new HSLA(0, 1, 0.251, 1), Color.fromRGBA(new RGBA(128, 0, 0, 255)).toHSLA());
assert.deepEqual(new HSLA(60, 1, 0.251, 1), Color.fromRGBA(new RGBA(128, 128, 0, 255)).toHSLA());
assert.deepEqual(new HSLA(120, 1, 0.251, 1), Color.fromRGBA(new RGBA(0, 128, 0, 255)).toHSLA());
assert.deepEqual(new HSLA(300, 1, 0.251, 1), Color.fromRGBA(new RGBA(128, 0, 128, 255)).toHSLA());
assert.deepEqual(new HSLA(180, 1, 0.251, 1), Color.fromRGBA(new RGBA(0, 128, 128, 255)).toHSLA());
assert.deepEqual(new HSLA(240, 1, 0.251, 1), Color.fromRGBA(new RGBA(0, 0, 128, 255)).toHSLA());
});
test('hsla2rgba', function () {
assert.deepEqual({ r: 0, g: 0, b: 0, a: 1 }, Color.fromHSLA({ h: 0, s: 0, l: 0, a: 1 }).toRGBA());
assert.deepEqual({ r: 255, g: 255, b: 255, a: 1 }, Color.fromHSLA({ h: 0, s: 0, l: 1, a: 1 }).toRGBA());
assert.deepEqual(new RGBA(0, 0, 0, 255), Color.fromHSLA(new HSLA(0, 0, 0, 1)).toRGBA());
assert.deepEqual(new RGBA(255, 255, 255, 255), Color.fromHSLA(new HSLA(0, 0, 1, 1)).toRGBA());
assert.deepEqual({ r: 255, g: 0, b: 0, a: 1 }, Color.fromHSLA({ h: 0, s: 1, l: 0.5, a: 1 }).toRGBA());
assert.deepEqual({ r: 0, g: 255, b: 0, a: 1 }, Color.fromHSLA({ h: 120, s: 1, l: 0.5, a: 1 }).toRGBA());
assert.deepEqual({ r: 0, g: 0, b: 255, a: 1 }, Color.fromHSLA({ h: 240, s: 1, l: 0.5, a: 1 }).toRGBA());
assert.deepEqual(new RGBA(255, 0, 0, 255), Color.fromHSLA(new HSLA(0, 1, 0.5, 1)).toRGBA());
assert.deepEqual(new RGBA(0, 255, 0, 255), Color.fromHSLA(new HSLA(120, 1, 0.5, 1)).toRGBA());
assert.deepEqual(new RGBA(0, 0, 255, 255), Color.fromHSLA(new HSLA(240, 1, 0.5, 1)).toRGBA());
assert.deepEqual({ r: 255, g: 255, b: 0, a: 1 }, Color.fromHSLA({ h: 60, s: 1, l: 0.5, a: 1 }).toRGBA());
assert.deepEqual({ r: 0, g: 255, b: 255, a: 1 }, Color.fromHSLA({ h: 180, s: 1, l: 0.5, a: 1 }).toRGBA());
assert.deepEqual({ r: 255, g: 0, b: 255, a: 1 }, Color.fromHSLA({ h: 300, s: 1, l: 0.5, a: 1 }).toRGBA());
assert.deepEqual(new RGBA(255, 255, 0, 255), Color.fromHSLA(new HSLA(60, 1, 0.5, 1)).toRGBA());
assert.deepEqual(new RGBA(0, 255, 255, 255), Color.fromHSLA(new HSLA(180, 1, 0.5, 1)).toRGBA());
assert.deepEqual(new RGBA(255, 0, 255, 255), Color.fromHSLA(new HSLA(300, 1, 0.5, 1)).toRGBA());
assert.deepEqual({ r: 192, g: 192, b: 192, a: 1 }, Color.fromHSLA({ h: 0, s: 0, l: 0.753, a: 1 }).toRGBA());
assert.deepEqual(new RGBA(192, 192, 192, 255), Color.fromHSLA(new HSLA(0, 0, 0.753, 1)).toRGBA());
assert.deepEqual({ r: 128, g: 128, b: 128, a: 1 }, Color.fromHSLA({ h: 0, s: 0, l: 0.502, a: 1 }).toRGBA());
assert.deepEqual({ r: 128, g: 0, b: 0, a: 1 }, Color.fromHSLA({ h: 0, s: 1, l: 0.251, a: 1 }).toRGBA());
assert.deepEqual({ r: 128, g: 128, b: 0, a: 1 }, Color.fromHSLA({ h: 60, s: 1, l: 0.251, a: 1 }).toRGBA());
assert.deepEqual({ r: 0, g: 128, b: 0, a: 1 }, Color.fromHSLA({ h: 120, s: 1, l: 0.251, a: 1 }).toRGBA());
assert.deepEqual({ r: 128, g: 0, b: 128, a: 1 }, Color.fromHSLA({ h: 300, s: 1, l: 0.251, a: 1 }).toRGBA());
assert.deepEqual({ r: 0, g: 128, b: 128, a: 1 }, Color.fromHSLA({ h: 180, s: 1, l: 0.251, a: 1 }).toRGBA());
assert.deepEqual({ r: 0, g: 0, b: 128, a: 1 }, Color.fromHSLA({ h: 240, s: 1, l: 0.251, a: 1 }).toRGBA());
assert.deepEqual(new RGBA(128, 128, 128, 255), Color.fromHSLA(new HSLA(0, 0, 0.502, 1)).toRGBA());
assert.deepEqual(new RGBA(128, 0, 0, 255), Color.fromHSLA(new HSLA(0, 1, 0.251, 1)).toRGBA());
assert.deepEqual(new RGBA(128, 128, 0, 255), Color.fromHSLA(new HSLA(60, 1, 0.251, 1)).toRGBA());
assert.deepEqual(new RGBA(0, 128, 0, 255), Color.fromHSLA(new HSLA(120, 1, 0.251, 1)).toRGBA());
assert.deepEqual(new RGBA(128, 0, 128, 255), Color.fromHSLA(new HSLA(300, 1, 0.251, 1)).toRGBA());
assert.deepEqual(new RGBA(0, 128, 128, 255), Color.fromHSLA(new HSLA(180, 1, 0.251, 1)).toRGBA());
assert.deepEqual(new RGBA(0, 0, 128, 255), Color.fromHSLA(new HSLA(240, 1, 0.251, 1)).toRGBA());
});
test('hex2rgba', function () {
assert.deepEqual({ r: 0, g: 0, b: 0, a: 1 }, Color.fromHex('#000000').toRGBA());
assert.deepEqual({ r: 255, g: 255, b: 255, a: 1 }, Color.fromHex('#FFFFFF').toRGBA());
assert.deepEqual(new RGBA(0, 0, 0, 255), Color.fromHex('#000000').toRGBA());
assert.deepEqual(new RGBA(255, 255, 255, 255), Color.fromHex('#FFFFFF').toRGBA());
assert.deepEqual({ r: 255, g: 0, b: 0, a: 1 }, Color.fromHex('#FF0000').toRGBA());
assert.deepEqual({ r: 0, g: 255, b: 0, a: 1 }, Color.fromHex('#00FF00').toRGBA());
assert.deepEqual({ r: 0, g: 0, b: 255, a: 1 }, Color.fromHex('#0000FF').toRGBA());
assert.deepEqual(new RGBA(255, 0, 0, 255), Color.fromHex('#FF0000').toRGBA());
assert.deepEqual(new RGBA(0, 255, 0, 255), Color.fromHex('#00FF00').toRGBA());
assert.deepEqual(new RGBA(0, 0, 255, 255), Color.fromHex('#0000FF').toRGBA());
assert.deepEqual({ r: 255, g: 255, b: 0, a: 1 }, Color.fromHex('#FFFF00').toRGBA());
assert.deepEqual({ r: 0, g: 255, b: 255, a: 1 }, Color.fromHex('#00FFFF').toRGBA());
assert.deepEqual({ r: 255, g: 0, b: 255, a: 1 }, Color.fromHex('#FF00FF').toRGBA());
assert.deepEqual(new RGBA(255, 255, 0, 255), Color.fromHex('#FFFF00').toRGBA());
assert.deepEqual(new RGBA(0, 255, 255, 255), Color.fromHex('#00FFFF').toRGBA());
assert.deepEqual(new RGBA(255, 0, 255, 255), Color.fromHex('#FF00FF').toRGBA());
assert.deepEqual({ r: 192, g: 192, b: 192, a: 1 }, Color.fromHex('#C0C0C0').toRGBA());
assert.deepEqual(new RGBA(192, 192, 192, 255), Color.fromHex('#C0C0C0').toRGBA());
assert.deepEqual({ r: 128, g: 128, b: 128, a: 1 }, Color.fromHex('#808080').toRGBA());
assert.deepEqual({ r: 128, g: 0, b: 0, a: 1 }, Color.fromHex('#800000').toRGBA());
assert.deepEqual({ r: 128, g: 128, b: 0, a: 1 }, Color.fromHex('#808000').toRGBA());
assert.deepEqual({ r: 0, g: 128, b: 0, a: 1 }, Color.fromHex('#008000').toRGBA());
assert.deepEqual({ r: 128, g: 0, b: 128, a: 1 }, Color.fromHex('#800080').toRGBA());
assert.deepEqual({ r: 0, g: 128, b: 128, a: 1 }, Color.fromHex('#008080').toRGBA());
assert.deepEqual({ r: 0, g: 0, b: 128, a: 1 }, Color.fromHex('#000080').toRGBA());
assert.deepEqual(new RGBA(128, 128, 128, 255), Color.fromHex('#808080').toRGBA());
assert.deepEqual(new RGBA(128, 0, 0, 255), Color.fromHex('#800000').toRGBA());
assert.deepEqual(new RGBA(128, 128, 0, 255), Color.fromHex('#808000').toRGBA());
assert.deepEqual(new RGBA(0, 128, 0, 255), Color.fromHex('#008000').toRGBA());
assert.deepEqual(new RGBA(128, 0, 128, 255), Color.fromHex('#800080').toRGBA());
assert.deepEqual(new RGBA(0, 128, 128, 255), Color.fromHex('#008080').toRGBA());
assert.deepEqual(new RGBA(0, 0, 128, 255), Color.fromHex('#000080').toRGBA());
function assertParseColor(input: string, expected: RGBA): void {
let actual = Color.fromHex(input).toRGBA();
assert.deepEqual(actual, expected, input);
}
// invalid
assertParseColor(null, new RGBA(255, 0, 0, 255));
assertParseColor('', new RGBA(255, 0, 0, 255));
assertParseColor('#', new RGBA(255, 0, 0, 255));
assertParseColor('#0102030', new RGBA(255, 0, 0, 255));
// somewhat valid
assertParseColor('#FFFFG0', new RGBA(255, 255, 0, 255));
assertParseColor('#FFFFg0', new RGBA(255, 255, 0, 255));
assertParseColor('#-FFF00', new RGBA(15, 255, 0, 255));
// valid
assertParseColor('#000000', new RGBA(0, 0, 0, 255));
assertParseColor('#010203', new RGBA(1, 2, 3, 255));
assertParseColor('#040506', new RGBA(4, 5, 6, 255));
assertParseColor('#070809', new RGBA(7, 8, 9, 255));
assertParseColor('#0a0A0a', new RGBA(10, 10, 10, 255));
assertParseColor('#0b0B0b', new RGBA(11, 11, 11, 255));
assertParseColor('#0c0C0c', new RGBA(12, 12, 12, 255));
assertParseColor('#0d0D0d', new RGBA(13, 13, 13, 255));
assertParseColor('#0e0E0e', new RGBA(14, 14, 14, 255));
assertParseColor('#0f0F0f', new RGBA(15, 15, 15, 255));
assertParseColor('#a0A0a0', new RGBA(160, 160, 160, 255));
assertParseColor('#FFFFFF', new RGBA(255, 255, 255, 255));
});
test('isLighterColor', function () {
let color1 = Color.fromHSLA({ h: 60, s: 1, l: 0.5, a: 1 }), color2 = Color.fromHSLA({ h: 0, s: 0, l: 0.753, a: 1 });
let color1 = Color.fromHSLA(new HSLA(60, 1, 0.5, 1)), color2 = Color.fromHSLA(new HSLA(0, 0, 0.753, 1));
assert.ok(color1.isLighterThan(color2));
@ -89,80 +119,80 @@ suite('Color', () => {
});
test('getLighterColor', function () {
let color1 = Color.fromHSLA({ h: 60, s: 1, l: 0.5, a: 1 }), color2 = Color.fromHSLA({ h: 0, s: 0, l: 0.753, a: 1 });
let color1 = Color.fromHSLA(new HSLA(60, 1, 0.5, 1)), color2 = Color.fromHSLA(new HSLA(0, 0, 0.753, 1));
assert.deepEqual(color1.toHSLA(), Color.getLighterColor(color1, color2).toHSLA());
assert.deepEqual({ h: 0, s: 0, l: 0.914, a: 1 }, Color.getLighterColor(color2, color1).toHSLA());
assert.deepEqual({ h: 0, s: 0, l: 0.851, a: 1 }, Color.getLighterColor(color2, color1, 0.3).toHSLA());
assert.deepEqual({ h: 0, s: 0, l: 0.98, a: 1 }, Color.getLighterColor(color2, color1, 0.7).toHSLA());
assert.deepEqual({ h: 0, s: 0, l: 1, a: 1 }, Color.getLighterColor(color2, color1, 1).toHSLA());
assert.deepEqual(new HSLA(0, 0, 0.914, 1), Color.getLighterColor(color2, color1).toHSLA());
assert.deepEqual(new HSLA(0, 0, 0.851, 1), Color.getLighterColor(color2, color1, 0.3).toHSLA());
assert.deepEqual(new HSLA(0, 0, 0.98, 1), Color.getLighterColor(color2, color1, 0.7).toHSLA());
assert.deepEqual(new HSLA(0, 0, 1, 1), Color.getLighterColor(color2, color1, 1).toHSLA());
});
test('isDarkerColor', function () {
let color1 = Color.fromHSLA({ h: 60, s: 1, l: 0.5, a: 1 }), color2 = Color.fromHSLA({ h: 0, s: 0, l: 0.753, a: 1 });
let color1 = Color.fromHSLA(new HSLA(60, 1, 0.5, 1)), color2 = Color.fromHSLA(new HSLA(0, 0, 0.753, 1));
assert.ok(color2.isDarkerThan(color1));
});
test('getDarkerColor', function () {
let color1 = Color.fromHSLA({ h: 60, s: 1, l: 0.5, a: 1 }), color2 = Color.fromHSLA({ h: 0, s: 0, l: 0.753, a: 1 });
let color1 = Color.fromHSLA(new HSLA(60, 1, 0.5, 1)), color2 = Color.fromHSLA(new HSLA(0, 0, 0.753, 1));
assert.deepEqual(color2.toHSLA(), Color.getDarkerColor(color2, color1).toHSLA());
assert.deepEqual({ h: 60, s: 1, l: 0.392, a: 1 }, Color.getDarkerColor(color1, color2).toHSLA());
assert.deepEqual({ h: 60, s: 1, l: 0.435, a: 1 }, Color.getDarkerColor(color1, color2, 0.3).toHSLA());
assert.deepEqual({ h: 60, s: 1, l: 0.349, a: 1 }, Color.getDarkerColor(color1, color2, 0.7).toHSLA());
assert.deepEqual({ h: 60, s: 1, l: 0.284, a: 1 }, Color.getDarkerColor(color1, color2, 1).toHSLA());
assert.deepEqual(new HSLA(60, 1, 0.392, 1), Color.getDarkerColor(color1, color2).toHSLA());
assert.deepEqual(new HSLA(60, 1, 0.435, 1), Color.getDarkerColor(color1, color2, 0.3).toHSLA());
assert.deepEqual(new HSLA(60, 1, 0.349, 1), Color.getDarkerColor(color1, color2, 0.7).toHSLA());
assert.deepEqual(new HSLA(60, 1, 0.284, 1), Color.getDarkerColor(color1, color2, 1).toHSLA());
// Abyss theme
assert.deepEqual({ h: 355, s: 0.874, l: 0.157, a: 1 }, Color.getDarkerColor(Color.fromHex('#770811'), Color.fromHex('#000c18'), 0.4).toHSLA());
assert.deepEqual(new HSLA(355, 0.874, 0.157, 1), Color.getDarkerColor(Color.fromHex('#770811'), Color.fromHex('#000c18'), 0.4).toHSLA());
});
test('luminosity', function () {
assert.deepEqual(0, Color.fromRGBA({ r: 0, g: 0, b: 0, a: 1 }).getLuminosity());
assert.deepEqual(1, Color.fromRGBA({ r: 255, g: 255, b: 255, a: 1 }).getLuminosity());
assert.deepEqual(0, Color.fromRGBA(new RGBA(0, 0, 0, 255)).getLuminosity());
assert.deepEqual(1, Color.fromRGBA(new RGBA(255, 255, 255, 255)).getLuminosity());
assert.deepEqual(0.2126, Color.fromRGBA({ r: 255, g: 0, b: 0, a: 1 }).getLuminosity());
assert.deepEqual(0.7152, Color.fromRGBA({ r: 0, g: 255, b: 0, a: 1 }).getLuminosity());
assert.deepEqual(0.0722, Color.fromRGBA({ r: 0, g: 0, b: 255, a: 1 }).getLuminosity());
assert.deepEqual(0.2126, Color.fromRGBA(new RGBA(255, 0, 0, 255)).getLuminosity());
assert.deepEqual(0.7152, Color.fromRGBA(new RGBA(0, 255, 0, 255)).getLuminosity());
assert.deepEqual(0.0722, Color.fromRGBA(new RGBA(0, 0, 255, 255)).getLuminosity());
assert.deepEqual(0.9278, Color.fromRGBA({ r: 255, g: 255, b: 0, a: 1 }).getLuminosity());
assert.deepEqual(0.7874, Color.fromRGBA({ r: 0, g: 255, b: 255, a: 1 }).getLuminosity());
assert.deepEqual(0.2848, Color.fromRGBA({ r: 255, g: 0, b: 255, a: 1 }).getLuminosity());
assert.deepEqual(0.9278, Color.fromRGBA(new RGBA(255, 255, 0, 255)).getLuminosity());
assert.deepEqual(0.7874, Color.fromRGBA(new RGBA(0, 255, 255, 255)).getLuminosity());
assert.deepEqual(0.2848, Color.fromRGBA(new RGBA(255, 0, 255, 255)).getLuminosity());
assert.deepEqual(0.5271, Color.fromRGBA({ r: 192, g: 192, b: 192, a: 1 }).getLuminosity());
assert.deepEqual(0.5271, Color.fromRGBA(new RGBA(192, 192, 192, 255)).getLuminosity());
assert.deepEqual(0.2159, Color.fromRGBA({ r: 128, g: 128, b: 128, a: 1 }).getLuminosity());
assert.deepEqual(0.0459, Color.fromRGBA({ r: 128, g: 0, b: 0, a: 1 }).getLuminosity());
assert.deepEqual(0.2003, Color.fromRGBA({ r: 128, g: 128, b: 0, a: 1 }).getLuminosity());
assert.deepEqual(0.1544, Color.fromRGBA({ r: 0, g: 128, b: 0, a: 1 }).getLuminosity());
assert.deepEqual(0.0615, Color.fromRGBA({ r: 128, g: 0, b: 128, a: 1 }).getLuminosity());
assert.deepEqual(0.17, Color.fromRGBA({ r: 0, g: 128, b: 128, a: 1 }).getLuminosity());
assert.deepEqual(0.0156, Color.fromRGBA({ r: 0, g: 0, b: 128, a: 1 }).getLuminosity());
assert.deepEqual(0.2159, Color.fromRGBA(new RGBA(128, 128, 128, 255)).getLuminosity());
assert.deepEqual(0.0459, Color.fromRGBA(new RGBA(128, 0, 0, 255)).getLuminosity());
assert.deepEqual(0.2003, Color.fromRGBA(new RGBA(128, 128, 0, 255)).getLuminosity());
assert.deepEqual(0.1544, Color.fromRGBA(new RGBA(0, 128, 0, 255)).getLuminosity());
assert.deepEqual(0.0615, Color.fromRGBA(new RGBA(128, 0, 128, 255)).getLuminosity());
assert.deepEqual(0.17, Color.fromRGBA(new RGBA(0, 128, 128, 255)).getLuminosity());
assert.deepEqual(0.0156, Color.fromRGBA(new RGBA(0, 0, 128, 255)).getLuminosity());
});
test('contrast', function () {
assert.deepEqual(0, Color.fromRGBA({ r: 0, g: 0, b: 0, a: 1 }).getLuminosity());
assert.deepEqual(1, Color.fromRGBA({ r: 255, g: 255, b: 255, a: 1 }).getLuminosity());
assert.deepEqual(0, Color.fromRGBA(new RGBA(0, 0, 0, 255)).getLuminosity());
assert.deepEqual(1, Color.fromRGBA(new RGBA(255, 255, 255, 255)).getLuminosity());
assert.deepEqual(0.2126, Color.fromRGBA({ r: 255, g: 0, b: 0, a: 1 }).getLuminosity());
assert.deepEqual(0.7152, Color.fromRGBA({ r: 0, g: 255, b: 0, a: 1 }).getLuminosity());
assert.deepEqual(0.0722, Color.fromRGBA({ r: 0, g: 0, b: 255, a: 1 }).getLuminosity());
assert.deepEqual(0.2126, Color.fromRGBA(new RGBA(255, 0, 0, 255)).getLuminosity());
assert.deepEqual(0.7152, Color.fromRGBA(new RGBA(0, 255, 0, 255)).getLuminosity());
assert.deepEqual(0.0722, Color.fromRGBA(new RGBA(0, 0, 255, 255)).getLuminosity());
assert.deepEqual(0.9278, Color.fromRGBA({ r: 255, g: 255, b: 0, a: 1 }).getLuminosity());
assert.deepEqual(0.7874, Color.fromRGBA({ r: 0, g: 255, b: 255, a: 1 }).getLuminosity());
assert.deepEqual(0.2848, Color.fromRGBA({ r: 255, g: 0, b: 255, a: 1 }).getLuminosity());
assert.deepEqual(0.9278, Color.fromRGBA(new RGBA(255, 255, 0, 255)).getLuminosity());
assert.deepEqual(0.7874, Color.fromRGBA(new RGBA(0, 255, 255, 255)).getLuminosity());
assert.deepEqual(0.2848, Color.fromRGBA(new RGBA(255, 0, 255, 255)).getLuminosity());
assert.deepEqual(0.5271, Color.fromRGBA({ r: 192, g: 192, b: 192, a: 1 }).getLuminosity());
assert.deepEqual(0.5271, Color.fromRGBA(new RGBA(192, 192, 192, 255)).getLuminosity());
assert.deepEqual(0.2159, Color.fromRGBA({ r: 128, g: 128, b: 128, a: 1 }).getLuminosity());
assert.deepEqual(0.0459, Color.fromRGBA({ r: 128, g: 0, b: 0, a: 1 }).getLuminosity());
assert.deepEqual(0.2003, Color.fromRGBA({ r: 128, g: 128, b: 0, a: 1 }).getLuminosity());
assert.deepEqual(0.1544, Color.fromRGBA({ r: 0, g: 128, b: 0, a: 1 }).getLuminosity());
assert.deepEqual(0.0615, Color.fromRGBA({ r: 128, g: 0, b: 128, a: 1 }).getLuminosity());
assert.deepEqual(0.17, Color.fromRGBA({ r: 0, g: 128, b: 128, a: 1 }).getLuminosity());
assert.deepEqual(0.0156, Color.fromRGBA({ r: 0, g: 0, b: 128, a: 1 }).getLuminosity());
assert.deepEqual(0.2159, Color.fromRGBA(new RGBA(128, 128, 128, 255)).getLuminosity());
assert.deepEqual(0.0459, Color.fromRGBA(new RGBA(128, 0, 0, 255)).getLuminosity());
assert.deepEqual(0.2003, Color.fromRGBA(new RGBA(128, 128, 0, 255)).getLuminosity());
assert.deepEqual(0.1544, Color.fromRGBA(new RGBA(0, 128, 0, 255)).getLuminosity());
assert.deepEqual(0.0615, Color.fromRGBA(new RGBA(128, 0, 128, 255)).getLuminosity());
assert.deepEqual(0.17, Color.fromRGBA(new RGBA(0, 128, 128, 255)).getLuminosity());
assert.deepEqual(0.0156, Color.fromRGBA(new RGBA(0, 0, 128, 255)).getLuminosity());
});
});

View file

@ -42,6 +42,9 @@ suite('JSON - edits', () => {
content = '{\n "x": "y"\n}';
edits = setProperty(content, ['x'], { key: true }, formatterOptions);
assertEdit(content, edits, '{\n "x": {\n "key": true\n }\n}');
content = '{\n "a": "b", "x": "y"\n}';
edits = setProperty(content, ['a'], null, formatterOptions);
assertEdit(content, edits, '{\n "a": null, "x": "y"\n}');
});
test('insert property', () => {
@ -64,6 +67,10 @@ suite('JSON - edits', () => {
edits = setProperty(content, ['foo'], 'bar', formatterOptions);
assertEdit(content, edits, '{\n "x": "y",\n "foo": "bar"\n}');
content = '{\n "x": "y"\n}';
edits = setProperty(content, ['e'], 'null', formatterOptions);
assertEdit(content, edits, '{\n "x": "y",\n "e": "null"\n}');
edits = setProperty(content, ['x'], 'bar', formatterOptions);
assertEdit(content, edits, '{\n "x": "bar"\n}');

View file

@ -28,8 +28,8 @@ suite('Labels', () => {
assert.deepEqual(labels.shorten(['a', 'a\\b']), ['a', '…\\b']);
assert.deepEqual(labels.shorten(['a\\b', 'a\\b\\c']), ['…\\b', '…\\c']);
assert.deepEqual(labels.shorten(['a', 'a\\b', 'a\\b\\c']), ['a', '…\\b', '…\\c']);
assert.deepEqual(labels.shorten(['x:\\a\\b', 'x:\\a\\c']), ['…\\b', '…\\c'], 'TODO: drive letter (or schema) should be preserved');
assert.deepEqual(labels.shorten(['\\\\a\\b', '\\\\a\\c']), ['…\\b', '…\\c'], 'TODO: root uri should be preserved');
assert.deepEqual(labels.shorten(['x:\\a\\b', 'x:\\a\\c']), ['x:\\…\\b', 'x:\\…\\c']);
assert.deepEqual(labels.shorten(['\\\\a\\b', '\\\\a\\c']), ['\\\\a\\b', '\\\\a\\c']);
// same ending
assert.deepEqual(labels.shorten(['a', 'b\\a']), ['a', 'b\\…']);
@ -39,9 +39,13 @@ suite('Labels', () => {
assert.deepEqual(labels.shorten(['a\\b\\c\\d', 'a\\f\\b\\c\\d']), ['a\\b\\…', '…\\f\\…']);
assert.deepEqual(labels.shorten(['a\\b\\a', 'b\\b\\a']), ['a\\b\\…', 'b\\b\\…']);
assert.deepEqual(labels.shorten(['d\\f\\a\\b\\c', 'h\\d\\b\\c']), ['…\\a\\…', 'h\\…']);
assert.deepEqual(labels.shorten(['a\\b\\c', 'x:\\0\\a\\b\\c']), ['a\\b\\c', '…\\0\\…'], 'TODO: drive letter (or schema) should be always preserved');
assert.deepEqual(labels.shorten(['a\\b\\c', 'x:\\0\\a\\b\\c']), ['a\\b\\c', 'x:\\0\\…']);
assert.deepEqual(labels.shorten(['x:\\a\\b\\c', 'x:\\0\\a\\b\\c']), ['x:\\a\\…', 'x:\\0\\…']);
assert.deepEqual(labels.shorten(['x:\\a\\b', 'y:\\a\\b']), ['x:\\…', 'y:\\…']);
assert.deepEqual(labels.shorten(['\\\\x\\b', '\\\\y\\b']), ['…\\x\\…', '…\\y\\…'], 'TODO: \\\\x instead of …\\x');
assert.deepEqual(labels.shorten(['x:\\a', 'x:\\c']), ['x:\\a', 'x:\\c']);
assert.deepEqual(labels.shorten(['x:\\a\\b', 'y:\\x\\a\\b']), ['x:\\…', 'y:\\…']);
assert.deepEqual(labels.shorten(['\\\\x\\b', '\\\\y\\b']), ['\\\\x\\…', '\\\\y\\…']);
assert.deepEqual(labels.shorten(['\\\\x\\a', '\\\\x\\b']), ['\\\\x\\a', '\\\\x\\b']);
// same in the middle
assert.deepEqual(labels.shorten(['a\\b\\c', 'd\\b\\e']), ['…\\c', '…\\e']);
@ -49,9 +53,12 @@ suite('Labels', () => {
// case-sensetive
assert.deepEqual(labels.shorten(['a\\b\\c', 'd\\b\\C']), ['…\\c', '…\\C']);
// empty or null
assert.deepEqual(labels.shorten(['', null]), ['.', null]);
assert.deepEqual(labels.shorten(['a', 'a\\b', 'a\\b\\c', 'd\\b\\c', 'd\\b']), ['a', 'a\\b', 'a\\b\\c', 'd\\b\\c', 'd\\b']);
assert.deepEqual(labels.shorten(['a', 'a\\b', 'b']), ['a', 'a\\b', 'b']);
assert.deepEqual(labels.shorten(['', 'a', 'b', 'b\\c', 'a\\c']), ['', 'a', 'b', 'b\\c', 'a\\c']);
assert.deepEqual(labels.shorten(['', 'a', 'b', 'b\\c', 'a\\c']), ['.', 'a', 'b', 'b\\c', 'a\\c']);
assert.deepEqual(labels.shorten(['src\\vs\\workbench\\parts\\execution\\electron-browser', 'src\\vs\\workbench\\parts\\execution\\electron-browser\\something', 'src\\vs\\workbench\\parts\\terminal\\electron-browser']), ['…\\execution\\electron-browser', '…\\something', '…\\terminal\\…']);
});
@ -73,8 +80,7 @@ suite('Labels', () => {
assert.deepEqual(labels.shorten(['a', 'a/b']), ['a', '…/b']);
assert.deepEqual(labels.shorten(['a/b', 'a/b/c']), ['…/b', '…/c']);
assert.deepEqual(labels.shorten(['a', 'a/b', 'a/b/c']), ['a', '…/b', '…/c']);
assert.deepEqual(labels.shorten(['x:/a/b', 'x:/a/c']), ['…/b', '…/c'], 'TODO: drive letter (or schema) should be preserved');
assert.deepEqual(labels.shorten(['//a/b', '//a/c']), ['…/b', '…/c'], 'TODO: root uri should be preserved');
assert.deepEqual(labels.shorten(['/a/b', '/a/c']), ['/a/b', '/a/c']);
// same ending
assert.deepEqual(labels.shorten(['a', 'b/a']), ['a', 'b/…']);
@ -84,9 +90,7 @@ suite('Labels', () => {
assert.deepEqual(labels.shorten(['a/b/c/d', 'a/f/b/c/d']), ['a/b/…', '…/f/…']);
assert.deepEqual(labels.shorten(['a/b/a', 'b/b/a']), ['a/b/…', 'b/b/…']);
assert.deepEqual(labels.shorten(['d/f/a/b/c', 'h/d/b/c']), ['…/a/…', 'h/…']);
assert.deepEqual(labels.shorten(['a/b/c', 'x:/0/a/b/c']), ['a/b/c', '…/0/…'], 'TODO: drive letter (or schema) should be always preserved');
assert.deepEqual(labels.shorten(['x:/a/b', 'y:/a/b']), ['x:/…', 'y:/…']);
assert.deepEqual(labels.shorten(['//x/b', '//y/b']), ['…/x/…', '…/y/…'], 'TODO: //x instead of …/x');
assert.deepEqual(labels.shorten(['/x/b', '/y/b']), ['/x/…', '/y/…']);
// same in the middle
assert.deepEqual(labels.shorten(['a/b/c', 'd/b/e']), ['…/c', '…/e']);
@ -94,9 +98,12 @@ suite('Labels', () => {
// case-sensitive
assert.deepEqual(labels.shorten(['a/b/c', 'd/b/C']), ['…/c', '…/C']);
// empty or null
assert.deepEqual(labels.shorten(['', null]), ['.', null]);
assert.deepEqual(labels.shorten(['a', 'a/b', 'a/b/c', 'd/b/c', 'd/b']), ['a', 'a/b', 'a/b/c', 'd/b/c', 'd/b']);
assert.deepEqual(labels.shorten(['a', 'a/b', 'b']), ['a', 'a/b', 'b']);
assert.deepEqual(labels.shorten(['', 'a', 'b', 'b/c', 'a/c']), ['', 'a', 'b', 'b/c', 'a/c']);
assert.deepEqual(labels.shorten(['', 'a', 'b', 'b/c', 'a/c']), ['.', 'a', 'b', 'b/c', 'a/c']);
});
test('template', function () {

View file

@ -136,7 +136,7 @@ export interface IVSCodeWindow {
export class VSCodeWindow implements IVSCodeWindow {
public static baseThemeStorageKey = 'baseTheme';
public static themeStorageKey = 'theme';
private static MIN_WIDTH = 200;
private static MIN_HEIGHT = 120;
@ -179,7 +179,7 @@ export class VSCodeWindow implements IVSCodeWindow {
this.restoreWindowState(config.state);
// For VS theme we can show directly because background is white
const baseTheme = this.storageService.getItem<string>(VSCodeWindow.baseThemeStorageKey);
const baseTheme = this.getBaseTheme();
const usesLightTheme = 'vs' === baseTheme;
const usesHighContrastTheme = 'hc-black' === baseTheme || (platform.isWindows && systemPreferences.isInvertedColorScheme());
@ -507,9 +507,8 @@ export class VSCodeWindow implements IVSCodeWindow {
windowConfiguration.highContrast = platform.isWindows && systemPreferences.isInvertedColorScheme() && (!windowConfig || windowConfig.autoDetectHighContrast);
windowConfiguration.accessibilitySupport = app.isAccessibilitySupportEnabled();
// background color
const baseTheme = this.storageService.getItem<string>(VSCodeWindow.baseThemeStorageKey, 'vs-dark');
windowConfiguration.baseTheme = baseTheme;
// Theme
windowConfiguration.baseTheme = this.getBaseTheme();
// Perf Counters
windowConfiguration.perfStartTime = global.perfStartTime;
@ -530,6 +529,11 @@ export class VSCodeWindow implements IVSCodeWindow {
return url;
}
private getBaseTheme(): string {
const theme = this.storageService.getItem<string>(VSCodeWindow.themeStorageKey, 'vs-dark');
return theme.split(' ')[0];
}
public serializeWindowState(): IWindowState {
if (this.win.isFullScreen()) {
return {

View file

@ -274,8 +274,8 @@ export class WindowsManager implements IWindowsMainService {
private onBroadcast(event: string, payload: any): void {
// Theme changes
if (event === 'vscode:changeBaseTheme' && typeof payload === 'string') {
this.storageService.setItem(VSCodeWindow.baseThemeStorageKey, payload);
if (event === 'vscode:changeColorTheme' && typeof payload === 'string') {
this.storageService.setItem(VSCodeWindow.themeStorageKey, payload);
}
}
public reload(win: VSCodeWindow, cli?: ParsedArgs): void {

View file

@ -226,7 +226,7 @@ export class Configuration extends CommonEditorConfiguration {
domNode.style.lineHeight = fontInfo.lineHeight + 'px';
}
public static applyFontInfo(domNode: FastDomNode, fontInfo: BareFontInfo): void {
public static applyFontInfo(domNode: FastDomNode<HTMLElement>, fontInfo: BareFontInfo): void {
domNode.setFontFamily(fontInfo.fontFamily);
domNode.setFontWeight(fontInfo.fontWeight);
domNode.setFontSize(fontInfo.fontSize);
@ -292,6 +292,10 @@ export class Configuration extends CommonEditorConfiguration {
return browser.canUseTranslate3d && browser.getZoomLevel() === 0;
}
protected _getPixelRatio(): number {
return browser.getPixelRatio();
}
protected readConfiguration(bareFontInfo: BareFontInfo): FontInfo {
return CSSBasedConfiguration.INSTANCE.readConfiguration(bareFontInfo);
}

View file

@ -29,9 +29,12 @@ class ClipboardEventWrapper implements IClipboardEvent {
return false;
}
public setTextData(text: string): void {
public setTextData(text: string, richText: string): void {
if (this._event.clipboardData) {
this._event.clipboardData.setData('text/plain', text);
if (richText !== null) {
this._event.clipboardData.setData('text/html', richText);
}
this._event.preventDefault();
return;
}

View file

@ -20,6 +20,8 @@ import { Configuration } from 'vs/editor/browser/config/configuration';
import { ViewContext } from 'vs/editor/common/view/viewContext';
import { VisibleRange } from 'vs/editor/common/view/renderingContext';
import { TextAreaWrapper } from 'vs/editor/browser/controller/input/textAreaWrapper';
import * as viewEvents from 'vs/editor/common/view/viewEvents';
import { ScrollEvent } from 'vs/base/common/scrollable';
export interface IKeyboardHandlerHelper {
viewDomNode: HTMLElement;
@ -52,8 +54,8 @@ export class KeyboardHandler extends ViewEventHandler implements IDisposable {
Configuration.applyFontInfoSlow(this.textArea.actual, this._context.configuration.editor.fontInfo);
this.viewHelper = viewHelper;
this.contentLeft = 0;
this.contentWidth = 0;
this.contentLeft = this._context.configuration.editor.layoutInfo.contentLeft;
this.contentWidth = this._context.configuration.editor.layoutInfo.contentWidth;
this.scrollLeft = 0;
this.textAreaHandler = new TextAreaHandler(browser, this._getStrategy(), this.textArea, this._context.model, () => this.viewHelper.flushAnyAccumulatedEvents());
@ -74,13 +76,14 @@ export class KeyboardHandler extends ViewEventHandler implements IDisposable {
let lineNumber = e.showAtLineNumber;
let column = e.showAtColumn;
let revealPositionEvent: editorCommon.IViewRevealRangeEvent = {
let revealPositionEvent: viewEvents.IViewRevealRangeEvent = {
_viewRevealRangeEventBrand: void 0,
range: new Range(lineNumber, column, lineNumber, column),
verticalType: editorCommon.VerticalRevealType.Simple,
revealHorizontal: true,
revealCursor: false
};
this._context.privateViewEventBus.emit(editorCommon.ViewEventNames.RevealRangeEvent, revealPositionEvent);
this._context.privateViewEventBus.emit(viewEvents.ViewEventNames.RevealRangeEvent, revealPositionEvent);
// Find range pixel position
this.visibleRange = this.viewHelper.visibleRangeForPositionRelativeToEditor(lineNumber, column);
@ -168,10 +171,14 @@ export class KeyboardHandler extends ViewEventHandler implements IDisposable {
if (e.viewInfo.experimentalScreenReader) {
this.textAreaHandler.setStrategy(this._getStrategy());
}
if (e.layoutInfo) {
this.contentLeft = this._context.configuration.editor.layoutInfo.contentLeft;
this.contentWidth = this._context.configuration.editor.layoutInfo.contentWidth;
}
return false;
}
public onScrollChanged(e: editorCommon.IScrollEvent): boolean {
public onScrollChanged(e: ScrollEvent): boolean {
this.scrollLeft = e.scrollLeft;
if (this.visibleRange) {
StyleMutator.setTop(this.textArea.actual, this.visibleRange.top);
@ -185,18 +192,12 @@ export class KeyboardHandler extends ViewEventHandler implements IDisposable {
return false;
}
private _lastCursorSelectionChanged: editorCommon.IViewCursorSelectionChangedEvent = null;
public onCursorSelectionChanged(e: editorCommon.IViewCursorSelectionChangedEvent): boolean {
private _lastCursorSelectionChanged: viewEvents.IViewCursorSelectionChangedEvent = null;
public onCursorSelectionChanged(e: viewEvents.IViewCursorSelectionChangedEvent): boolean {
this._lastCursorSelectionChanged = e;
return false;
}
public onLayoutChanged(layoutInfo: editorCommon.EditorLayoutInfo): boolean {
this.contentLeft = layoutInfo.contentLeft;
this.contentWidth = layoutInfo.contentWidth;
return false;
}
public writeToTextArea(): void {
if (this._lastCursorSelectionChanged) {
let e = this._lastCursorSelectionChanged;

View file

@ -21,6 +21,8 @@ import { EditorMouseEventFactory, GlobalEditorMouseMoveMonitor, EditorMouseEvent
import { StandardMouseWheelEvent } from 'vs/base/browser/mouseEvent';
import { EditorZoom } from 'vs/editor/common/config/editorZoom';
import { IViewCursorRenderData } from 'vs/editor/browser/viewParts/viewCursors/viewCursor';
import * as viewEvents from 'vs/editor/common/view/viewEvents';
import { ScrollEvent } from 'vs/base/common/scrollable';
/**
* Merges mouse events when mouse move events are throttled
@ -204,14 +206,11 @@ export class MouseHandler extends ViewEventHandler implements IDisposable {
}
// --- begin event handlers
public onLayoutChanged(layoutInfo: editorCommon.EditorLayoutInfo): boolean {
return false;
}
public onScrollChanged(e: editorCommon.IScrollEvent): boolean {
public onScrollChanged(e: ScrollEvent): boolean {
this._mouseDownOperation.onScrollChanged();
return false;
}
public onCursorSelectionChanged(e: editorCommon.IViewCursorSelectionChangedEvent): boolean {
public onCursorSelectionChanged(e: viewEvents.IViewCursorSelectionChangedEvent): boolean {
this._mouseDownOperation.onCursorSelectionChanged(e);
return false;
}
@ -455,7 +454,7 @@ class MouseDownOperation extends Disposable {
}, 10);
}
public onCursorSelectionChanged(e: editorCommon.IViewCursorSelectionChangedEvent): void {
public onCursorSelectionChanged(e: viewEvents.IViewCursorSelectionChangedEvent): void {
this._currentSelection = e.selection;
}

View file

@ -4,7 +4,7 @@
*--------------------------------------------------------------------------------------------*/
'use strict';
import { Theme, IThemeRule } from 'vs/editor/common/modes/supports/tokenization';
import { Theme, IThemeRule, generateTokensCSSForColorMap } from 'vs/editor/common/modes/supports/tokenization';
import { IStandaloneColorService, BuiltinTheme, ITheme } from 'vs/editor/common/services/standaloneColorService';
import { vs, vs_dark, hc_black } from 'vs/editor/common/standalone/themes';
import * as dom from 'vs/base/browser/dom';
@ -61,18 +61,6 @@ export class StandaloneColorServiceImpl implements IStandaloneColorService {
this.setTheme(VS_THEME_NAME);
}
private static _generateCSS(colorMap: string[]): string {
let rules: string[] = [];
for (let i = 1, len = colorMap.length; i < len; i++) {
let color = colorMap[i];
rules[i] = `.mtk${i} { color: #${color}; }`;
}
rules.push('.mtki { font-style: italic; }');
rules.push('.mtkb { font-weight: bold; }');
rules.push('.mtku { text-decoration: underline; }');
return rules.join('\n');
}
public defineTheme(themeName: string, themeData: ITheme): void {
if (!/^[a-z0-9\-]+$/i.test(themeName) || isBuiltinTheme(themeName)) {
throw new Error('Illegal theme name!');
@ -107,7 +95,7 @@ export class StandaloneColorServiceImpl implements IStandaloneColorService {
this._theme = Theme.createFromRawTheme(themeData.rules);
let colorMap = this._theme.getColorMap();
let cssRules = StandaloneColorServiceImpl._generateCSS(colorMap);
let cssRules = generateTokensCSSForColorMap(colorMap);
this._styleElement.innerHTML = cssRules;
TokenizationRegistry.setColorMap(colorMap);

View file

@ -7,7 +7,7 @@
import { IDisposable } from 'vs/base/common/lifecycle';
import { TPromise } from 'vs/base/common/winjs.base';
import { IModel } from 'vs/editor/common/editorCommon';
import { TokenizationRegistry, ITokenizationSupport } from 'vs/editor/common/modes';
import { ColorId, MetadataConsts, FontStyle, TokenizationRegistry, ITokenizationSupport } from 'vs/editor/common/modes';
import { IModeService } from 'vs/editor/common/services/modeService';
import { renderViewLine, RenderLineInput } from 'vs/editor/common/viewLayout/viewLineRenderer';
import { ViewLineToken } from 'vs/editor/common/core/viewLineToken';
@ -56,7 +56,7 @@ export class Colorizer {
return new TPromise<void>((c, e, p) => {
listener = TokenizationRegistry.onDidChange((e) => {
if (e.languages.indexOf(language) >= 0) {
if (e.changedLanguages.indexOf(language) >= 0) {
stopListening();
c(void 0);
}
@ -126,6 +126,12 @@ function _colorize(lines: string[], tabSize: number, tokenizationSupport: IToken
function _fakeColorize(lines: string[], tabSize: number): string {
let html: string[] = [];
const defaultMetadata = (
(FontStyle.None << MetadataConsts.FONT_STYLE_OFFSET)
| (ColorId.DefaultForeground << MetadataConsts.FOREGROUND_OFFSET)
| (ColorId.DefaultBackground << MetadataConsts.BACKGROUND_OFFSET)
) >>> 0;
for (let i = 0, length = lines.length; i < length; i++) {
let line = lines[i];
@ -134,7 +140,7 @@ function _fakeColorize(lines: string[], tabSize: number): string {
line,
false,
0,
[new ViewLineToken(line.length, '')],
[new ViewLineToken(line.length, defaultMetadata)],
[],
tabSize,
0,
@ -153,12 +159,11 @@ function _fakeColorize(lines: string[], tabSize: number): string {
function _actualColorize(lines: string[], tabSize: number, tokenizationSupport: ITokenizationSupport): string {
let html: string[] = [];
let state = tokenizationSupport.getInitialState();
let colorMap = TokenizationRegistry.getColorMap();
for (let i = 0, length = lines.length; i < length; i++) {
let line = lines[i];
let tokenizeResult = tokenizationSupport.tokenize2(line, state, 0);
let lineTokens = new LineTokens(colorMap, tokenizeResult.tokens, line);
let lineTokens = new LineTokens(tokenizeResult.tokens, line);
let renderResult = renderViewLine(new RenderLineInput(
false,
line,

View file

@ -344,9 +344,11 @@ export function createMonacoEditorAPI(): typeof monaco.editor {
TextEditorCursorBlinkingStyle: editorCommon.TextEditorCursorBlinkingStyle,
ContentWidgetPositionPreference: ContentWidgetPositionPreference,
OverlayWidgetPositionPreference: OverlayWidgetPositionPreference,
RenderMinimap: editorCommon.RenderMinimap,
// classes
InternalEditorScrollbarOptions: <any>editorCommon.InternalEditorScrollbarOptions,
InternalEditorMinimapOptions: <any>editorCommon.InternalEditorMinimapOptions,
EditorWrappingInfo: <any>editorCommon.EditorWrappingInfo,
InternalEditorViewOptions: <any>editorCommon.InternalEditorViewOptions,
EditorContribOptions: <any>editorCommon.EditorContribOptions,

View file

@ -49,6 +49,9 @@ import { IPointerHandlerHelper } from 'vs/editor/browser/controller/mouseHandler
import { ViewOutgoingEvents } from 'vs/editor/browser/view/viewOutgoingEvents';
import { ViewportData } from 'vs/editor/common/viewLayout/viewLinesViewportData';
import { EditorScrollbar } from 'vs/editor/browser/viewParts/editorScrollbar/editorScrollbar';
import { Minimap } from 'vs/editor/browser/viewParts/minimap/minimap';
import * as viewEvents from 'vs/editor/common/view/viewEvents';
import { ScrollEvent } from 'vs/base/common/scrollable';
export class View extends ViewEventHandler implements editorBrowser.IView, IDisposable {
@ -139,6 +142,7 @@ export class View extends ViewEventHandler implements editorBrowser.IView, IDisp
this.createTextArea();
this.createViewParts();
this._setLayout();
// Keyboard handler
this.keyboardHandler = new KeyboardHandler(this._context, viewController, this.createKeyboardHandlerHelper());
@ -270,6 +274,9 @@ export class View extends ViewEventHandler implements editorBrowser.IView, IDisp
let rulers = new Rulers(this._context);
this.viewParts.push(rulers);
let minimap = new Minimap(this._context, this.layoutProvider, this._scrollbar);
this.viewParts.push(minimap);
// -------------- Wire dom nodes up
this.linesContentContainer = this._scrollbar.getScrollbarContainerDomNode();
@ -292,6 +299,7 @@ export class View extends ViewEventHandler implements editorBrowser.IView, IDisp
this.overflowGuardContainer.appendChild(this.overlayWidgets.domNode);
this.overflowGuardContainer.appendChild(this.textArea);
this.overflowGuardContainer.appendChild(this.textAreaCover);
this.overflowGuardContainer.appendChild(minimap.getDomNode());
this.domNode.appendChild(this.overflowGuardContainer);
this.domNode.appendChild(this.contentWidgets.overflowingContentWidgetsDomNode);
}
@ -451,15 +459,16 @@ export class View extends ViewEventHandler implements editorBrowser.IView, IDisp
this.layoutProvider.onModelFlushed(this._context.model.getLineCount());
return false;
}
public onModelLinesDeleted(e: editorCommon.IViewLinesDeletedEvent): boolean {
public onModelLinesDeleted(e: viewEvents.IViewLinesDeletedEvent): boolean {
this.layoutProvider.onModelLinesDeleted(e);
return false;
}
public onModelLinesInserted(e: editorCommon.IViewLinesInsertedEvent): boolean {
public onModelLinesInserted(e: viewEvents.IViewLinesInsertedEvent): boolean {
this.layoutProvider.onModelLinesInserted(e);
return false;
}
public onLayoutChanged(layoutInfo: editorCommon.EditorLayoutInfo): boolean {
private _setLayout(): void {
const layoutInfo = this._context.configuration.editor.layoutInfo;
if (browser.isChrome) {
/* tslint:disable:no-unused-variable */
// Access overflowGuardContainer.clientWidth to prevent relayouting bug in Chrome
@ -477,11 +486,9 @@ export class View extends ViewEventHandler implements editorBrowser.IView, IDisp
StyleMutator.setHeight(this.linesContent, 1000000);
StyleMutator.setLeft(this.linesContentContainer, layoutInfo.contentLeft);
StyleMutator.setWidth(this.linesContentContainer, layoutInfo.contentWidth);
StyleMutator.setWidth(this.linesContentContainer, layoutInfo.contentWidth + layoutInfo.minimapWidth);
StyleMutator.setHeight(this.linesContentContainer, layoutInfo.contentHeight);
this.outgoingEvents.emitViewLayoutChanged(layoutInfo);
return false;
}
public onConfigurationChanged(e: editorCommon.IConfigurationChangedEvent): boolean {
if (e.viewInfo.editorClassName) {
@ -490,10 +497,13 @@ export class View extends ViewEventHandler implements editorBrowser.IView, IDisp
if (e.viewInfo.ariaLabel) {
this.textArea.setAttribute('aria-label', this._context.configuration.editor.viewInfo.ariaLabel);
}
if (e.layoutInfo) {
this._setLayout();
}
this.layoutProvider.onConfigurationChanged(e);
return false;
}
public onScrollChanged(e: editorCommon.IScrollEvent): boolean {
public onScrollChanged(e: ScrollEvent): boolean {
this.outgoingEvents.emitScrollChanged(e);
return false;
}
@ -507,7 +517,7 @@ export class View extends ViewEventHandler implements editorBrowser.IView, IDisp
return false;
}
public onCursorRevealRange(e: editorCommon.IViewRevealRangeEvent): boolean {
public onCursorRevealRange(e: viewEvents.IViewRevealRangeEvent): boolean {
return e.revealCursor ? this.revealCursor() : false;
}
@ -743,7 +753,7 @@ export class View extends ViewEventHandler implements editorBrowser.IView, IDisp
if (zonesHaveChanged) {
this.layoutProvider.onHeightMaybeChanged();
this._context.privateViewEventBus.emit(editorCommon.EventType.ViewZonesChanged, null);
this._context.privateViewEventBus.emit(viewEvents.ViewEventNames.ZonesChanged, null);
}
});
return zonesHaveChanged;
@ -818,11 +828,17 @@ export class View extends ViewEventHandler implements editorBrowser.IView, IDisp
throw new Error('ViewImpl.render: View is disposed');
}
if (everything) {
// Force a render with a layout event
this.layoutProvider.emitLayoutChangedEvent();
// Force everything to render...
this.viewLines.forceShouldRender();
for (let i = 0, len = this.viewParts.length; i < len; i++) {
let viewPart = this.viewParts[i];
viewPart.forceShouldRender();
}
}
if (now) {
this._flushAccumulatedAndRenderNow();
} else {
this._scheduleRender();
}
}
@ -919,7 +935,7 @@ export class View extends ViewEventHandler implements editorBrowser.IView, IDisp
private _setHasFocus(newHasFocus: boolean): void {
if (this.hasFocus !== newHasFocus) {
this.hasFocus = newHasFocus;
this._context.privateViewEventBus.emit(editorCommon.EventType.ViewFocusChanged, this.hasFocus);
this._context.privateViewEventBus.emit(viewEvents.ViewEventNames.ViewFocusChanged, this.hasFocus);
}
}
}

View file

@ -9,6 +9,8 @@ import { ViewPart } from 'vs/editor/browser/view/viewPart';
import { FastDomNode, createFastDomNode } from 'vs/base/browser/styleMutator';
import { ViewContext } from 'vs/editor/common/view/viewContext';
import { ViewportData } from 'vs/editor/common/viewLayout/viewLinesViewportData';
import * as viewEvents from 'vs/editor/common/view/viewEvents';
import { ScrollEvent } from 'vs/base/common/scrollable';
/**
* Represents a visible line
@ -108,7 +110,19 @@ export class RenderedLinesCollection<T extends ILine> {
let startLineNumber = this.getStartLineNumber();
let endLineNumber = this.getEndLineNumber();
// Record what needs to be deleted, notify lines that survive after deletion
if (deleteToLineNumber < startLineNumber) {
// deleting above the viewport
let deleteCnt = deleteToLineNumber - deleteFromLineNumber + 1;
this._rendLineNumberStart -= deleteCnt;
return null;
}
if (deleteFromLineNumber > endLineNumber) {
// deleted below the viewport
return null;
}
// Record what needs to be deleted
let deleteStartIndex = 0;
let deleteCount = 0;
for (let lineNumber = startLineNumber; lineNumber <= endLineNumber; lineNumber++) {
@ -154,18 +168,14 @@ export class RenderedLinesCollection<T extends ILine> {
let startLineNumber = this.getStartLineNumber();
let endLineNumber = this.getEndLineNumber();
// Notify lines after the change
let notifiedSomeone = false;
for (let lineNumber = startLineNumber; lineNumber <= endLineNumber; lineNumber++) {
let lineIndex = lineNumber - this._rendLineNumberStart;
if (lineNumber === changedLineNumber) {
this._lines[lineIndex].onContentChanged();
notifiedSomeone = true;
}
if (changedLineNumber < startLineNumber || changedLineNumber > endLineNumber) {
// a line has been changed above or below the viewport
return false;
}
return notifiedSomeone;
// Notify the line
this._lines[changedLineNumber - this._rendLineNumberStart].onContentChanged();
return true;
}
public onModelLinesInserted(insertFromLineNumber: number, insertToLineNumber: number): T[] {
@ -244,7 +254,7 @@ export class RenderedLinesCollection<T extends ILine> {
export abstract class ViewLayer<T extends IVisibleLine> extends ViewPart {
protected domNode: FastDomNode;
protected domNode: FastDomNode<HTMLElement>;
protected _linesCollection: RenderedLinesCollection<T>;
private _renderer: ViewLayerRenderer<T>;
private _scrollDomNode: HTMLElement;
@ -272,11 +282,11 @@ export abstract class ViewLayer<T extends IVisibleLine> extends ViewPart {
// ---- begin view event handlers
public onLayoutChanged(layoutInfo: editorCommon.EditorLayoutInfo): boolean {
return true;
public onConfigurationChanged(e: editorCommon.IConfigurationChangedEvent): boolean {
return e.layoutInfo;
}
public onScrollChanged(e: editorCommon.IScrollEvent): boolean {
public onScrollChanged(e: ScrollEvent): boolean {
return e.scrollTopChanged;
}
@ -291,7 +301,7 @@ export abstract class ViewLayer<T extends IVisibleLine> extends ViewPart {
return true;
}
public onModelLinesDeleted(e: editorCommon.IViewLinesDeletedEvent): boolean {
public onModelLinesDeleted(e: viewEvents.IViewLinesDeletedEvent): boolean {
let deleted = this._linesCollection.onModelLinesDeleted(e.fromLineNumber, e.toLineNumber);
if (deleted) {
// Remove from DOM
@ -306,11 +316,11 @@ export abstract class ViewLayer<T extends IVisibleLine> extends ViewPart {
return true;
}
public onModelLineChanged(e: editorCommon.IViewLineChangedEvent): boolean {
public onModelLineChanged(e: viewEvents.IViewLineChangedEvent): boolean {
return this._linesCollection.onModelLineChanged(e.lineNumber);
}
public onModelLinesInserted(e: editorCommon.IViewLinesInsertedEvent): boolean {
public onModelLinesInserted(e: viewEvents.IViewLinesInsertedEvent): boolean {
let deleted = this._linesCollection.onModelLinesInserted(e.fromLineNumber, e.toLineNumber);
if (deleted) {
// Remove from DOM
@ -325,7 +335,7 @@ export abstract class ViewLayer<T extends IVisibleLine> extends ViewPart {
return true;
}
public onModelTokensChanged(e: editorCommon.IViewTokensChangedEvent): boolean {
public onModelTokensChanged(e: viewEvents.IViewTokensChangedEvent): boolean {
return this._linesCollection.onModelTokensChanged(e.ranges);
}
@ -353,7 +363,7 @@ export abstract class ViewLayer<T extends IVisibleLine> extends ViewPart {
this._scrollDomNodeIsAbove = resCtx.scrollDomNodeIsAbove;
}
private _createDomNode(): FastDomNode {
private _createDomNode(): FastDomNode<HTMLElement> {
let domNode = createFastDomNode(document.createElement('div'));
domNode.setClassName('view-layer');
domNode.setPosition('absolute');

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