Merge branch 'master' into misolori/icon-font-dialog

This commit is contained in:
Miguel Solorio
2019-11-22 15:11:26 -08:00
committed by GitHub
387 changed files with 9841 additions and 4660 deletions
+1
View File
@@ -131,6 +131,7 @@
"linux": {
"runtimeExecutable": "${workspaceFolder}/scripts/code.sh"
},
"port": 9222,
"timeout": 20000,
"env": {
"VSCODE_EXTHOST_WILL_SEND_SOCKET": null
+1 -1
View File
@@ -1,3 +1,3 @@
disturl "https://atom.io/download/electron"
target "6.1.4"
target "6.1.5"
runtime "electron"
+2 -4
View File
@@ -22,8 +22,6 @@ This repository ("`Code - OSS`") is where we (Microsoft) develop the [Visual Stu
Visual Studio Code is updated monthly with new features and bug fixes. You can download it for Windows, macOS, and Linux on [Visual Studio Code's website](https://code.visualstudio.com/Download). To get the latest releases every day, install the [Insiders build](https://code.visualstudio.com/insiders).
## Contributing
There are many ways in which you can participate in the project, for example:
@@ -52,11 +50,11 @@ please see the document [How to Contribute](https://github.com/Microsoft/vscode/
## Related Projects
Many of the core components and extensions to Code live in their own repositories on GitHub. For example, the [node debug adapter](https://github.com/microsoft/vscode-node-debug) and the [mono debug adapter](https://github.com/microsoft/vscode-mono-debug) have their own repositories. For a complete list, please visit the [Related Projects](https://github.com/Microsoft/vscode/wiki/Related-Projects) page on our [wiki](https://github.com/Microsoft/vscode/wiki).
Many of the core components and extensions to VS Code live in their own repositories on GitHub. For example, the [node debug adapter](https://github.com/microsoft/vscode-node-debug) and the [mono debug adapter](https://github.com/microsoft/vscode-mono-debug) have their own repositories. For a complete list, please visit the [Related Projects](https://github.com/Microsoft/vscode/wiki/Related-Projects) page on our [wiki](https://github.com/Microsoft/vscode/wiki).
## Bundled Extensions
Code includes a set of built-in extensions located in the [extensions](extensions) folder, including grammars and snippets for many languages. Extensions that provide rich language support (code completion, Go to Definition) for a language have the suffix `language-features`. For example, the `json` extension provides coloring for `JSON` and the `json-language-features` provides rich language support for `JSON`.
VS Code includes a set of built-in extensions located in the [extensions](extensions) folder, including grammars and snippets for many languages. Extensions that provide rich language support (code completion, Go to Definition) for a language have the suffix `language-features`. For example, the `json` extension provides coloring for `JSON` and the `json-language-features` provides rich language support for `JSON`.
## Code of Conduct
+18 -17
View File
@@ -12,23 +12,24 @@ steps:
vstsFeed: 'npm-vscode'
platformIndependent: true
alias: 'Compilation'
dryRun: true
- task: NodeTool@0
inputs:
versionSpec: "12.13.0"
condition: and(succeeded(), ne(variables['CacheRestored-Compilation'], 'true'))
condition: and(succeeded(), ne(variables['CacheExists-Compilation'], 'true'))
- task: geeklearningio.gl-vsts-tasks-yarn.yarn-installer-task.YarnInstaller@2
inputs:
versionSpec: "1.x"
condition: and(succeeded(), ne(variables['CacheRestored-Compilation'], 'true'))
condition: and(succeeded(), ne(variables['CacheExists-Compilation'], 'true'))
- task: AzureKeyVault@1
displayName: 'Azure Key Vault: Get Secrets'
inputs:
azureSubscription: 'vscode-builds-subscription'
KeyVaultName: vscode
condition: and(succeeded(), ne(variables['CacheRestored-Compilation'], 'true'))
condition: and(succeeded(), ne(variables['CacheExists-Compilation'], 'true'))
- script: |
set -e
@@ -41,7 +42,7 @@ steps:
git config user.email "vscode@microsoft.com"
git config user.name "VSCode"
displayName: Prepare tooling
condition: and(succeeded(), ne(variables['CacheRestored-Compilation'], 'true'))
condition: and(succeeded(), ne(variables['CacheExists-Compilation'], 'true'))
- script: |
set -e
@@ -49,33 +50,33 @@ steps:
git fetch distro
git merge $(node -p "require('./package.json').distro")
displayName: Merge distro
condition: and(succeeded(), ne(variables['CacheRestored-Compilation'], 'true'))
condition: and(succeeded(), ne(variables['CacheExists-Compilation'], 'true'))
- task: 1ESLighthouseEng.PipelineArtifactCaching.RestoreCacheV1.RestoreCache@1
inputs:
keyfile: 'build/.cachesalt, .yarnrc, remote/.yarnrc, **/yarn.lock, !**/node_modules/**/yarn.lock, !**/.*/**/yarn.lock'
targetfolder: '**/node_modules, !**/node_modules/**/node_modules'
vstsFeed: 'npm-vscode'
condition: and(succeeded(), ne(variables['CacheRestored-Compilation'], 'true'))
condition: and(succeeded(), ne(variables['CacheExists-Compilation'], 'true'))
- script: |
set -e
CHILD_CONCURRENCY=1 yarn --frozen-lockfile
displayName: Install dependencies
condition: and(succeeded(), ne(variables['CacheRestored-Compilation'], 'true'), ne(variables['CacheRestored'], 'true'))
condition: and(succeeded(), ne(variables['CacheExists-Compilation'], 'true'), ne(variables['CacheRestored'], 'true'))
- task: 1ESLighthouseEng.PipelineArtifactCaching.SaveCacheV1.SaveCache@1
inputs:
keyfile: 'build/.cachesalt, .yarnrc, remote/.yarnrc, **/yarn.lock, !**/node_modules/**/yarn.lock, !**/.*/**/yarn.lock'
targetfolder: '**/node_modules, !**/node_modules/**/node_modules'
vstsFeed: 'npm-vscode'
condition: and(succeeded(), ne(variables['CacheRestored-Compilation'], 'true'), ne(variables['CacheRestored'], 'true'))
condition: and(succeeded(), ne(variables['CacheExists-Compilation'], 'true'), ne(variables['CacheRestored'], 'true'))
- script: |
set -e
yarn postinstall
displayName: Run postinstall scripts
condition: and(succeeded(), ne(variables['CacheRestored-Compilation'], 'true'), eq(variables['CacheRestored'], 'true'))
condition: and(succeeded(), ne(variables['CacheExists-Compilation'], 'true'), eq(variables['CacheRestored'], 'true'))
# Mixin must run before optimize, because the CSS loader will
# inline small SVGs
@@ -83,7 +84,7 @@ steps:
set -e
node build/azure-pipelines/mixin
displayName: Mix in quality
condition: and(succeeded(), ne(variables['CacheRestored-Compilation'], 'true'))
condition: and(succeeded(), ne(variables['CacheExists-Compilation'], 'true'))
- script: |
set -e
@@ -91,20 +92,20 @@ steps:
yarn gulp tslint
yarn monaco-compile-check
displayName: Run hygiene, tslint and monaco compile checks
condition: and(succeeded(), ne(variables['CacheRestored-Compilation'], 'true'), eq(variables['VSCODE_STEP_ON_IT'], 'false'))
condition: and(succeeded(), ne(variables['CacheExists-Compilation'], 'true'), eq(variables['VSCODE_STEP_ON_IT'], 'false'))
- script: |
set -
./build/azure-pipelines/common/extract-telemetry.sh
displayName: Extract Telemetry
condition: and(succeeded(), ne(variables['CacheRestored-Compilation'], 'true'))
condition: and(succeeded(), ne(variables['CacheExists-Compilation'], 'true'))
- script: |
set -e
AZURE_WEBVIEW_STORAGE_ACCESS_KEY="$(vscode-webview-storage-key)" \
./build/azure-pipelines/common/publish-webview.sh
displayName: Publish Webview
condition: and(succeeded(), ne(variables['CacheRestored-Compilation'], 'true'))
condition: and(succeeded(), ne(variables['CacheExists-Compilation'], 'true'))
- script: |
set -e
@@ -114,14 +115,14 @@ steps:
yarn gulp minify-vscode-reh
yarn gulp minify-vscode-reh-web
displayName: Compile
condition: and(succeeded(), ne(variables['CacheRestored-Compilation'], 'true'))
condition: and(succeeded(), ne(variables['CacheExists-Compilation'], 'true'))
- script: |
set -e
AZURE_STORAGE_ACCESS_KEY="$(ticino-storage-key)" \
node build/azure-pipelines/upload-sourcemaps
displayName: Upload sourcemaps
condition: and(succeeded(), ne(variables['CacheRestored-Compilation'], 'true'))
condition: and(succeeded(), ne(variables['CacheExists-Compilation'], 'true'))
- script: |
set -e
@@ -129,7 +130,7 @@ steps:
AZURE_DOCUMENTDB_MASTERKEY="$(builds-docdb-key-readwrite)" \
node build/azure-pipelines/common/createBuild.js $VERSION
displayName: Create build
condition: and(succeeded(), ne(variables['CacheRestored-Compilation'], 'true'))
condition: and(succeeded(), ne(variables['CacheExists-Compilation'], 'true'))
- task: 1ESLighthouseEng.PipelineArtifactCaching.SaveCacheV1.SaveCache@1
inputs:
@@ -138,4 +139,4 @@ steps:
vstsFeed: 'npm-vscode'
platformIndependent: true
alias: 'Compilation'
condition: and(succeeded(), ne(variables['CacheRestored-Compilation'], 'true'))
condition: and(succeeded(), ne(variables['CacheExists-Compilation'], 'true'))
+1 -1
View File
@@ -1,7 +1,7 @@
[
{
"name": "ms-vscode.node-debug",
"version": "1.41.0",
"version": "1.41.1",
"repo": "https://github.com/Microsoft/vscode-node-debug",
"metadata": {
"id": "b6ded8fb-a0a0-4c1c-acbd-ab2a3bc995a6",
+6 -3
View File
@@ -109,7 +109,8 @@ const tasks = compilations.map(function (tsconfigFile) {
const compileTask = task.define(`compile-extension:${name}`, task.series(cleanTask, () => {
const pipeline = createPipeline(false, true);
const input = pipeline.tsProjectSrc();
const nonts = gulp.src(src, srcOpts).pipe(filter(['**', '!**/*.ts']));
const input = es.merge(nonts, pipeline.tsProjectSrc());
return input
.pipe(pipeline())
@@ -118,7 +119,8 @@ const tasks = compilations.map(function (tsconfigFile) {
const watchTask = task.define(`watch-extension:${name}`, task.series(cleanTask, () => {
const pipeline = createPipeline(false);
const input = pipeline.tsProjectSrc();
const nonts = gulp.src(src, srcOpts).pipe(filter(['**', '!**/*.ts']));
const input = es.merge(nonts, pipeline.tsProjectSrc());
const watchInput = watcher(src, { ...srcOpts, ...{ readDelay: 200 } });
return watchInput
@@ -128,7 +130,8 @@ const tasks = compilations.map(function (tsconfigFile) {
const compileBuildTask = task.define(`compile-build-extension-${name}`, task.series(cleanTask, () => {
const pipeline = createPipeline(true, true);
const input = pipeline.tsProjectSrc();
const nonts = gulp.src(src, srcOpts).pipe(filter(['**', '!**/*.ts']));
const input = es.merge(nonts, pipeline.tsProjectSrc());
return input
.pipe(pipeline())
+2 -2
View File
@@ -60,12 +60,12 @@
"git": {
"name": "electron",
"repositoryUrl": "https://github.com/electron/electron",
"commitHash": "a5b474e8248803f54efc2c2c724c3322590c4fda"
"commitHash": "6f62f91822a80192cb711c604f1a8f1a176f328d"
}
},
"isOnlyProductionDependency": true,
"license": "MIT",
"version": "6.1.4"
"version": "6.1.5"
},
{
"component": {
@@ -18,6 +18,16 @@
"type": "integer"
}
},
"remoteEnv": {
"type": "object",
"additionalProperties": {
"type": [
"string",
"null"
]
},
"description": "Remote environment variables."
},
"extensions": {
"type": "array",
"description": "An array of extensions that should be installed into the container.",
@@ -22,6 +22,16 @@
"$ref": "vscode://schemas/settings/machine",
"description": "Machine specific settings that should be copied into the container."
},
"remoteEnv": {
"type": "object",
"additionalProperties": {
"type": [
"string",
"null"
]
},
"description": "Remote environment variables."
},
"postCreateCommand": {
"type": [
"string",
@@ -55,6 +65,13 @@
]
}
},
"containerEnv": {
"type": "object",
"additionalProperties": {
"type": "string"
},
"description": "Container environment variables."
},
"runArgs": {
"type": "array",
"description": "The arguments required when starting in the container.",
+1 -1
View File
@@ -13,6 +13,6 @@ module.exports = withDefaults({
context: __dirname,
entry: {
main: './src/main.ts',
['askpass-main']: './src/askpass-main.ts'
['askpass-main']: './src/askpass/askpass-main.ts'
}
});
+9 -15
View File
@@ -1194,7 +1194,7 @@
{
"command": "git.openFile",
"group": "navigation",
"when": "config.git.enabled && gitOpenRepositoryCount != 0 && isInDiffEditor && resourceScheme =~ /^git$|^file$/"
"when": "config.git.enabled && gitOpenRepositoryCount != 0 && isInDiffEditor && resourceScheme =~ /^gitfs$|^file$/"
},
{
"command": "git.openChange",
@@ -1204,44 +1204,44 @@
{
"command": "git.stageSelectedRanges",
"group": "2_git@1",
"when": "config.git.enabled && gitOpenRepositoryCount != 0 && isInDiffEditor && resourceScheme =~ /^git$|^file$/"
"when": "config.git.enabled && gitOpenRepositoryCount != 0 && isInDiffEditor && resourceScheme =~ /^gitfs$|^file$/"
},
{
"command": "git.unstageSelectedRanges",
"group": "2_git@2",
"when": "config.git.enabled && gitOpenRepositoryCount != 0 && isInDiffEditor && resourceScheme =~ /^git$|^file$/"
"when": "config.git.enabled && gitOpenRepositoryCount != 0 && isInDiffEditor && resourceScheme =~ /^gitfs$|^file$/"
},
{
"command": "git.revertSelectedRanges",
"group": "2_git@3",
"when": "config.git.enabled && gitOpenRepositoryCount != 0 && isInDiffEditor && resourceScheme =~ /^git$|^file$/"
"when": "config.git.enabled && gitOpenRepositoryCount != 0 && isInDiffEditor && resourceScheme =~ /^gitfs$|^file$/"
}
],
"editor/context": [
{
"command": "git.stageSelectedRanges",
"group": "2_git@1",
"when": "isInDiffRightEditor && config.git.enabled && gitOpenRepositoryCount != 0 && isInDiffEditor && resourceScheme =~ /^git$|^file$/"
"when": "isInDiffRightEditor && config.git.enabled && gitOpenRepositoryCount != 0 && isInDiffEditor && resourceScheme =~ /^gitfs$|^file$/"
},
{
"command": "git.unstageSelectedRanges",
"group": "2_git@2",
"when": "isInDiffRightEditor && config.git.enabled && gitOpenRepositoryCount != 0 && isInDiffEditor && resourceScheme =~ /^git$|^file$/"
"when": "isInDiffRightEditor && config.git.enabled && gitOpenRepositoryCount != 0 && isInDiffEditor && resourceScheme =~ /^gitfs$|^file$/"
},
{
"command": "git.revertSelectedRanges",
"group": "2_git@3",
"when": "isInDiffRightEditor && config.git.enabled && gitOpenRepositoryCount != 0 && isInDiffEditor && resourceScheme =~ /^git$|^file$/"
"when": "isInDiffRightEditor && config.git.enabled && gitOpenRepositoryCount != 0 && isInDiffEditor && resourceScheme =~ /^gitfs$|^file$/"
}
],
"scm/change/title": [
{
"command": "git.stageChange",
"when": "originalResourceScheme == git"
"when": "originalResourceScheme == gitfs"
},
{
"command": "git.revertChange",
"when": "originalResourceScheme == git"
"when": "originalResourceScheme == gitfs"
}
]
},
@@ -1608,12 +1608,6 @@
"default": "mixed",
"description": "%config.untrackedChanges%",
"scope": "resource"
},
"git.restoreCommitTemplateComments": {
"type": "boolean",
"scope": "resource",
"default": true,
"description": "%config.restoreCommitTemplateComments%"
}
}
},
+1 -2
View File
@@ -61,7 +61,7 @@
"command.publish": "Publish Branch...",
"command.showOutput": "Show Git Output",
"command.ignore": "Add to .gitignore",
"command.revealInExplorer": "Reveal in Explorer",
"command.revealInExplorer": "Reveal in Side Bar",
"command.stashIncludeUntracked": "Stash (Include Untracked)",
"command.stash": "Stash",
"command.stashPop": "Pop Stash...",
@@ -139,7 +139,6 @@
"config.untrackedChanges.mixed": "All changes, tracked and untracked, appear together and behave equally.",
"config.untrackedChanges.separate": "Untracked changes appear separately in the Source Control view. They are also excluded from several actions.",
"config.untrackedChanges.hidden": "Untracked changes are hidden and excluded from several actions.",
"config.restoreCommitTemplateComments": "Controls whether to restore commit template comments in the commit input box.",
"colors.added": "Color for added resources.",
"colors.modified": "Color for modified resources.",
"colors.deleted": "Color for deleted resources.",
+5
View File
@@ -8,6 +8,7 @@ import { Repository as BaseRepository, Resource } from '../repository';
import { InputBox, Git, API, Repository, Remote, RepositoryState, Branch, Ref, Submodule, Commit, Change, RepositoryUIState, Status, LogOptions, APIState } from './git';
import { Event, SourceControlInputBox, Uri, SourceControl } from 'vscode';
import { mapEvent } from '../util';
import { toGitUri } from '../uri';
class ApiInputBox implements InputBox {
set value(value: string) { this._inputBox.value = value; }
@@ -234,5 +235,9 @@ export class ApiImpl implements API {
return this._model.repositories.map(r => new ApiRepository(r));
}
toGitUri(uri: Uri, ref: string): Uri {
return toGitUri(uri, ref);
}
constructor(private _model: Model) { }
}
+2
View File
@@ -185,6 +185,8 @@ export interface API {
readonly repositories: Repository[];
readonly onDidOpenRepository: Event<Repository>;
readonly onDidCloseRepository: Event<Repository>;
toGitUri(uri: Uri, ref: string): Uri;
}
export interface GitExtension {
-119
View File
@@ -1,119 +0,0 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import { Disposable, window, InputBoxOptions } from 'vscode';
import { denodeify } from './util';
import * as path from 'path';
import * as http from 'http';
import * as os from 'os';
import * as fs from 'fs';
import * as crypto from 'crypto';
const randomBytes = denodeify<Buffer>(crypto.randomBytes);
export interface AskpassEnvironment {
GIT_ASKPASS: string;
ELECTRON_RUN_AS_NODE?: string;
VSCODE_GIT_ASKPASS_NODE?: string;
VSCODE_GIT_ASKPASS_MAIN?: string;
VSCODE_GIT_ASKPASS_HANDLE?: string;
}
function getIPCHandlePath(nonce: string): string {
if (process.platform === 'win32') {
return `\\\\.\\pipe\\vscode-git-askpass-${nonce}-sock`;
}
if (process.env['XDG_RUNTIME_DIR']) {
return path.join(process.env['XDG_RUNTIME_DIR'] as string, `vscode-git-askpass-${nonce}.sock`);
}
return path.join(os.tmpdir(), `vscode-git-askpass-${nonce}.sock`);
}
export class Askpass implements Disposable {
private server: http.Server;
private ipcHandlePathPromise: Promise<string>;
private ipcHandlePath: string | undefined;
private enabled = true;
constructor() {
this.server = http.createServer((req, res) => this.onRequest(req, res));
this.ipcHandlePathPromise = this.setup().catch(err => {
console.error(err);
return '';
});
}
private async setup(): Promise<string> {
const buffer = await randomBytes(20);
const nonce = buffer.toString('hex');
const ipcHandlePath = getIPCHandlePath(nonce);
this.ipcHandlePath = ipcHandlePath;
try {
this.server.listen(ipcHandlePath);
this.server.on('error', err => console.error(err));
} catch (err) {
console.error('Could not launch git askpass helper.');
this.enabled = false;
}
return ipcHandlePath;
}
private onRequest(req: http.IncomingMessage, res: http.ServerResponse): void {
const chunks: string[] = [];
req.setEncoding('utf8');
req.on('data', (d: string) => chunks.push(d));
req.on('end', () => {
const { request, host } = JSON.parse(chunks.join(''));
this.prompt(host, request).then(result => {
res.writeHead(200);
res.end(JSON.stringify(result));
}, () => {
res.writeHead(500);
res.end();
});
});
}
private async prompt(host: string, request: string): Promise<string> {
const options: InputBoxOptions = {
password: /password/i.test(request),
placeHolder: request,
prompt: `Git: ${host}`,
ignoreFocusOut: true
};
return await window.showInputBox(options) || '';
}
async getEnv(): Promise<AskpassEnvironment> {
if (!this.enabled) {
return {
GIT_ASKPASS: path.join(__dirname, 'askpass-empty.sh')
};
}
return {
ELECTRON_RUN_AS_NODE: '1',
GIT_ASKPASS: path.join(__dirname, 'askpass.sh'),
VSCODE_GIT_ASKPASS_NODE: process.execPath,
VSCODE_GIT_ASKPASS_MAIN: path.join(__dirname, 'askpass-main.js'),
VSCODE_GIT_ASKPASS_HANDLE: await this.ipcHandlePathPromise
};
}
dispose(): void {
this.server.close();
if (this.ipcHandlePath && process.platform !== 'win32') {
fs.unlinkSync(this.ipcHandlePath);
}
}
}
@@ -3,9 +3,9 @@
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import * as http from 'http';
import * as fs from 'fs';
import * as nls from 'vscode-nls';
import { IPCClient } from '../ipc/ipcClient';
const localize = nls.loadMessageBundle();
@@ -20,10 +20,6 @@ function main(argv: string[]): void {
return fatal('Wrong number of arguments');
}
if (!process.env['VSCODE_GIT_ASKPASS_HANDLE']) {
return fatal('Missing handle');
}
if (!process.env['VSCODE_GIT_ASKPASS_PIPE']) {
return fatal('Missing pipe');
}
@@ -33,40 +29,14 @@ function main(argv: string[]): void {
}
const output = process.env['VSCODE_GIT_ASKPASS_PIPE'] as string;
const socketPath = process.env['VSCODE_GIT_ASKPASS_HANDLE'] as string;
const request = argv[2];
const host = argv[4].substring(1, argv[4].length - 2);
const opts: http.RequestOptions = {
socketPath,
path: '/',
method: 'POST'
};
const ipcClient = new IPCClient('askpass');
const req = http.request(opts, res => {
if (res.statusCode !== 200) {
return fatal(`Bad status code: ${res.statusCode}`);
}
const chunks: string[] = [];
res.setEncoding('utf8');
res.on('data', (d: string) => chunks.push(d));
res.on('end', () => {
const raw = chunks.join('');
try {
const result = JSON.parse(raw);
fs.writeFileSync(output, result + '\n');
} catch (err) {
return fatal(`Error parsing response`);
}
setTimeout(() => process.exit(0), 0);
});
});
req.on('error', () => fatal('Error in request'));
req.write(JSON.stringify({ request, host }));
req.end();
ipcClient.call({ request, host }).then(res => {
fs.writeFileSync(output, res + '\n');
setTimeout(() => process.exit(0), 0);
}).catch(err => fatal(err));
}
main(process.argv);
+56
View File
@@ -0,0 +1,56 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import { window, InputBoxOptions } from 'vscode';
import { IDisposable } from '../util';
import * as path from 'path';
import { IIPCHandler, IIPCServer } from '../ipc/ipcServer';
export interface AskpassEnvironment {
GIT_ASKPASS: string;
ELECTRON_RUN_AS_NODE?: string;
VSCODE_GIT_ASKPASS_NODE?: string;
VSCODE_GIT_ASKPASS_MAIN?: string;
VSCODE_GIT_ASKPASS_HANDLE?: string;
}
export class Askpass implements IIPCHandler {
private disposable: IDisposable;
static getDisabledEnv(): AskpassEnvironment {
return {
GIT_ASKPASS: path.join(__dirname, 'askpass-empty.sh')
};
}
constructor(ipc: IIPCServer) {
this.disposable = ipc.registerHandler('askpass', this);
}
async handle({ request, host }: { request: string, host: string }): Promise<string> {
const options: InputBoxOptions = {
password: /password/i.test(request),
placeHolder: request,
prompt: `Git: ${host}`,
ignoreFocusOut: true
};
return await window.showInputBox(options) || '';
}
getEnv(): AskpassEnvironment {
return {
ELECTRON_RUN_AS_NODE: '1',
GIT_ASKPASS: path.join(__dirname, 'askpass.sh'),
VSCODE_GIT_ASKPASS_NODE: process.execPath,
VSCODE_GIT_ASKPASS_MAIN: path.join(__dirname, 'askpass-main.js')
};
}
dispose(): void {
this.disposable.dispose();
}
}
+32 -65
View File
@@ -14,7 +14,7 @@ import { CommitOptions, ForcePushMode, Git, Stash } from './git';
import { Model } from './model';
import { Repository, Resource, ResourceGroupType } from './repository';
import { applyLineChanges, getModifiedRange, intersectDiffWithRange, invertLineChange, toLineRanges } from './staging';
import { fromGitUri, toGitUri } from './uri';
import { fromGitUri, toGitUri, isGitUri } from './uri';
import { grep, isDescendant, pathEquals } from './util';
const localize = nls.loadMessageBundle();
@@ -170,14 +170,14 @@ function command(commandId: string, options: CommandOptions = {}): Function {
};
}
const ImageMimetypes = [
'image/png',
'image/gif',
'image/jpeg',
'image/webp',
'image/tiff',
'image/bmp'
];
// const ImageMimetypes = [
// 'image/png',
// 'image/gif',
// 'image/jpeg',
// 'image/webp',
// 'image/tiff',
// 'image/bmp'
// ];
async function categorizeResourceByResolution(resources: Resource[]): Promise<{ merge: Resource[], resolved: Resource[], unresolved: Resource[], deletionConflicts: Resource[] }> {
const selection = resources.filter(s => s instanceof Resource) as Resource[];
@@ -295,10 +295,10 @@ export class CommandCenter {
}
} else {
if (resource.type !== Status.DELETED_BY_THEM) {
left = await this.getLeftResource(resource);
left = this.getLeftResource(resource);
}
right = await this.getRightResource(resource);
right = this.getRightResource(resource);
}
const title = this.getTitle(resource);
@@ -330,79 +330,40 @@ export class CommandCenter {
}
}
private async getURI(uri: Uri, ref: string): Promise<Uri | undefined> {
const repository = this.model.getRepository(uri);
if (!repository) {
return toGitUri(uri, ref);
}
try {
let gitRef = ref;
if (gitRef === '~') {
const uriString = uri.toString();
const [indexStatus] = repository.indexGroup.resourceStates.filter(r => r.resourceUri.toString() === uriString);
gitRef = indexStatus ? '' : 'HEAD';
}
const { size, object } = await repository.getObjectDetails(gitRef, uri.fsPath);
const { mimetype } = await repository.detectObjectType(object);
if (mimetype === 'text/plain') {
return toGitUri(uri, ref);
}
if (size > 1000000) { // 1 MB
return Uri.parse(`data:;label:${path.basename(uri.fsPath)};description:${gitRef},`);
}
if (ImageMimetypes.indexOf(mimetype) > -1) {
const contents = await repository.buffer(gitRef, uri.fsPath);
return Uri.parse(`data:${mimetype};label:${path.basename(uri.fsPath)};description:${gitRef};size:${size};base64,${contents.toString('base64')}`);
}
return Uri.parse(`data:;label:${path.basename(uri.fsPath)};description:${gitRef},`);
} catch (err) {
return toGitUri(uri, ref);
}
}
private async getLeftResource(resource: Resource): Promise<Uri | undefined> {
private getLeftResource(resource: Resource): Uri | undefined {
switch (resource.type) {
case Status.INDEX_MODIFIED:
case Status.INDEX_RENAMED:
case Status.INDEX_ADDED:
return this.getURI(resource.original, 'HEAD');
return toGitUri(resource.original, 'HEAD');
case Status.MODIFIED:
case Status.UNTRACKED:
return this.getURI(resource.resourceUri, '~');
return toGitUri(resource.resourceUri, '~');
case Status.DELETED_BY_THEM:
return this.getURI(resource.resourceUri, '');
return toGitUri(resource.resourceUri, '');
}
return undefined;
}
private async getRightResource(resource: Resource): Promise<Uri | undefined> {
private getRightResource(resource: Resource): Uri | undefined {
switch (resource.type) {
case Status.INDEX_MODIFIED:
case Status.INDEX_ADDED:
case Status.INDEX_COPIED:
case Status.INDEX_RENAMED:
return this.getURI(resource.resourceUri, '');
return toGitUri(resource.resourceUri, '');
case Status.INDEX_DELETED:
case Status.DELETED:
return this.getURI(resource.resourceUri, 'HEAD');
return toGitUri(resource.resourceUri, 'HEAD');
case Status.DELETED_BY_US:
return this.getURI(resource.resourceUri, '~3');
return toGitUri(resource.resourceUri, '~3');
case Status.DELETED_BY_THEM:
return this.getURI(resource.resourceUri, '~2');
return toGitUri(resource.resourceUri, '~2');
case Status.MODIFIED:
case Status.UNTRACKED:
@@ -692,7 +653,7 @@ export class CommandCenter {
let uris: Uri[] | undefined;
if (arg instanceof Uri) {
if (arg.scheme === 'git') {
if (isGitUri(arg)) {
uris = [Uri.file(fromGitUri(arg).path)];
} else if (arg.scheme === 'file') {
uris = [arg];
@@ -771,7 +732,7 @@ export class CommandCenter {
return;
}
const HEAD = await this.getLeftResource(resource);
const HEAD = this.getLeftResource(resource);
const basename = path.basename(resource.resourceUri.fsPath);
const title = `${basename} (HEAD)`;
@@ -1117,7 +1078,7 @@ export class CommandCenter {
const modifiedDocument = textEditor.document;
const modifiedUri = modifiedDocument.uri;
if (modifiedUri.scheme !== 'git') {
if (!isGitUri(modifiedUri)) {
return;
}
@@ -1445,6 +1406,7 @@ export class CommandCenter {
const message = repository.inputBox.value;
const getCommitMessage = async () => {
let _message: string | undefined = message;
if (!_message) {
let value: string | undefined = undefined;
@@ -1469,7 +1431,7 @@ export class CommandCenter {
});
}
return _message ? repository.cleanUpCommitEditMessage(_message) : _message;
return _message;
};
const didCommit = await this.smartCommit(repository, getCommitMessage, opts);
@@ -2162,9 +2124,14 @@ export class CommandCenter {
return;
}
const branchName = repository.HEAD && repository.HEAD.name || '';
if (remotes.length === 1) {
return await repository.pushTo(remotes[0].name, branchName, true);
}
const addRemote = new AddRemoteItem(this);
const picks = [...repository.remotes.map(r => ({ label: r.name, description: r.pushUrl })), addRemote];
const branchName = repository.HEAD && repository.HEAD.name || '';
const placeHolder = localize('pick remote', "Pick a remote to publish the branch '{0}' to:", branchName);
const choice = await window.showQuickPick(picks, { placeHolder });
@@ -2454,7 +2421,7 @@ export class CommandCenter {
return undefined;
}
if (uri.scheme === 'git') {
if (isGitUri(uri)) {
const { path } = fromGitUri(uri);
uri = Uri.file(path);
}
+1 -1
View File
@@ -147,4 +147,4 @@ export class GitContentProvider {
dispose(): void {
this.disposables.forEach(d => d.dispose());
}
}
}
+199
View File
@@ -0,0 +1,199 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import { workspace, Uri, Disposable, Event, EventEmitter, window, FileSystemProvider, FileChangeEvent, FileStat, FileType, FileChangeType, FileSystemError } from 'vscode';
import { debounce, throttle } from './decorators';
import { fromGitUri, toGitUri } from './uri';
import { Model, ModelChangeEvent, OriginalResourceChangeEvent } from './model';
import { filterEvent, eventToPromise, isDescendant, pathEquals, EmptyDisposable } from './util';
interface CacheRow {
uri: Uri;
timestamp: number;
}
const THREE_MINUTES = 1000 * 60 * 3;
const FIVE_MINUTES = 1000 * 60 * 5;
export class GitFileSystemProvider implements FileSystemProvider {
private _onDidChangeFile = new EventEmitter<FileChangeEvent[]>();
readonly onDidChangeFile: Event<FileChangeEvent[]> = this._onDidChangeFile.event;
private changedRepositoryRoots = new Set<string>();
private cache = new Map<string, CacheRow>();
private mtime = new Date().getTime();
private disposables: Disposable[] = [];
constructor(private model: Model) {
this.disposables.push(
model.onDidChangeRepository(this.onDidChangeRepository, this),
model.onDidChangeOriginalResource(this.onDidChangeOriginalResource, this),
workspace.registerFileSystemProvider('gitfs', this, { isReadonly: true, isCaseSensitive: true }),
workspace.registerResourceLabelFormatter({
scheme: 'gitfs',
formatting: {
label: '${path} (git)',
separator: '/'
}
})
);
setInterval(() => this.cleanup(), FIVE_MINUTES);
}
private onDidChangeRepository({ repository }: ModelChangeEvent): void {
this.changedRepositoryRoots.add(repository.root);
this.eventuallyFireChangeEvents();
}
private onDidChangeOriginalResource({ uri }: OriginalResourceChangeEvent): void {
if (uri.scheme !== 'file') {
return;
}
const gitUri = toGitUri(uri, '', { replaceFileExtension: true });
this.mtime = new Date().getTime();
this._onDidChangeFile.fire([{ type: FileChangeType.Changed, uri: gitUri }]);
}
@debounce(1100)
private eventuallyFireChangeEvents(): void {
this.fireChangeEvents();
}
@throttle
private async fireChangeEvents(): Promise<void> {
if (!window.state.focused) {
const onDidFocusWindow = filterEvent(window.onDidChangeWindowState, e => e.focused);
await eventToPromise(onDidFocusWindow);
}
const events: FileChangeEvent[] = [];
for (const { uri } of this.cache.values()) {
const fsPath = uri.fsPath;
for (const root of this.changedRepositoryRoots) {
if (isDescendant(root, fsPath)) {
events.push({ type: FileChangeType.Changed, uri });
break;
}
}
}
if (events.length > 0) {
this.mtime = new Date().getTime();
this._onDidChangeFile.fire(events);
}
this.changedRepositoryRoots.clear();
}
private cleanup(): void {
const now = new Date().getTime();
const cache = new Map<string, CacheRow>();
for (const row of this.cache.values()) {
const { path } = fromGitUri(row.uri);
const isOpen = workspace.textDocuments
.filter(d => d.uri.scheme === 'file')
.some(d => pathEquals(d.uri.fsPath, path));
if (isOpen || now - row.timestamp < THREE_MINUTES) {
cache.set(row.uri.toString(), row);
} else {
// TODO: should fire delete events?
}
}
this.cache = cache;
}
watch(): Disposable {
return EmptyDisposable;
}
stat(uri: Uri): FileStat {
const { submoduleOf } = fromGitUri(uri);
const repository = submoduleOf ? this.model.getRepository(submoduleOf) : this.model.getRepository(uri);
if (!repository) {
throw FileSystemError.FileNotFound();
}
return { type: FileType.File, size: 0, mtime: this.mtime, ctime: 0 };
}
readDirectory(): Thenable<[string, FileType][]> {
throw new Error('Method not implemented.');
}
createDirectory(): void {
throw new Error('Method not implemented.');
}
async readFile(uri: Uri): Promise<Uint8Array> {
let { path, ref, submoduleOf } = fromGitUri(uri);
if (submoduleOf) {
const repository = this.model.getRepository(submoduleOf);
if (!repository) {
throw FileSystemError.FileNotFound();
}
const encoder = new TextEncoder();
if (ref === 'index') {
return encoder.encode(await repository.diffIndexWithHEAD(path));
} else {
return encoder.encode(await repository.diffWithHEAD(path));
}
}
const repository = this.model.getRepository(uri);
if (!repository) {
throw FileSystemError.FileNotFound();
}
const timestamp = new Date().getTime();
const cacheValue: CacheRow = { uri, timestamp };
this.cache.set(uri.toString(), cacheValue);
if (ref === '~') {
const fileUri = Uri.file(path);
const uriString = fileUri.toString();
const [indexStatus] = repository.indexGroup.resourceStates.filter(r => r.resourceUri.toString() === uriString);
ref = indexStatus ? '' : 'HEAD';
} else if (/^~\d$/.test(ref)) {
ref = `:${ref[1]}`;
}
try {
return await repository.buffer(ref, path);
} catch (err) {
return new Uint8Array(0);
}
}
writeFile(): void {
throw new Error('Method not implemented.');
}
delete(): void {
throw new Error('Method not implemented.');
}
rename(): void {
throw new Error('Method not implemented.');
}
dispose(): void {
this.disposables.forEach(d => d.dispose());
}
}
+11 -23
View File
@@ -3,7 +3,7 @@
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import * as fs from 'fs';
import { promises as fs, exists } from 'fs';
import * as path from 'path';
import * as os from 'os';
import * as cp from 'child_process';
@@ -11,7 +11,7 @@ import * as which from 'which';
import { EventEmitter } from 'events';
import iconv = require('iconv-lite');
import * as filetype from 'file-type';
import { assign, groupBy, denodeify, IDisposable, toDisposable, dispose, mkdirp, readBytes, detectUnicodeEncoding, Encoding, onceEvent, splitInChunks, Limiter } from './util';
import { assign, groupBy, IDisposable, toDisposable, dispose, mkdirp, readBytes, detectUnicodeEncoding, Encoding, onceEvent, splitInChunks, Limiter } from './util';
import { CancellationToken, Progress } from 'vscode';
import { URI } from 'vscode-uri';
import { detectEncoding } from './encoding';
@@ -22,8 +22,6 @@ import { StringDecoder } from 'string_decoder';
// https://github.com/microsoft/vscode/issues/65693
const MAX_CLI_LENGTH = 30000;
const readfile = denodeify<string, string | null, string>(fs.readFile);
export interface IGit {
path: string;
version: string;
@@ -350,7 +348,7 @@ export class Git {
let folderPath = path.join(parentPath, folderName);
let count = 1;
while (count < 20 && await new Promise(c => fs.exists(folderPath, c))) {
while (count < 20 && await new Promise(c => exists(folderPath, c))) {
folderName = `${baseFolderName}-${count++}`;
folderPath = path.join(parentPath, folderName);
}
@@ -1812,26 +1810,17 @@ export class Repository {
}
}
cleanupCommitEditMessage(message: string): string {
// If the message is a single line starting with whitespace followed by `#`, just allow it.
if (/^\s*#[^\n]*$/.test(message)) {
return message;
}
// Else, remove all lines starting with whitespace followed by `#`.
// TODO: Support core.commentChar
return message.replace(/^(\s*#)(.*)$(\n?)/gm, (_, prefix, content, suffix) => {
// https://github.com/microsoft/vscode/issues/84201#issuecomment-552834814
return /^\d/.test(content) ? `${prefix}${content}${suffix}` : '';
}).trim();
// TODO: Support core.commentChar
stripCommitMessageComments(message: string): string {
return message.replace(/^\s*#.*$\n?/gm, '').trim();
}
async getMergeMessage(): Promise<string | undefined> {
const mergeMsgPath = path.join(this.repositoryRoot, '.git', 'MERGE_MSG');
try {
const raw = await readfile(mergeMsgPath, 'utf8');
return raw.trim();
const raw = await fs.readFile(mergeMsgPath, 'utf8');
return this.stripCommitMessageComments(raw);
} catch {
return undefined;
}
@@ -1854,9 +1843,8 @@ export class Repository {
templatePath = path.join(this.repositoryRoot, templatePath);
}
const raw = await readfile(templatePath, 'utf8');
return raw.trim();
const raw = await fs.readFile(templatePath, 'utf8');
return this.stripCommitMessageComments(raw);
} catch (err) {
return '';
}
@@ -1879,7 +1867,7 @@ export class Repository {
const gitmodulesPath = path.join(this.root, '.gitmodules');
try {
const gitmodulesRaw = await readfile(gitmodulesPath, 'utf8');
const gitmodulesRaw = await fs.readFile(gitmodulesPath, 'utf8');
return parseGitmodules(gitmodulesRaw);
} catch (err) {
if (/ENOENT/.test(err.message)) {
+45
View File
@@ -0,0 +1,45 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import * as http from 'http';
export class IPCClient {
private ipcHandlePath: string;
constructor(private handlerName: string) {
const ipcHandlePath = process.env['VSCODE_GIT_IPC_HANDLE'];
if (!ipcHandlePath) {
throw new Error('Missing VSCODE_GIT_IPC_HANDLE');
}
this.ipcHandlePath = ipcHandlePath;
}
call(request: any): Promise<any> {
const opts: http.RequestOptions = {
socketPath: this.ipcHandlePath,
path: `/${this.handlerName}`,
method: 'POST'
};
return new Promise((c, e) => {
const req = http.request(opts, res => {
if (res.statusCode !== 200) {
return e(new Error(`Bad status code: ${res.statusCode}`));
}
const chunks: Buffer[] = [];
res.on('data', d => chunks.push(d));
res.on('end', () => c(JSON.parse(Buffer.concat(chunks).toString('utf8'))));
});
req.on('error', err => e(err));
req.write(JSON.stringify(request));
req.end();
});
}
}
+106
View File
@@ -0,0 +1,106 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import { Disposable } from 'vscode';
import { toDisposable } from '../util';
import * as path from 'path';
import * as http from 'http';
import * as os from 'os';
import * as fs from 'fs';
import * as crypto from 'crypto';
function getIPCHandlePath(nonce: string): string {
if (process.platform === 'win32') {
return `\\\\.\\pipe\\vscode-git-ipc-${nonce}-sock`;
}
if (process.env['XDG_RUNTIME_DIR']) {
return path.join(process.env['XDG_RUNTIME_DIR'] as string, `vscode-git-ipc-${nonce}.sock`);
}
return path.join(os.tmpdir(), `vscode-git-ipc-${nonce}.sock`);
}
export interface IIPCHandler {
handle(request: any): Promise<any>;
}
export async function createIPCServer(): Promise<IIPCServer> {
const server = http.createServer();
const buffer = await new Promise<Buffer>((c, e) => crypto.randomBytes(20, (err, buf) => err ? e(err) : c(buf)));
const nonce = buffer.toString('hex');
const ipcHandlePath = getIPCHandlePath(nonce);
return new Promise((c, e) => {
try {
server.on('error', err => e(err));
server.listen(ipcHandlePath);
c(new IPCServer(server, ipcHandlePath));
} catch (err) {
e(err);
}
});
}
export interface IIPCServer extends Disposable {
readonly ipcHandlePath: string | undefined;
getEnv(): any;
registerHandler(name: string, handler: IIPCHandler): Disposable;
}
class IPCServer implements IIPCServer, Disposable {
private handlers = new Map<string, IIPCHandler>();
get ipcHandlePath(): string { return this._ipcHandlePath; }
constructor(private server: http.Server, private _ipcHandlePath: string) {
this.server.on('request', this.onRequest.bind(this));
}
registerHandler(name: string, handler: IIPCHandler): Disposable {
this.handlers.set(`/${name}`, handler);
return toDisposable(() => this.handlers.delete(name));
}
private onRequest(req: http.IncomingMessage, res: http.ServerResponse): void {
if (!req.url) {
console.warn(`Request lacks url`);
return;
}
const handler = this.handlers.get(req.url);
if (!handler) {
console.warn(`IPC handler for ${req.url} not found`);
return;
}
const chunks: Buffer[] = [];
req.on('data', d => chunks.push(d));
req.on('end', () => {
const request = JSON.parse(Buffer.concat(chunks).toString('utf8'));
handler.handle(request).then(result => {
res.writeHead(200);
res.end(JSON.stringify(result));
}, () => {
res.writeHead(500);
res.end();
});
});
}
getEnv(): any {
return { VSCODE_GIT_IPC_HANDLE: this.ipcHandlePath };
}
dispose(): void {
this.handlers.clear();
this.server.close();
if (this._ipcHandlePath && process.platform !== 'win32') {
fs.unlinkSync(this._ipcHandlePath);
}
}
}
+23 -4
View File
@@ -11,8 +11,9 @@ import { findGit, Git, IGit } from './git';
import { Model } from './model';
import { CommandCenter } from './commands';
import { GitContentProvider } from './contentProvider';
import { GitFileSystemProvider } from './fileSystemProvider';
import { GitDecorations } from './decorationProvider';
import { Askpass } from './askpass';
import { Askpass } from './askpass/askpass';
import { toDisposable, filterEvent, eventToPromise } from './util';
import TelemetryReporter from 'vscode-extension-telemetry';
import { GitExtension } from './api/git';
@@ -20,6 +21,7 @@ import { GitProtocolHandler } from './protocolHandler';
import { GitExtensionImpl } from './api/extension';
import * as path from 'path';
import * as fs from 'fs';
import { createIPCServer, IIPCServer } from './ipc/ipcServer';
const deactivateTasks: { (): Promise<any>; }[] = [];
@@ -32,10 +34,26 @@ export async function deactivate(): Promise<any> {
async function createModel(context: ExtensionContext, outputChannel: OutputChannel, telemetryReporter: TelemetryReporter, disposables: Disposable[]): Promise<Model> {
const pathHint = workspace.getConfiguration('git').get<string>('path');
const info = await findGit(pathHint, path => outputChannel.appendLine(localize('looking', "Looking for git in: {0}", path)));
const askpass = new Askpass();
disposables.push(askpass);
const env = await askpass.getEnv();
let env: any = {};
let ipc: IIPCServer | undefined;
try {
ipc = await createIPCServer();
disposables.push(ipc);
env = { ...env, ...ipc.getEnv() };
} catch {
// noop
}
if (ipc) {
const askpass = new Askpass(ipc);
disposables.push(askpass);
env = { ...env, ...askpass.getEnv() };
} else {
env = { ...env, ...Askpass.getDisabledEnv() };
}
const git = new Git({ gitPath: info.path, version: info.version, env });
const model = new Model(git, context.globalState, outputChannel);
disposables.push(model);
@@ -62,6 +80,7 @@ async function createModel(context: ExtensionContext, outputChannel: OutputChann
disposables.push(
new CommandCenter(git, model, outputChannel, telemetryReporter),
new GitContentProvider(model),
new GitFileSystemProvider(model),
new GitDecorations(model),
new GitProtocolHandler()
);
+1 -13
View File
@@ -844,15 +844,7 @@ export class Repository implements Disposable {
return mergeMessage;
}
let template = await this.repository.getCommitTemplate();
const config = workspace.getConfiguration('git', Uri.file(this.root));
if (!config.get<boolean>('restoreCommitTemplateComments')) {
template = this.cleanUpCommitEditMessage(template);
}
return template;
return await this.repository.getCommitTemplate();
}
getConfigs(): Promise<{ key: string; value: string; }[]> {
@@ -1286,10 +1278,6 @@ export class Repository implements Disposable {
return await this.run(Operation.GetCommitTemplate, async () => this.repository.getCommitTemplate());
}
cleanUpCommitEditMessage(editMessage: string): string {
return this.repository.cleanupCommitEditMessage(editMessage);
}
async ignore(files: Uri[]): Promise<void> {
return await this.run(Operation.Ignore, async () => {
const ignoreFile = `${this.repository.root}${path.sep}.gitignore`;
+23 -4
View File
@@ -4,6 +4,7 @@
*--------------------------------------------------------------------------------------------*/
import { Uri } from 'vscode';
import * as qs from 'querystring';
export interface GitUriParams {
path: string;
@@ -11,8 +12,26 @@ export interface GitUriParams {
submoduleOf?: string;
}
export function isGitUri(uri: Uri): boolean {
return /^git(fs)?$/.test(uri.scheme);
}
export function fromGitUri(uri: Uri): GitUriParams {
return JSON.parse(uri.query);
const result = qs.parse(uri.query) as any;
if (!result) {
throw new Error('Invalid git URI: empty query');
}
if (typeof result.path !== 'string') {
throw new Error('Invalid git URI: missing path');
}
if (typeof result.ref !== 'string') {
throw new Error('Invalid git URI: missing ref');
}
return result;
}
export interface GitUriOptions {
@@ -42,8 +61,8 @@ export function toGitUri(uri: Uri, ref: string, options: GitUriOptions = {}): Ur
}
return uri.with({
scheme: 'git',
scheme: 'gitfs',
path,
query: JSON.stringify(params)
query: qs.stringify(params as any)
});
}
}
+4 -15
View File
@@ -6,7 +6,7 @@
import { Event } from 'vscode';
import { dirname, sep } from 'path';
import { Readable } from 'stream';
import * as fs from 'fs';
import { promises as fs, createReadStream } from 'fs';
import * as byline from 'byline';
export function log(...args: any[]): void {
@@ -140,25 +140,14 @@ export function groupBy<T>(arr: T[], fn: (el: T) => string): { [key: string]: T[
}, Object.create(null));
}
export function denodeify<A, B, C, R>(fn: Function): (a: A, b: B, c: C) => Promise<R>;
export function denodeify<A, B, R>(fn: Function): (a: A, b: B) => Promise<R>;
export function denodeify<A, R>(fn: Function): (a: A) => Promise<R>;
export function denodeify<R>(fn: Function): (...args: any[]) => Promise<R>;
export function denodeify<R>(fn: Function): (...args: any[]) => Promise<R> {
return (...args) => new Promise<R>((c, e) => fn(...args, (err: any, r: any) => err ? e(err) : c(r)));
}
export function nfcall<R>(fn: Function, ...args: any[]): Promise<R> {
return new Promise<R>((c, e) => fn(...args, (err: any, r: any) => err ? e(err) : c(r)));
}
export async function mkdirp(path: string, mode?: number): Promise<boolean> {
const mkdir = async () => {
try {
await nfcall(fs.mkdir, path, mode);
await fs.mkdir(path, mode);
} catch (err) {
if (err.code === 'EEXIST') {
const stat = await nfcall<fs.Stats>(fs.stat, path);
const stat = await fs.stat(path);
if (stat.isDirectory()) {
return;
@@ -232,7 +221,7 @@ export function find<T>(array: T[], fn: (t: T) => boolean): T | undefined {
export async function grep(filename: string, pattern: RegExp): Promise<boolean> {
return new Promise<boolean>((c, e) => {
const fileStream = fs.createReadStream(filename, { encoding: 'utf8' });
const fileStream = createReadStream(filename, { encoding: 'utf8' });
const stream = byline(fileStream);
stream.on('data', (line: string) => {
if (pattern.test(line)) {
@@ -14,10 +14,14 @@ import { EMPTY_ELEMENTS } from './htmlEmptyTagsShared';
import { activateTagClosing } from './tagClosing';
import TelemetryReporter from 'vscode-extension-telemetry';
import { getCustomDataPathsInAllWorkspaces, getCustomDataPathsFromAllExtensions } from './customData';
import { activateMatchingTagPosition as activateMatchingTagSelection } from './matchingTag';
namespace TagCloseRequest {
export const type: RequestType<TextDocumentPositionParams, string, any, any> = new RequestType('html/tag');
}
namespace MatchingTagPositionRequest {
export const type: RequestType<TextDocumentPositionParams, Position | null, any, any> = new RequestType('html/matchingTagPosition');
}
interface IPackageInfo {
name: string;
@@ -84,6 +88,14 @@ export function activate(context: ExtensionContext) {
disposable = activateTagClosing(tagRequestor, { html: true, handlebars: true }, 'html.autoClosingTags');
toDispose.push(disposable);
const matchingTagPositionRequestor = (document: TextDocument, position: Position) => {
let param = client.code2ProtocolConverter.asTextDocumentPositionParams(document, position);
return client.sendRequest(MatchingTagPositionRequest.type, param);
};
disposable = activateMatchingTagSelection(matchingTagPositionRequestor, { html: true, handlebars: true }, 'html.autoSelectingMatchingTags');
toDispose.push(disposable);
disposable = client.onTelemetry(e => {
if (telemetryReporter) {
telemetryReporter.sendTelemetryEvent(e.key, e.data);
@@ -0,0 +1,143 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import {
window,
workspace,
Disposable,
TextDocument,
Position,
TextEditorSelectionChangeEvent,
Selection,
Range,
WorkspaceEdit
} from 'vscode';
export function activateMatchingTagPosition(
matchingTagPositionProvider: (document: TextDocument, position: Position) => Thenable<Position | null>,
supportedLanguages: { [id: string]: boolean },
configName: string
): Disposable {
let disposables: Disposable[] = [];
window.onDidChangeTextEditorSelection(event => onDidChangeTextEditorSelection(event), null, disposables);
let isEnabled = false;
updateEnabledState();
window.onDidChangeActiveTextEditor(updateEnabledState, null, disposables);
function updateEnabledState() {
isEnabled = false;
let editor = window.activeTextEditor;
if (!editor) {
return;
}
let document = editor.document;
if (!supportedLanguages[document.languageId]) {
return;
}
if (!workspace.getConfiguration(undefined, document.uri).get<boolean>(configName)) {
return;
}
isEnabled = true;
}
let prevCursorCount = 0;
let cursorCount = 0;
let inMirrorMode = false;
function onDidChangeTextEditorSelection(event: TextEditorSelectionChangeEvent) {
if (!isEnabled) {
return;
}
prevCursorCount = cursorCount;
cursorCount = event.selections.length;
if (cursorCount === 1) {
if (inMirrorMode && prevCursorCount === 2) {
return;
}
if (event.selections[0].isEmpty) {
matchingTagPositionProvider(event.textEditor.document, event.selections[0].active).then(position => {
if (position && window.activeTextEditor) {
inMirrorMode = true;
const newCursor = new Selection(position.line, position.character, position.line, position.character);
window.activeTextEditor.selections = [...window.activeTextEditor.selections, newCursor];
}
});
}
}
if (cursorCount === 2 && inMirrorMode) {
// Check two cases
if (event.selections[0].isEmpty && event.selections[1].isEmpty) {
const charBeforePrimarySelection = getCharBefore(event.textEditor.document, event.selections[0].anchor);
const charAfterPrimarySelection = getCharAfter(event.textEditor.document, event.selections[0].anchor);
const charBeforeSecondarySelection = getCharBefore(event.textEditor.document, event.selections[1].anchor);
const charAfterSecondarySelection = getCharAfter(event.textEditor.document, event.selections[1].anchor);
// Exit mirror mode when cursor position no longer mirror
// Unless it's in the case of `<|></|>`
const charBeforeBothPositionRoughlyEqual =
charBeforePrimarySelection === charBeforeSecondarySelection ||
(charBeforePrimarySelection === '/' && charBeforeSecondarySelection === '<') ||
(charBeforeSecondarySelection === '/' && charBeforePrimarySelection === '<');
const charAfterBothPositionRoughlyEqual =
charAfterPrimarySelection === charAfterSecondarySelection ||
(charAfterPrimarySelection === ' ' && charAfterSecondarySelection === '>') ||
(charAfterSecondarySelection === ' ' && charAfterPrimarySelection === '>');
if (!charBeforeBothPositionRoughlyEqual || !charAfterBothPositionRoughlyEqual) {
inMirrorMode = false;
window.activeTextEditor!.selections = [window.activeTextEditor!.selections[0]];
return;
} else {
// Need to cleanup in the case of <div |></div |>
if (
charBeforePrimarySelection === ' ' &&
charAfterPrimarySelection === '>' &&
charBeforeSecondarySelection === ' ' &&
charAfterSecondarySelection === '>'
) {
const primaryBeforeSecondary =
event.textEditor.document.offsetAt(event.selections[0].anchor) <
event.textEditor.document.offsetAt(event.selections[1].anchor);
if (primaryBeforeSecondary) {
inMirrorMode = false;
const cleanupEdit = new WorkspaceEdit();
const cleanupRange = new Range(event.selections[1].anchor.translate(0, -1), event.selections[1].anchor);
cleanupEdit.replace(event.textEditor.document.uri, cleanupRange, '');
window.activeTextEditor!.selections = [window.activeTextEditor!.selections[0]];
workspace.applyEdit(cleanupEdit);
}
}
}
}
}
}
return Disposable.from(...disposables);
}
function getCharBefore(document: TextDocument, position: Position) {
const offset = document.offsetAt(position);
if (offset === 0) {
return '';
}
return document.getText(new Range(document.positionAt(offset - 1), position));
}
function getCharAfter(document: TextDocument, position: Position) {
const offset = document.offsetAt(position);
if (offset === document.getText().length) {
return '';
}
return document.getText(new Range(position, document.positionAt(offset + 1)));
}
@@ -161,6 +161,12 @@
"default": true,
"description": "%html.autoClosingTags%"
},
"html.autoSelectingMatchingTags": {
"type": "boolean",
"scope": "resource",
"default": true,
"description": "%html.autoSelectingMatchingTags%"
},
"html.trace.server": {
"type": "string",
"scope": "window",
@@ -24,5 +24,6 @@
"html.trace.server.desc": "Traces the communication between VS Code and the HTML language server.",
"html.validate.scripts": "Controls whether the built-in HTML language support validates embedded scripts.",
"html.validate.styles": "Controls whether the built-in HTML language support validates embedded styles.",
"html.autoClosingTags": "Enable/disable autoclosing of HTML tags."
"html.autoClosingTags": "Enable/disable autoclosing of HTML tags.",
"html.autoSelectingMatchingTags": "Enable/disable auto selecting matching HTML tags."
}
@@ -10,7 +10,7 @@
"main": "./out/htmlServerMain",
"dependencies": {
"vscode-css-languageservice": "^4.0.3-next.20",
"vscode-html-languageservice": "^3.0.4-next.8",
"vscode-html-languageservice": "^3.0.4-next.10",
"vscode-languageserver": "^6.0.0-next.3",
"vscode-nls": "^4.1.1",
"vscode-uri": "^2.0.3"
@@ -24,6 +24,9 @@ import { getDataProviders } from './customData';
namespace TagCloseRequest {
export const type: RequestType<TextDocumentPositionParams, string | null, any, any> = new RequestType('html/tag');
}
namespace MatchingTagPositionRequest {
export const type: RequestType<TextDocumentPositionParams, Position | null, any, any> = new RequestType('html/matchingTagPosition');
}
// Create a connection for the server
const connection: IConnection = createConnection();
@@ -136,6 +139,7 @@ connection.onInitialize((params: InitializeParams): InitializeResult => {
colorProvider: {},
foldingRangeProvider: true,
selectionRangeProvider: true,
renameProvider: true
};
return { capabilities };
});
@@ -469,6 +473,36 @@ connection.onSelectionRanges((params, token) => {
}, [], `Error while computing selection ranges for ${params.textDocument.uri}`, token);
});
connection.onRenameRequest((params, token) => {
return runSafe(() => {
const document = documents.get(params.textDocument.uri);
const position: Position = params.position;
if (document) {
const htmlMode = languageModes.getMode('html');
if (htmlMode && htmlMode.doRename) {
return htmlMode.doRename(document, position, params.newName);
}
}
return null;
}, null, `Error while computing rename for ${params.textDocument.uri}`, token);
});
connection.onRequest(MatchingTagPositionRequest.type, (params, token) => {
return runSafe(() => {
const document = documents.get(params.textDocument.uri);
if (document) {
const pos = params.position;
if (pos.character > 0) {
const mode = languageModes.getModeAtPosition(document, Position.create(pos.line, pos.character - 1));
if (mode && mode.findMatchingTagPosition) {
return mode.findMatchingTagPosition(document, pos);
}
}
}
return null;
}, null, `Error while computing matching tag position for ${params.textDocument.uri}`, token);
});
// Listen on the connection
connection.listen();
@@ -74,9 +74,17 @@ export function getHTMLMode(htmlLanguageService: HTMLLanguageService, workspace:
}
return null;
},
doRename(document: TextDocument, position: Position, newName: string) {
const htmlDocument = htmlDocuments.get(document);
return htmlLanguageService.doRename(document, position, newName, htmlDocument);
},
onDocumentRemoved(document: TextDocument) {
htmlDocuments.onDocumentRemoved(document);
},
findMatchingTagPosition(document: TextDocument, position: Position) {
const htmlDocument = htmlDocuments.get(document);
return htmlLanguageService.findMatchingTagPosition(document, position, htmlDocument);
},
dispose() {
htmlDocuments.dispose();
}
@@ -8,7 +8,7 @@ import {
ClientCapabilities, DocumentContext, getLanguageService as getHTMLLanguageService, IHTMLDataProvider, SelectionRange,
CompletionItem, CompletionList, Definition, Diagnostic, DocumentHighlight, DocumentLink, FoldingRange, FormattingOptions,
Hover, Location, Position, Range, SignatureHelp, SymbolInformation, TextDocument, TextEdit,
Color, ColorInformation, ColorPresentation
Color, ColorInformation, ColorPresentation, WorkspaceEdit
} from 'vscode-html-languageservice';
import { WorkspaceFolder } from 'vscode-languageserver';
import { getLanguageModelCache, LanguageModelCache } from '../languageModelCache';
@@ -38,6 +38,7 @@ export interface LanguageMode {
doResolve?: (document: TextDocument, item: CompletionItem) => CompletionItem;
doHover?: (document: TextDocument, position: Position) => Hover | null;
doSignatureHelp?: (document: TextDocument, position: Position) => SignatureHelp | null;
doRename?: (document: TextDocument, position: Position, newName: string) => WorkspaceEdit | null;
findDocumentHighlight?: (document: TextDocument, position: Position) => DocumentHighlight[];
findDocumentSymbols?: (document: TextDocument) => SymbolInformation[];
findDocumentLinks?: (document: TextDocument, documentContext: DocumentContext) => DocumentLink[];
@@ -47,6 +48,7 @@ export interface LanguageMode {
findDocumentColors?: (document: TextDocument) => ColorInformation[];
getColorPresentations?: (document: TextDocument, color: Color, range: Range) => ColorPresentation[];
doAutoClose?: (document: TextDocument, position: Position) => string | null;
findMatchingTagPosition?: (document: TextDocument, position: Position) => Position | null;
getFoldingRanges?: (document: TextDocument) => FoldingRange[];
onDocumentRemoved(document: TextDocument): void;
dispose(): void;
@@ -621,10 +621,10 @@ vscode-css-languageservice@^4.0.3-next.20:
vscode-nls "^4.1.1"
vscode-uri "^2.1.1"
vscode-html-languageservice@^3.0.4-next.8:
version "3.0.4-next.8"
resolved "https://registry.yarnpkg.com/vscode-html-languageservice/-/vscode-html-languageservice-3.0.4-next.8.tgz#b3df7b7e8f69c1bf76392c4fd4df4cf483e77e7d"
integrity sha512-gT34wzCwM1rCJzd0EAFnuVe0FaaSr3eXaJpYcMj6rt1UspIJYaL4WtDLCcw4eBL906N1b1Vu+sapiRmV5PjZpg==
vscode-html-languageservice@^3.0.4-next.10:
version "3.0.4-next.10"
resolved "https://registry.yarnpkg.com/vscode-html-languageservice/-/vscode-html-languageservice-3.0.4-next.10.tgz#da426326833770c51712abb2c7473b9b30bf1cbc"
integrity sha512-8P0QBtMPJ9nDMhW8MF/z+5JGg6rK6UOa9po18KIleNuV0rDHU9CAqDyUjxW0CEfLrHYz6dQdkW12ZTClvQnNHw==
dependencies:
vscode-languageserver-textdocument "^1.0.0-next.4"
vscode-languageserver-types "^3.15.0-next.6"
+1 -2
View File
@@ -29,8 +29,7 @@
"priority": "builtin",
"selector": [
{
"filenamePattern": "*.{jpg,jpe,jpeg,png,bmp,gif,ico,webp}",
"mime": "image/*"
"filenamePattern": "*.{jpg,jpe,jpeg,png,bmp,gif,ico,webp}"
}
]
}
+2 -2
View File
@@ -240,9 +240,9 @@ class Preview extends Disposable implements vscode.WebviewEditorEditingCapabilit
default:
// Avoid adding cache busting if there is already a query string
if (resource.query) {
return encodeURI(webviewEditor.webview.asWebviewUri(resource).toString());
return webviewEditor.webview.asWebviewUri(resource).toString(true);
}
return encodeURI(webviewEditor.webview.asWebviewUri(resource).toString() + `?version=${version}`);
return webviewEditor.webview.asWebviewUri(resource).with({ query: `version=${version}` }).toString(true);
}
}
@@ -4,7 +4,7 @@
"If you want to provide a fix or improvement, please create a pull request against the original repository.",
"Once accepted there, we are happy to receive an update request."
],
"version": "https://github.com/Microsoft/TypeScript-TmLanguage/commit/477c1b17e273b64af13040c064c9ed62c8b32fba",
"version": "https://github.com/Microsoft/TypeScript-TmLanguage/commit/4daff7b8904bc549dfbee8df1e2f7c82194b9f45",
"name": "JavaScript (with React support)",
"scopeName": "source.js",
"patterns": [
@@ -2451,7 +2451,7 @@
},
{
"name": "string.regexp.js",
"begin": "(?<=\\))\\s*\\/(?![\\/*])(?=(?:[^\\/\\\\\\[]|\\\\.|\\[([^\\]\\\\]|\\\\.)+\\])+\\/[gimsuy]*(?!\\s*[a-zA-Z0-9_$]))",
"begin": "(?<=\\))\\s*\\/(?![\\/*])(?=(?:[^\\/\\\\\\[]|\\\\.|\\[([^\\]\\\\]|\\\\.)+\\])+\\/([gimsuy]+|(?![\\/\\*])|(?=\\/\\*))(?!\\s*[a-zA-Z0-9_$]))",
"beginCaptures": {
"0": {
"name": "punctuation.definition.string.begin.js"
@@ -4572,7 +4572,7 @@
"patterns": [
{
"name": "string.regexp.js",
"begin": "(?<!\\+\\+|--|})(?<=[=(:,\\[?+!]|^return|[^\\._$[:alnum:]]return|^case|[^\\._$[:alnum:]]case|=>|&&|\\|\\||\\*\\/)\\s*(\\/)(?![\\/*])(?=(?:[^\\/\\\\\\[\\()]|\\\\.|\\[([^\\]\\\\]|\\\\.)+\\]|\\(([^\\)\\\\]|\\\\.)+\\))+\\/[gimsuy]*(?!\\s*[a-zA-Z0-9_$]))",
"begin": "(?<!\\+\\+|--|})(?<=[=(:,\\[?+!]|^return|[^\\._$[:alnum:]]return|^case|[^\\._$[:alnum:]]case|=>|&&|\\|\\||\\*\\/)\\s*(\\/)(?![\\/*])(?=(?:[^\\/\\\\\\[\\()]|\\\\.|\\[([^\\]\\\\]|\\\\.)+\\]|\\(([^\\)\\\\]|\\\\.)+\\))+\\/([gimsuy]+|(?![\\/\\*])|(?=\\/\\*))(?!\\s*[a-zA-Z0-9_$]))",
"beginCaptures": {
"1": {
"name": "punctuation.definition.string.begin.js"
@@ -4595,7 +4595,7 @@
},
{
"name": "string.regexp.js",
"begin": "((?<![_$[:alnum:])\\]]|\\+\\+|--|}|\\*\\/)|((?<=^return|[^\\._$[:alnum:]]return|^case|[^\\._$[:alnum:]]case))\\s*)\\/(?![\\/*])(?=(?:[^\\/\\\\\\[]|\\\\.|\\[([^\\]\\\\]|\\\\.)+\\])+\\/[gimsuy]*(?!\\s*[a-zA-Z0-9_$]))",
"begin": "((?<![_$[:alnum:])\\]]|\\+\\+|--|}|\\*\\/)|((?<=^return|[^\\._$[:alnum:]]return|^case|[^\\._$[:alnum:]]case))\\s*)\\/(?![\\/*])(?=(?:[^\\/\\\\\\[]|\\\\.|\\[([^\\]\\\\]|\\\\.)+\\])+\\/([gimsuy]+|(?![\\/\\*])|(?=\\/\\*))(?!\\s*[a-zA-Z0-9_$]))",
"beginCaptures": {
"0": {
"name": "punctuation.definition.string.begin.js"
@@ -4,7 +4,7 @@
"If you want to provide a fix or improvement, please create a pull request against the original repository.",
"Once accepted there, we are happy to receive an update request."
],
"version": "https://github.com/Microsoft/TypeScript-TmLanguage/commit/477c1b17e273b64af13040c064c9ed62c8b32fba",
"version": "https://github.com/Microsoft/TypeScript-TmLanguage/commit/4daff7b8904bc549dfbee8df1e2f7c82194b9f45",
"name": "JavaScript (with React support)",
"scopeName": "source.js.jsx",
"patterns": [
@@ -2451,7 +2451,7 @@
},
{
"name": "string.regexp.js.jsx",
"begin": "(?<=\\))\\s*\\/(?![\\/*])(?=(?:[^\\/\\\\\\[]|\\\\.|\\[([^\\]\\\\]|\\\\.)+\\])+\\/[gimsuy]*(?!\\s*[a-zA-Z0-9_$]))",
"begin": "(?<=\\))\\s*\\/(?![\\/*])(?=(?:[^\\/\\\\\\[]|\\\\.|\\[([^\\]\\\\]|\\\\.)+\\])+\\/([gimsuy]+|(?![\\/\\*])|(?=\\/\\*))(?!\\s*[a-zA-Z0-9_$]))",
"beginCaptures": {
"0": {
"name": "punctuation.definition.string.begin.js.jsx"
@@ -4572,7 +4572,7 @@
"patterns": [
{
"name": "string.regexp.js.jsx",
"begin": "(?<!\\+\\+|--|})(?<=[=(:,\\[?+!]|^return|[^\\._$[:alnum:]]return|^case|[^\\._$[:alnum:]]case|=>|&&|\\|\\||\\*\\/)\\s*(\\/)(?![\\/*])(?=(?:[^\\/\\\\\\[\\()]|\\\\.|\\[([^\\]\\\\]|\\\\.)+\\]|\\(([^\\)\\\\]|\\\\.)+\\))+\\/[gimsuy]*(?!\\s*[a-zA-Z0-9_$]))",
"begin": "(?<!\\+\\+|--|})(?<=[=(:,\\[?+!]|^return|[^\\._$[:alnum:]]return|^case|[^\\._$[:alnum:]]case|=>|&&|\\|\\||\\*\\/)\\s*(\\/)(?![\\/*])(?=(?:[^\\/\\\\\\[\\()]|\\\\.|\\[([^\\]\\\\]|\\\\.)+\\]|\\(([^\\)\\\\]|\\\\.)+\\))+\\/([gimsuy]+|(?![\\/\\*])|(?=\\/\\*))(?!\\s*[a-zA-Z0-9_$]))",
"beginCaptures": {
"1": {
"name": "punctuation.definition.string.begin.js.jsx"
@@ -4595,7 +4595,7 @@
},
{
"name": "string.regexp.js.jsx",
"begin": "((?<![_$[:alnum:])\\]]|\\+\\+|--|}|\\*\\/)|((?<=^return|[^\\._$[:alnum:]]return|^case|[^\\._$[:alnum:]]case))\\s*)\\/(?![\\/*])(?=(?:[^\\/\\\\\\[]|\\\\.|\\[([^\\]\\\\]|\\\\.)+\\])+\\/[gimsuy]*(?!\\s*[a-zA-Z0-9_$]))",
"begin": "((?<![_$[:alnum:])\\]]|\\+\\+|--|}|\\*\\/)|((?<=^return|[^\\._$[:alnum:]]return|^case|[^\\._$[:alnum:]]case))\\s*)\\/(?![\\/*])(?=(?:[^\\/\\\\\\[]|\\\\.|\\[([^\\]\\\\]|\\\\.)+\\])+\\/([gimsuy]+|(?![\\/\\*])|(?=\\/\\*))(?!\\s*[a-zA-Z0-9_$]))",
"beginCaptures": {
"0": {
"name": "punctuation.definition.string.begin.js.jsx"
@@ -41,13 +41,21 @@ export class Logger {
public log(message: string, data?: any): void {
if (this.trace === Trace.Verbose) {
this.appendLine(`[Log - ${(new Date().toTimeString())}] ${message}`);
this.appendLine(`[Log - ${this.now()}] ${message}`);
if (data) {
this.appendLine(Logger.data2String(data));
}
}
}
private now(): string {
const now = new Date();
return padLeft(now.getUTCHours() + '', 2, '0')
+ ':' + padLeft(now.getMinutes() + '', 2, '0')
+ ':' + padLeft(now.getUTCSeconds() + '', 2, '0') + '.' + now.getMilliseconds();
}
public updateConfiguration() {
this.trace = this.readTrace();
}
@@ -73,3 +81,7 @@ export class Logger {
return JSON.stringify(data, undefined, 2);
}
}
function padLeft(s: string, n: number, pad = ' ') {
return pad.repeat(Math.max(0, n - s.length)) + s;
}
+1 -1
View File
@@ -3,7 +3,7 @@
"version": "0.0.1",
"description": "Dependencies shared by all extensions",
"dependencies": {
"typescript": "3.7.2"
"typescript": "3.7.3-insiders.20191118"
},
"scripts": {
"postinstall": "node ./postinstall"
+2 -2
View File
@@ -6,11 +6,11 @@
"git": {
"name": "language-php",
"repositoryUrl": "https://github.com/atom/language-php",
"commitHash": "43a7b842fb58ac7561184db142344a1b127e0d52"
"commitHash": "b95dc79f30084c25547397ab41388af154e69895"
}
},
"license": "MIT",
"version": "0.44.2"
"version": "0.44.3"
}
],
"version": 1
+28 -8
View File
@@ -4,7 +4,7 @@
"If you want to provide a fix or improvement, please create a pull request against the original repository.",
"Once accepted there, we are happy to receive an update request."
],
"version": "https://github.com/atom/language-php/commit/43a7b842fb58ac7561184db142344a1b127e0d52",
"version": "https://github.com/atom/language-php/commit/b95dc79f30084c25547397ab41388af154e69895",
"scopeName": "source.php",
"patterns": [
{
@@ -439,22 +439,25 @@
"name": "keyword.control.exception.php"
},
{
"begin": "(?i)\\b(function)\\s*(?=\\()",
"begin": "(?i)\\b(function)\\s*(?=&?\\s*\\()",
"beginCaptures": {
"1": {
"name": "storage.type.function.php"
}
},
"end": "(?={)",
"end": "(?=\\s*{)",
"name": "meta.function.closure.php",
"patterns": [
{
"include": "#comments"
},
{
"begin": "\\(",
"begin": "(&)?\\s*(\\()",
"beginCaptures": {
"0": {
"1": {
"name": "storage.modifier.reference.php"
},
"2": {
"name": "punctuation.definition.parameters.begin.bracket.round.php"
}
},
@@ -504,11 +507,25 @@
"name": "meta.function.closure.use.php"
}
]
},
{
"match": "(:)\\s*(\\?)?\\s*((?:\\\\?[a-zA-Z_\\x{7f}-\\x{7fffffff}][a-zA-Z0-9_\\x{7f}-\\x{7fffffff}]*)+)",
"captures": {
"1": {
"name": "keyword.operator.return-value.php"
},
"2": {
"name": "keyword.operator.nullable-type.php"
},
"3": {
"name": "storage.type.php"
}
}
}
]
},
{
"begin": "(?x)\n((?:(?:final|abstract|public|private|protected|static)\\s+)*)\n(function)\\s+\n(?i:\n (__(?:call|construct|debugInfo|destruct|get|set|isset|unset|toString|\n clone|set_state|sleep|wakeup|autoload|invoke|callStatic))\n |([a-zA-Z_\\x{7f}-\\x{7fffffff}][a-zA-Z0-9_\\x{7f}-\\x{7fffffff}]*)\n)\n\\s*(\\()",
"begin": "(?x)\n((?:(?:final|abstract|public|private|protected|static)\\s+)*)\n(function)\\s+\n(?i:\n (__(?:call|construct|debugInfo|destruct|get|set|isset|unset|toString|\n clone|set_state|sleep|wakeup|autoload|invoke|callStatic))\n |(?:(&)?\\s*([a-zA-Z_\\x{7f}-\\x{7fffffff}][a-zA-Z0-9_\\x{7f}-\\x{7fffffff}]*))\n)\n\\s*(\\()",
"beginCaptures": {
"1": {
"patterns": [
@@ -525,14 +542,17 @@
"name": "support.function.magic.php"
},
"4": {
"name": "entity.name.function.php"
"name": "storage.modifier.reference.php"
},
"5": {
"name": "entity.name.function.php"
},
"6": {
"name": "punctuation.definition.parameters.begin.bracket.round.php"
}
},
"contentName": "meta.function.parameters.php",
"end": "(\\))(?:\\s*(:)\\s*(\\?)?\\s*([a-zA-Z_\\x{7f}-\\x{7fffffff}][a-zA-Z0-9_\\x{7f}-\\x{7fffffff}]*))?",
"end": "(\\))(?:\\s*(:)\\s*(\\?)?\\s*((?:\\\\?[a-zA-Z_\\x{7f}-\\x{7fffffff}][a-zA-Z0-9_\\x{7f}-\\x{7fffffff}]*)+))?",
"endCaptures": {
"1": {
"name": "punctuation.definition.parameters.end.bracket.round.php"
+1 -1
View File
@@ -6,7 +6,7 @@
"git": {
"name": "TypeScript-TmLanguage",
"repositoryUrl": "https://github.com/Microsoft/TypeScript-TmLanguage",
"commitHash": "477c1b17e273b64af13040c064c9ed62c8b32fba"
"commitHash": "4daff7b8904bc549dfbee8df1e2f7c82194b9f45"
}
},
"license": "MIT",
@@ -4,7 +4,7 @@
"If you want to provide a fix or improvement, please create a pull request against the original repository.",
"Once accepted there, we are happy to receive an update request."
],
"version": "https://github.com/Microsoft/TypeScript-TmLanguage/commit/477c1b17e273b64af13040c064c9ed62c8b32fba",
"version": "https://github.com/Microsoft/TypeScript-TmLanguage/commit/4daff7b8904bc549dfbee8df1e2f7c82194b9f45",
"name": "TypeScript",
"scopeName": "source.ts",
"patterns": [
@@ -2448,7 +2448,7 @@
},
{
"name": "string.regexp.ts",
"begin": "(?<=\\))\\s*\\/(?![\\/*])(?=(?:[^\\/\\\\\\[]|\\\\.|\\[([^\\]\\\\]|\\\\.)+\\])+\\/[gimsuy]*(?!\\s*[a-zA-Z0-9_$]))",
"begin": "(?<=\\))\\s*\\/(?![\\/*])(?=(?:[^\\/\\\\\\[]|\\\\.|\\[([^\\]\\\\]|\\\\.)+\\])+\\/([gimsuy]+|(?![\\/\\*])|(?=\\/\\*))(?!\\s*[a-zA-Z0-9_$]))",
"beginCaptures": {
"0": {
"name": "punctuation.definition.string.begin.ts"
@@ -4621,7 +4621,7 @@
"patterns": [
{
"name": "string.regexp.ts",
"begin": "(?<!\\+\\+|--|})(?<=[=(:,\\[?+!]|^return|[^\\._$[:alnum:]]return|^case|[^\\._$[:alnum:]]case|=>|&&|\\|\\||\\*\\/)\\s*(\\/)(?![\\/*])(?=(?:[^\\/\\\\\\[\\()]|\\\\.|\\[([^\\]\\\\]|\\\\.)+\\]|\\(([^\\)\\\\]|\\\\.)+\\))+\\/[gimsuy]*(?!\\s*[a-zA-Z0-9_$]))",
"begin": "(?<!\\+\\+|--|})(?<=[=(:,\\[?+!]|^return|[^\\._$[:alnum:]]return|^case|[^\\._$[:alnum:]]case|=>|&&|\\|\\||\\*\\/)\\s*(\\/)(?![\\/*])(?=(?:[^\\/\\\\\\[\\()]|\\\\.|\\[([^\\]\\\\]|\\\\.)+\\]|\\(([^\\)\\\\]|\\\\.)+\\))+\\/([gimsuy]+|(?![\\/\\*])|(?=\\/\\*))(?!\\s*[a-zA-Z0-9_$]))",
"beginCaptures": {
"1": {
"name": "punctuation.definition.string.begin.ts"
@@ -4644,7 +4644,7 @@
},
{
"name": "string.regexp.ts",
"begin": "((?<![_$[:alnum:])\\]]|\\+\\+|--|}|\\*\\/)|((?<=^return|[^\\._$[:alnum:]]return|^case|[^\\._$[:alnum:]]case))\\s*)\\/(?![\\/*])(?=(?:[^\\/\\\\\\[]|\\\\.|\\[([^\\]\\\\]|\\\\.)+\\])+\\/[gimsuy]*(?!\\s*[a-zA-Z0-9_$]))",
"begin": "((?<![_$[:alnum:])\\]]|\\+\\+|--|}|\\*\\/)|((?<=^return|[^\\._$[:alnum:]]return|^case|[^\\._$[:alnum:]]case))\\s*)\\/(?![\\/*])(?=(?:[^\\/\\\\\\[]|\\\\.|\\[([^\\]\\\\]|\\\\.)+\\])+\\/([gimsuy]+|(?![\\/\\*])|(?=\\/\\*))(?!\\s*[a-zA-Z0-9_$]))",
"beginCaptures": {
"0": {
"name": "punctuation.definition.string.begin.ts"
@@ -4,7 +4,7 @@
"If you want to provide a fix or improvement, please create a pull request against the original repository.",
"Once accepted there, we are happy to receive an update request."
],
"version": "https://github.com/Microsoft/TypeScript-TmLanguage/commit/477c1b17e273b64af13040c064c9ed62c8b32fba",
"version": "https://github.com/Microsoft/TypeScript-TmLanguage/commit/4daff7b8904bc549dfbee8df1e2f7c82194b9f45",
"name": "TypeScriptReact",
"scopeName": "source.tsx",
"patterns": [
@@ -2451,7 +2451,7 @@
},
{
"name": "string.regexp.tsx",
"begin": "(?<=\\))\\s*\\/(?![\\/*])(?=(?:[^\\/\\\\\\[]|\\\\.|\\[([^\\]\\\\]|\\\\.)+\\])+\\/[gimsuy]*(?!\\s*[a-zA-Z0-9_$]))",
"begin": "(?<=\\))\\s*\\/(?![\\/*])(?=(?:[^\\/\\\\\\[]|\\\\.|\\[([^\\]\\\\]|\\\\.)+\\])+\\/([gimsuy]+|(?![\\/\\*])|(?=\\/\\*))(?!\\s*[a-zA-Z0-9_$]))",
"beginCaptures": {
"0": {
"name": "punctuation.definition.string.begin.tsx"
@@ -4572,7 +4572,7 @@
"patterns": [
{
"name": "string.regexp.tsx",
"begin": "(?<!\\+\\+|--|})(?<=[=(:,\\[?+!]|^return|[^\\._$[:alnum:]]return|^case|[^\\._$[:alnum:]]case|=>|&&|\\|\\||\\*\\/)\\s*(\\/)(?![\\/*])(?=(?:[^\\/\\\\\\[\\()]|\\\\.|\\[([^\\]\\\\]|\\\\.)+\\]|\\(([^\\)\\\\]|\\\\.)+\\))+\\/[gimsuy]*(?!\\s*[a-zA-Z0-9_$]))",
"begin": "(?<!\\+\\+|--|})(?<=[=(:,\\[?+!]|^return|[^\\._$[:alnum:]]return|^case|[^\\._$[:alnum:]]case|=>|&&|\\|\\||\\*\\/)\\s*(\\/)(?![\\/*])(?=(?:[^\\/\\\\\\[\\()]|\\\\.|\\[([^\\]\\\\]|\\\\.)+\\]|\\(([^\\)\\\\]|\\\\.)+\\))+\\/([gimsuy]+|(?![\\/\\*])|(?=\\/\\*))(?!\\s*[a-zA-Z0-9_$]))",
"beginCaptures": {
"1": {
"name": "punctuation.definition.string.begin.tsx"
@@ -4595,7 +4595,7 @@
},
{
"name": "string.regexp.tsx",
"begin": "((?<![_$[:alnum:])\\]]|\\+\\+|--|}|\\*\\/)|((?<=^return|[^\\._$[:alnum:]]return|^case|[^\\._$[:alnum:]]case))\\s*)\\/(?![\\/*])(?=(?:[^\\/\\\\\\[]|\\\\.|\\[([^\\]\\\\]|\\\\.)+\\])+\\/[gimsuy]*(?!\\s*[a-zA-Z0-9_$]))",
"begin": "((?<![_$[:alnum:])\\]]|\\+\\+|--|}|\\*\\/)|((?<=^return|[^\\._$[:alnum:]]return|^case|[^\\._$[:alnum:]]case))\\s*)\\/(?![\\/*])(?=(?:[^\\/\\\\\\[]|\\\\.|\\[([^\\]\\\\]|\\\\.)+\\])+\\/([gimsuy]+|(?![\\/\\*])|(?=\\/\\*))(?!\\s*[a-zA-Z0-9_$]))",
"beginCaptures": {
"0": {
"name": "punctuation.definition.string.begin.tsx"
@@ -859,10 +859,10 @@
"background": {
"activeOnStart": true,
"beginsPattern": {
"regexp": "^\\s*(?:message TS6032:|\\[?\\d{1,2}:\\d{1,2}:\\d{1,2}(?: AM| PM| a\\.m\\.| p\\.m\\.)?(?:\\]| -)) File change detected\\. Starting incremental compilation\\.\\.\\."
"regexp": "^\\s*(?:message TS6032:|\\[?\\D*\\d{1,2}:\\d{1,2}:\\d{1,2}\\D*(?:\\]| -)) File change detected\\. Starting incremental compilation\\.\\.\\."
},
"endsPattern": {
"regexp": "^\\s*(?:message TS6042:|\\[?\\d{1,2}:\\d{1,2}:\\d{1,2}(?: AM| PM| a\\.m\\.| p\\.m\\.)?(?:\\]| -)) (?:Compilation complete\\.|Found \\d+ errors?\\.) Watching for file changes\\."
"regexp": "^\\s*(?:message TS6042:|\\[?\\D*\\d{1,2}:\\d{1,2}:\\d{1,2}\\D*(?:\\]| -)) (?:Compilation complete\\.|Found \\d+ errors?\\.) Watching for file changes\\."
}
}
}
@@ -238,9 +238,14 @@ class TypeScriptRefactorProvider implements vscode.CodeActionProvider {
return undefined;
}
return this.convertApplicableRefactors(response.body, document, rangeOrSelection);
const actions = this.convertApplicableRefactors(response.body, document, rangeOrSelection);
if (!context.only) {
return actions;
}
return this.appendInvalidActions(actions);
}
private convertApplicableRefactors(
body: Proto.ApplicableRefactorInfo[],
document: vscode.TextDocument,
@@ -305,6 +310,16 @@ class TypeScriptRefactorProvider implements vscode.CodeActionProvider {
}
return false;
}
private appendInvalidActions(actions: vscode.CodeAction[]): vscode.CodeAction[] {
if (!actions.some(action => action.kind && Extract_Constant.kind.contains(action.kind))) {
const disabledAction = new vscode.CodeAction('Extract to constant', Extract_Constant.kind);
disabledAction.disabled = localize('extract.disabled', "The current selection cannot be extracted");
disabledAction.isPreferred = true;
actions.push(disabledAction);
}
return actions;
}
}
export function register(
@@ -5,6 +5,9 @@
import * as vscode from 'vscode';
const nulTokenSource = new vscode.CancellationTokenSource();
const noopDisposable = vscode.Disposable.from();
export const nulToken = nulTokenSource.token;
export const nulToken: vscode.CancellationToken = {
isCancellationRequested: false,
onCancellationRequested: () => noopDisposable
};
@@ -41,9 +41,20 @@ export default class Logger {
}
public logLevel(level: LogLevel, message: string, data?: any): void {
this.output.appendLine(`[${level} - ${(new Date().toTimeString())}] ${message}`);
this.output.appendLine(`[${level} - ${this.now()}] ${message}`);
if (data) {
this.output.appendLine(this.data2String(data));
}
}
private now(): string {
const now = new Date();
return padLeft(now.getUTCHours() + '', 2, '0')
+ ':' + padLeft(now.getMinutes() + '', 2, '0')
+ ':' + padLeft(now.getUTCSeconds() + '', 2, '0') + '.' + now.getMilliseconds();
}
}
function padLeft(s: string, n: number, pad = ' ') {
return pad.repeat(Math.max(0, n - s.length)) + s;
}
+64 -16
View File
@@ -7,7 +7,8 @@
"enableProposedApi": true,
"private": true,
"activationEvents": [
"onFileSystem:memfs"
"onFileSystem:memfs",
"onDebug"
],
"main": "./out/extension",
"engines": {
@@ -46,23 +47,70 @@
}
},
"taskDefinitions": [
{
"type": "custombuildscript",
"required": [
"flavor"
],
"properties": {
"flavor": {
"type": "string",
"description": "The build flavor. Should be either '32' or '64'."
},
"flags": {
"type": "array",
"description": "Additional build flags."
}
{
"type": "custombuildscript",
"required": [
"flavor"
],
"properties": {
"flavor": {
"type": "string",
"description": "The build flavor. Should be either '32' or '64'."
},
"flags": {
"type": "array",
"description": "Additional build flags."
}
}
]
}
],
"breakpoints": [
{
"language": "markdown"
}
],
"debuggers": [
{
"type": "mock",
"label": "Mock Debug",
"languages": [
"markdown"
],
"configurationAttributes": {
"launch": {
"required": [
"program"
],
"properties": {
"program": {
"type": "string",
"description": "Absolute path to a text file.",
"default": "${workspaceFolder}/file.md"
},
"stopOnEntry": {
"type": "boolean",
"description": "Automatically stop after launch.",
"default": true
},
"trace": {
"type": "boolean",
"description": "Enable logging of the Debug Adapter Protocol.",
"default": true
}
}
}
},
"initialConfigurations": [
{
"type": "mock",
"request": "launch",
"name": "Debug file.md",
"program": "${workspaceFolder}/file.md"
}
]
}
]
},
"scripts": {
"compile": "node ./node_modules/vscode/bin/compile -watch -p ./",
File diff suppressed because it is too large Load Diff
@@ -55,7 +55,7 @@ suite('window namespace tests', () => {
}
terminal.processId.then(id => {
try {
ok(id > 0);
ok(id && id > 0);
} catch (e) {
done(e);
}
@@ -5,12 +5,20 @@
"publisher": "vscode",
"license": "MIT",
"private": true,
"activationEvents": [
"onLanguage:json"
],
"main": "./out/colorizerTestMain",
"enableProposedApi": true,
"engines": {
"vscode": "*"
},
"scripts": {
"vscode:prepublish": "node ../../node_modules/gulp/bin/gulp.js --gulpfile ../../build/gulpfile.extensions.js compile-extension:vscode-colorize-tests ./tsconfig.json"
},
"dependencies": {
"jsonc-parser": "2.2.0"
},
"devDependencies": {
"@types/node": "^12.11.7",
"mocha-junit-reporter": "^1.17.0",
@@ -0,0 +1,62 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import * as vscode from 'vscode';
import * as jsoncParser from 'jsonc-parser';
export function activate(context: vscode.ExtensionContext): any {
console.log('activates');
const tokenModifiers = ['static', 'abstract', 'deprecated'];
const tokenTypes = ['strings', 'types', 'structs', 'classes', 'functions', 'variables'];
const legend = new vscode.SemanticColoringLegend(tokenTypes, tokenModifiers);
/*
* A certain token (at index `i` is encoded using 5 uint32 integers):
* - at index `5*i` - `deltaLine`: token line number, relative to `SemanticColoringArea.line`
* - at index `5*i+1` - `startCharacter`: token start character offset inside the line (inclusive)
* - at index `5*i+2` - `endCharacter`: token end character offset inside the line (exclusive)
* - at index `5*i+3` - `tokenType`: will be looked up in `SemanticColoringLegend.tokenTypes`
* - at index `5*i+4` - `tokenModifiers`: each set bit will be looked up in `SemanticColoringLegend.tokenModifiers`
*/
const semanticHighlightProvider: vscode.SemanticColoringProvider = {
provideSemanticColoring(document: vscode.TextDocument): vscode.ProviderResult<vscode.SemanticColoring> {
const result: number[] = [];
console.log('provideSemanticColoring');
const visitor: jsoncParser.JSONVisitor = {
onObjectProperty: (property: string, _offset: number, length: number, startLine: number, startCharacter: number) => {
result.push(startLine);
result.push(startCharacter);
result.push(startCharacter + length);
const [type, ...modifiers] = property.split('.');
let tokenType = legend.tokenTypes.indexOf(type);
if (tokenType === -1) {
tokenType = 0;
}
result.push(tokenType);
let tokenModifiers = 0;
for (let i = 0; i < modifiers.length; i++) {
const index = legend.tokenModifiers.indexOf(modifiers[i]);
if (index !== -1) {
tokenModifiers = tokenModifiers | 1 << index;
}
}
result.push(tokenModifiers);
}
};
jsoncParser.visit(document.getText(), visitor);
return new vscode.SemanticColoring([new vscode.SemanticColoringArea(0, new Uint32Array(result))]);
}
};
context.subscriptions.push(vscode.languages.registerSemanticColoringProvider({ pattern: '**/color-test.json' }, semanticHighlightProvider, legend));
}
+3 -1
View File
@@ -3,5 +3,7 @@
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
/// <reference path="../../../../src/vs/vscode.d.ts" />
/// <reference path="../../../../src/vs/vscode.proposed.d.ts" />
/// <reference types='@types/node'/>
/// <reference path='../../../../src/vs/vscode.d.ts'/>
@@ -1042,6 +1042,11 @@ json3@3.3.2:
resolved "https://registry.yarnpkg.com/json3/-/json3-3.3.2.tgz#3c0434743df93e2f5c42aee7b19bcb483575f4e1"
integrity sha1-PAQ0dD35Pi9cQq7nsZvLSDV19OE=
jsonc-parser@2.2.0:
version "2.2.0"
resolved "https://registry.yarnpkg.com/jsonc-parser/-/jsonc-parser-2.2.0.tgz#f206f87f9d49d644b7502052c04e82dd6392e9ef"
integrity sha512-4fLQxW1j/5fWj6p78vAlAafoCKtuBm6ghv+Ij5W2DrDx0qE+ZdEl2c6Ko1mgJNF5ftX1iEWQQ4Ap7+3GlhjkOA==
jsonify@~0.0.0:
version "0.0.0"
resolved "https://registry.yarnpkg.com/jsonify/-/jsonify-0.0.0.tgz#2c74b6ee41d93ca51b7b5aaee8f503631d252a73"
+4 -4
View File
@@ -2,7 +2,7 @@
# yarn lockfile v1
typescript@3.7.2:
version "3.7.2"
resolved "https://registry.yarnpkg.com/typescript/-/typescript-3.7.2.tgz#27e489b95fa5909445e9fef5ee48d81697ad18fb"
integrity sha512-ml7V7JfiN2Xwvcer+XAf2csGO1bPBdRbFCkYBczNZggrBZ9c7G3riSUeJmqEU5uOtXNPMhE3n+R4FA/3YOAWOQ==
typescript@3.7.3-insiders.20191118:
version "3.7.3-insiders.20191118"
resolved "https://registry.yarnpkg.com/typescript/-/typescript-3.7.3-insiders.20191118.tgz#86d3b1de1859d70b0a081b708a223f8f3c6a4d46"
integrity sha512-r06UsJwJzLwgRkf3Or2T5tBnUmp8RD5gOHkC6ax9mLHu5r7voo1WAUpvG09R92GvdEQsgZXxOUhdEJWEoc/5sA==
+5 -5
View File
@@ -1,7 +1,7 @@
{
"name": "code-oss-dev",
"version": "1.41.0",
"distro": "b2b71bcd54560577429f8ee10aa270a41036a09c",
"distro": "531a9666cfe4c178d84b8540af753fa5ee456f33",
"author": {
"name": "Microsoft Corporation"
},
@@ -39,10 +39,10 @@
"jschardet": "2.1.1",
"keytar": "^4.11.0",
"native-is-elevated": "0.4.1",
"native-keymap": "2.0.0",
"native-watchdog": "1.2.0",
"native-keymap": "2.1.0",
"native-watchdog": "1.3.0",
"node-pty": "^0.10.0-beta2",
"onigasm-umd": "^2.2.4",
"onigasm-umd": "2.2.5",
"semver-umd": "^5.5.3",
"spdlog": "^0.11.1",
"sudo-prompt": "9.1.1",
@@ -52,7 +52,7 @@
"vscode-proxy-agent": "^0.5.2",
"vscode-ripgrep": "^1.5.7",
"vscode-sqlite3": "4.0.9",
"vscode-textmate": "^4.3.0",
"vscode-textmate": "4.4.0",
"xterm": "4.3.0-beta17",
"xterm-addon-search": "0.4.0-beta4",
"xterm-addon-web-links": "0.2.1",
+3 -3
View File
@@ -10,16 +10,16 @@
"https-proxy-agent": "^2.2.3",
"iconv-lite": "0.5.0",
"jschardet": "2.1.1",
"native-watchdog": "1.2.0",
"native-watchdog": "1.3.0",
"node-pty": "^0.10.0-beta2",
"onigasm-umd": "^2.2.4",
"onigasm-umd": "2.2.5",
"semver-umd": "^5.5.3",
"spdlog": "^0.11.1",
"vscode-minimist": "^1.2.2",
"vscode-nsfw": "1.2.8",
"vscode-proxy-agent": "^0.5.2",
"vscode-ripgrep": "^1.5.7",
"vscode-textmate": "^4.3.0",
"vscode-textmate": "4.4.0",
"xterm": "4.3.0-beta17",
"xterm-addon-search": "0.4.0-beta4",
"xterm-addon-web-links": "0.2.1",
+2 -2
View File
@@ -2,9 +2,9 @@
"name": "vscode-web",
"version": "0.0.0",
"dependencies": {
"onigasm-umd": "^2.2.4",
"onigasm-umd": "2.2.5",
"semver-umd": "^5.5.3",
"vscode-textmate": "^4.3.0",
"vscode-textmate": "4.4.0",
"xterm": "4.3.0-beta17",
"xterm-addon-search": "0.4.0-beta4",
"xterm-addon-web-links": "0.2.1",
+8 -8
View File
@@ -7,10 +7,10 @@ nan@^2.14.0:
resolved "https://registry.yarnpkg.com/nan/-/nan-2.14.0.tgz#7818f722027b2459a86f0295d434d1fc2336c52c"
integrity sha512-INOFj37C7k3AfaNTtX8RhsTw7qRy7eLET14cROi9+5HAVbbHuIWUHEauBv5qT4Av2tWasiTY1Jw6puUNqRJXQg==
onigasm-umd@^2.2.4:
version "2.2.4"
resolved "https://registry.yarnpkg.com/onigasm-umd/-/onigasm-umd-2.2.4.tgz#27ee87f7496c66ad40cebfbc0d418c19bb7db5ec"
integrity sha512-N9VqCUhl9KBuzm47vcK8T/xUnbYylIhMN45Rwltlo1sZc3QUDda6SxIlyVB8r0SJQwURv8JOHjyXjjCriGvzRg==
onigasm-umd@2.2.5:
version "2.2.5"
resolved "https://registry.yarnpkg.com/onigasm-umd/-/onigasm-umd-2.2.5.tgz#f104247334a543accd3f8d641a4d99b3d908d6a1"
integrity sha512-R3qD7hq6i2bBklF+QyjqZl/G4fe7GwtukI28YLH2vuiatqx52tb9vpg2sxwemKc3nF76SgkeyOKJLchBmTm0Aw==
oniguruma@^7.2.0:
version "7.2.0"
@@ -24,10 +24,10 @@ semver-umd@^5.5.3:
resolved "https://registry.yarnpkg.com/semver-umd/-/semver-umd-5.5.3.tgz#b64d7a2d4f5a717b369d56e31940a38e47e34d1e"
integrity sha512-HOnQrn2iKnVe/xlqCTzMXQdvSz3rPbD0DmQXYuQ+oK1dpptGFfPghonQrx5JHl2O7EJwDqtQnjhE7ME23q6ngw==
vscode-textmate@^4.3.0:
version "4.3.0"
resolved "https://registry.yarnpkg.com/vscode-textmate/-/vscode-textmate-4.3.0.tgz#6e1f0f273d84148cfa1e9c7ed85bd16c974f9f61"
integrity sha512-MhEZ3hvxOVuYGsrRzW/PZLDR2VdtG2+V6TIKPvmE9JT+RAq/OtPlrFd1+ZQwBefoHEhjRNuRJ0OktcFezuxPmg==
vscode-textmate@4.4.0:
version "4.4.0"
resolved "https://registry.yarnpkg.com/vscode-textmate/-/vscode-textmate-4.4.0.tgz#14032afeb50152e8f53258c95643e555f2948305"
integrity sha512-dFpm2eK0HwEjeFSD1DDh3j0q47bDSVuZt20RiJWxGqjtm73Wu2jip3C2KaZI3dQx/fSeeXCr/uEN4LNaNj7Ytw==
dependencies:
oniguruma "^7.2.0"
+12 -12
View File
@@ -261,10 +261,10 @@ nan@^2.10.0, nan@^2.14.0:
resolved "https://registry.yarnpkg.com/nan/-/nan-2.14.0.tgz#7818f722027b2459a86f0295d434d1fc2336c52c"
integrity sha512-INOFj37C7k3AfaNTtX8RhsTw7qRy7eLET14cROi9+5HAVbbHuIWUHEauBv5qT4Av2tWasiTY1Jw6puUNqRJXQg==
native-watchdog@1.2.0:
version "1.2.0"
resolved "https://registry.yarnpkg.com/native-watchdog/-/native-watchdog-1.2.0.tgz#9c710093ac6e9e60b19517cb1ef4ac9d7c997395"
integrity sha512-jOOoA3PLSxt1adaeuEW7ymV9cApZiDxn4y4iFs7b4sP73EG+5Lsz+OgUNFcGMyrtznTw6ZvlLcilIN4jeAIgaQ==
native-watchdog@1.3.0:
version "1.3.0"
resolved "https://registry.yarnpkg.com/native-watchdog/-/native-watchdog-1.3.0.tgz#88cee94c9dc766b85c8506eda14c8bd8c9618e27"
integrity sha512-WOjGRNGkYZ5MXsntcvCYrKtSYMaewlbCFplbcUVo9bE80LPVt8TAVFHYWB8+a6fWCGYheq21+Wtt6CJrUaCJhw==
node-addon-api@1.6.2:
version "1.6.2"
@@ -283,10 +283,10 @@ normalize-path@^3.0.0, normalize-path@~3.0.0:
resolved "https://registry.yarnpkg.com/normalize-path/-/normalize-path-3.0.0.tgz#0dcd69ff23a1c9b11fd0978316644a0388216a65"
integrity sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==
onigasm-umd@^2.2.4:
version "2.2.4"
resolved "https://registry.yarnpkg.com/onigasm-umd/-/onigasm-umd-2.2.4.tgz#27ee87f7496c66ad40cebfbc0d418c19bb7db5ec"
integrity sha512-N9VqCUhl9KBuzm47vcK8T/xUnbYylIhMN45Rwltlo1sZc3QUDda6SxIlyVB8r0SJQwURv8JOHjyXjjCriGvzRg==
onigasm-umd@2.2.5:
version "2.2.5"
resolved "https://registry.yarnpkg.com/onigasm-umd/-/onigasm-umd-2.2.5.tgz#f104247334a543accd3f8d641a4d99b3d908d6a1"
integrity sha512-R3qD7hq6i2bBklF+QyjqZl/G4fe7GwtukI28YLH2vuiatqx52tb9vpg2sxwemKc3nF76SgkeyOKJLchBmTm0Aw==
oniguruma@^7.2.0:
version "7.2.0"
@@ -399,10 +399,10 @@ vscode-ripgrep@^1.5.7:
resolved "https://registry.yarnpkg.com/vscode-ripgrep/-/vscode-ripgrep-1.5.7.tgz#acb6b548af488a4bca5d0f1bb5faf761343289ce"
integrity sha512-/Vsz/+k8kTvui0q3O74pif9FK0nKopgFTiGNVvxicZANxtSA8J8gUE9GQ/4dpi7D/2yI/YVORszwVskFbz46hQ==
vscode-textmate@^4.3.0:
version "4.3.0"
resolved "https://registry.yarnpkg.com/vscode-textmate/-/vscode-textmate-4.3.0.tgz#6e1f0f273d84148cfa1e9c7ed85bd16c974f9f61"
integrity sha512-MhEZ3hvxOVuYGsrRzW/PZLDR2VdtG2+V6TIKPvmE9JT+RAq/OtPlrFd1+ZQwBefoHEhjRNuRJ0OktcFezuxPmg==
vscode-textmate@4.4.0:
version "4.4.0"
resolved "https://registry.yarnpkg.com/vscode-textmate/-/vscode-textmate-4.4.0.tgz#14032afeb50152e8f53258c95643e555f2948305"
integrity sha512-dFpm2eK0HwEjeFSD1DDh3j0q47bDSVuZt20RiJWxGqjtm73Wu2jip3C2KaZI3dQx/fSeeXCr/uEN4LNaNj7Ytw==
dependencies:
oniguruma "^7.2.0"
+8
View File
@@ -227,6 +227,14 @@ function getMediaMime(forPath) {
*/
async function serveFile(req, res, filePath, responseHeaders = Object.create(null)) {
try {
// Sanity checks
filePath = path.normalize(filePath); // ensure no "." and ".."
if (filePath.indexOf(`${APP_ROOT}${path.sep}`) !== 0) {
// invalid location outside of APP_ROOT
return serveError(req, res, 400, `Bad request.`);
}
const stat = await util.promisify(fs.stat)(filePath);
// Check if file modified since
+1 -1
View File
@@ -1,4 +1,4 @@
// Type definitions for Electron 6.1.4
// Type definitions for Electron 6.1.5
// Project: http://electronjs.org/
// Definitions by: The Electron Team <https://github.com/electron/electron>
// Definitions: https://github.com/electron/electron-typescript-definitions
-93
View File
@@ -1,93 +0,0 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
declare module 'native-keymap' {
export interface IWindowsKeyMapping {
vkey: string;
value: string;
withShift: string;
withAltGr: string;
withShiftAltGr: string;
}
export interface IWindowsKeyboardMapping {
[code: string]: IWindowsKeyMapping;
}
export interface ILinuxKeyMapping {
value: string;
withShift: string;
withAltGr: string;
withShiftAltGr: string;
}
export interface ILinuxKeyboardMapping {
[code: string]: ILinuxKeyMapping;
}
export interface IMacKeyMapping {
value: string;
withShift: string;
withAltGr: string;
withShiftAltGr: string;
valueIsDeadKey: boolean;
withShiftIsDeadKey: boolean;
withAltGrIsDeadKey: boolean;
withShiftAltGrIsDeadKey: boolean;
}
export interface IMacKeyboardMapping {
[code: string]: IMacKeyMapping;
}
export type IKeyboardMapping = IWindowsKeyboardMapping | ILinuxKeyboardMapping | IMacKeyboardMapping;
export function getKeyMap(): IKeyboardMapping;
/* __GDPR__FRAGMENT__
"IKeyboardLayoutInfo" : {
"name" : { "classification": "SystemMetaData", "purpose": "FeatureInsight" },
"id": { "classification": "SystemMetaData", "purpose": "FeatureInsight" },
"text": { "classification": "SystemMetaData", "purpose": "FeatureInsight" }
}
*/
export interface IWindowsKeyboardLayoutInfo {
name: string;
id: string;
text: string;
}
/* __GDPR__FRAGMENT__
"IKeyboardLayoutInfo" : {
"model" : { "classification": "SystemMetaData", "purpose": "FeatureInsight" },
"layout": { "classification": "SystemMetaData", "purpose": "FeatureInsight" },
"variant": { "classification": "SystemMetaData", "purpose": "FeatureInsight" },
"options": { "classification": "SystemMetaData", "purpose": "FeatureInsight" },
"rules": { "classification": "SystemMetaData", "purpose": "FeatureInsight" }
}
*/
export interface ILinuxKeyboardLayoutInfo {
model: string;
layout: string;
variant: string;
options: string;
rules: string;
}
/* __GDPR__FRAGMENT__
"IKeyboardLayoutInfo" : {
"id" : { "classification": "SystemMetaData", "purpose": "FeatureInsight" },
"lang": { "classification": "SystemMetaData", "purpose": "FeatureInsight" }
}
*/
export interface IMacKeyboardLayoutInfo {
id: string;
lang: string;
}
export type IKeyboardLayoutInfo = IWindowsKeyboardLayoutInfo | ILinuxKeyboardLayoutInfo | IMacKeyboardLayoutInfo;
export function getCurrentKeyboardLayout(): IKeyboardLayoutInfo;
export function onDidChangeKeyboardLayout(callback: () => void): void;
export function isISOKeyboard(): boolean;
}
-17
View File
@@ -1,17 +0,0 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
declare module 'native-watchdog' {
/**
* Start monitoring for a certain pid to exist.
* If the process indicated by pid ceases to execute,
* the current process will exit in 6 seconds with exit code 87
*/
export function start(pid: number): void;
export function exit(exitCode: number): void;
}
-33
View File
@@ -1,33 +0,0 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
declare module "onigasm-umd" {
function loadWASM(data: string | ArrayBuffer): Promise<void>;
class OnigString {
constructor(content: string);
readonly content: string;
readonly dispose?: () => void;
}
class OnigScanner {
constructor(patterns: string[]);
findNextMatchSync(string: string | OnigString, startPosition: number): IOnigMatch;
}
export interface IOnigCaptureIndex {
index: number
start: number
end: number
length: number
}
export interface IOnigMatch {
index: number
captureIndices: IOnigCaptureIndex[]
scanner: OnigScanner
}
}
-256
View File
@@ -1,256 +0,0 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
declare module "vscode-textmate" {
/**
* A single theme setting.
*/
export interface IRawThemeSetting {
readonly name?: string;
readonly scope?: string | string[];
readonly settings: {
readonly fontStyle?: string;
readonly foreground?: string;
readonly background?: string;
};
}
/**
* A TextMate theme.
*/
export interface IRawTheme {
readonly name?: string;
readonly settings: IRawThemeSetting[];
}
export interface Thenable<T> extends PromiseLike<T> {
}
/**
* A registry helper that can locate grammar file paths given scope names.
*/
export interface RegistryOptions {
theme?: IRawTheme;
loadGrammar(scopeName: string): Thenable<IRawGrammar | undefined | null>;
getInjections?(scopeName: string): string[];
getOnigLib?(): Thenable<IOnigLib>;
}
/**
* A map from scope name to a language id. Please do not use language id 0.
*/
export interface IEmbeddedLanguagesMap {
[scopeName: string]: number;
}
/**
* A map from selectors to token types.
*/
export interface ITokenTypeMap {
[selector: string]: StandardTokenType;
}
export const enum StandardTokenType {
Other = 0,
Comment = 1,
String = 2,
RegEx = 4,
}
export interface IGrammarConfiguration {
embeddedLanguages?: IEmbeddedLanguagesMap;
tokenTypes?: ITokenTypeMap;
}
/**
* The registry that will hold all grammars.
*/
export class Registry {
private readonly _locator;
private readonly _syncRegistry;
constructor(locator?: RegistryOptions);
/**
* Change the theme. Once called, no previous `ruleStack` should be used anymore.
*/
setTheme(theme: IRawTheme): void;
/**
* Returns a lookup array for color ids.
*/
getColorMap(): string[];
/**
* Load the grammar for `scopeName` and all referenced included grammars asynchronously.
* Please do not use language id 0.
*/
loadGrammarWithEmbeddedLanguages(initialScopeName: string, initialLanguage: number, embeddedLanguages: IEmbeddedLanguagesMap): Thenable<IGrammar>;
/**
* Load the grammar for `scopeName` and all referenced included grammars asynchronously.
* Please do not use language id 0.
*/
loadGrammarWithConfiguration(initialScopeName: string, initialLanguage: number, configuration: IGrammarConfiguration): Thenable<IGrammar>;
/**
* Load the grammar for `scopeName` and all referenced included grammars asynchronously.
*/
loadGrammar(initialScopeName: string): Thenable<IGrammar>;
private _loadGrammar;
/**
* Adds a rawGrammar.
*/
addGrammar(rawGrammar: IRawGrammar, injections?: string[], initialLanguage?: number, embeddedLanguages?: IEmbeddedLanguagesMap): Thenable<IGrammar>;
/**
* Get the grammar for `scopeName`. The grammar must first be created via `loadGrammar` or `addGrammar`.
*/
grammarForScopeName(scopeName: string, initialLanguage?: number, embeddedLanguages?: IEmbeddedLanguagesMap, tokenTypes?: ITokenTypeMap): Thenable<IGrammar>;
}
/**
* A grammar
*/
export interface IGrammar {
/**
* Tokenize `lineText` using previous line state `prevState`.
*/
tokenizeLine(lineText: string, prevState: StackElement | null): ITokenizeLineResult;
/**
* Tokenize `lineText` using previous line state `prevState`.
* The result contains the tokens in binary format, resolved with the following information:
* - language
* - token type (regex, string, comment, other)
* - font style
* - foreground color
* - background color
* e.g. for getting the languageId: `(metadata & MetadataConsts.LANGUAGEID_MASK) >>> MetadataConsts.LANGUAGEID_OFFSET`
*/
tokenizeLine2(lineText: string, prevState: StackElement | null): ITokenizeLineResult2;
}
export interface ITokenizeLineResult {
readonly tokens: IToken[];
/**
* The `prevState` to be passed on to the next line tokenization.
*/
readonly ruleStack: StackElement;
}
/**
* Helpers to manage the "collapsed" metadata of an entire StackElement stack.
* The following assumptions have been made:
* - languageId < 256 => needs 8 bits
* - unique color count < 512 => needs 9 bits
*
* The binary format is:
* - -------------------------------------------
* 3322 2222 2222 1111 1111 1100 0000 0000
* 1098 7654 3210 9876 5432 1098 7654 3210
* - -------------------------------------------
* xxxx xxxx xxxx xxxx xxxx xxxx xxxx xxxx
* bbbb bbbb bfff ffff ffFF FTTT LLLL LLLL
* - -------------------------------------------
* - L = LanguageId (8 bits)
* - T = StandardTokenType (3 bits)
* - F = FontStyle (3 bits)
* - f = foreground color (9 bits)
* - b = background color (9 bits)
*/
export const enum MetadataConsts {
LANGUAGEID_MASK = 255,
TOKEN_TYPE_MASK = 1792,
FONT_STYLE_MASK = 14336,
FOREGROUND_MASK = 8372224,
BACKGROUND_MASK = 4286578688,
LANGUAGEID_OFFSET = 0,
TOKEN_TYPE_OFFSET = 8,
FONT_STYLE_OFFSET = 11,
FOREGROUND_OFFSET = 14,
BACKGROUND_OFFSET = 23,
}
export interface ITokenizeLineResult2 {
/**
* The tokens in binary format. Each token occupies two array indices. For token i:
* - at offset 2*i => startIndex
* - at offset 2*i + 1 => metadata
*
*/
readonly tokens: Uint32Array;
/**
* The `prevState` to be passed on to the next line tokenization.
*/
readonly ruleStack: StackElement;
}
export interface IToken {
startIndex: number;
readonly endIndex: number;
readonly scopes: string[];
}
/**
* **IMPORTANT** - Immutable!
*/
export interface StackElement {
_stackElementBrand: void;
readonly depth: number;
clone(): StackElement;
equals(other: StackElement): boolean;
}
export const INITIAL: StackElement;
export const parseRawGrammar: (content: string, filePath?: string) => IRawGrammar;
export interface ILocation {
readonly filename: string;
readonly line: number;
readonly char: number;
}
export interface ILocatable {
readonly $vscodeTextmateLocation?: ILocation;
}
export interface IRawGrammar extends ILocatable {
repository: IRawRepository;
readonly scopeName: string;
readonly patterns: IRawRule[];
readonly injections?: {
[expression: string]: IRawRule;
};
readonly injectionSelector?: string;
readonly fileTypes?: string[];
readonly name?: string;
readonly firstLineMatch?: string;
}
export interface IRawRepositoryMap {
[name: string]: IRawRule;
$self: IRawRule;
$base: IRawRule;
}
export type IRawRepository = IRawRepositoryMap & ILocatable;
export interface IRawRule extends ILocatable {
id?: number;
readonly include?: string;
readonly name?: string;
readonly contentName?: string;
readonly match?: string;
readonly captures?: IRawCaptures;
readonly begin?: string;
readonly beginCaptures?: IRawCaptures;
readonly end?: string;
readonly endCaptures?: IRawCaptures;
readonly while?: string;
readonly whileCaptures?: IRawCaptures;
readonly patterns?: IRawRule[];
readonly repository?: IRawRepository;
readonly applyEndPatternLast?: boolean;
}
export interface IRawCapturesMap {
[captureId: string]: IRawRule;
}
export type IRawCaptures = IRawCapturesMap & ILocatable;
export interface IOnigLib {
createOnigScanner(sources: string[]): OnigScanner;
createOnigString(sources: string): OnigString;
}
export interface IOnigCaptureIndex {
start: number;
end: number;
length: number;
}
export interface IOnigMatch {
index: number;
captureIndices: IOnigCaptureIndex[];
scanner: OnigScanner;
}
export interface OnigScanner {
findNextMatchSync(string: string | OnigString, startPosition: number): IOnigMatch;
}
export interface OnigString {
readonly content: string;
readonly dispose?: () => void;
}
}
+1 -1
View File
@@ -19,7 +19,7 @@ export const BrowserFeatures = {
clipboard: {
writeText: (
platform.isNative
|| document.queryCommandSupported('copy')
|| (document.queryCommandSupported && document.queryCommandSupported('copy'))
|| !!(navigator && navigator.clipboard && navigator.clipboard.writeText)
),
readText: (
+21 -1
View File
@@ -267,10 +267,20 @@ export let addStandardDisposableListener: IAddStandardDisposableListenerSignatur
return addDisposableListener(node, type, wrapHandler, useCapture);
};
export let addStandardDisposableGenericMouseDownListner = function addStandardDisposableListener(node: HTMLElement, handler: (event: any) => void, useCapture?: boolean): IDisposable {
let wrapHandler = _wrapAsStandardMouseEvent(handler);
return addDisposableGenericMouseDownListner(node, wrapHandler, useCapture);
};
export function addDisposableGenericMouseDownListner(node: EventTarget, handler: (event: any) => void, useCapture?: boolean): IDisposable {
return addDisposableListener(node, platform.isIOS && BrowserFeatures.pointerEvents ? EventType.POINTER_DOWN : EventType.MOUSE_DOWN, handler, useCapture);
}
export function addDisposableGenericMouseMoveListner(node: EventTarget, handler: (event: any) => void, useCapture?: boolean): IDisposable {
return addDisposableListener(node, platform.isIOS && BrowserFeatures.pointerEvents ? EventType.POINTER_MOVE : EventType.MOUSE_MOVE, handler, useCapture);
}
export function addDisposableGenericMouseUpListner(node: EventTarget, handler: (event: any) => void, useCapture?: boolean): IDisposable {
return addDisposableListener(node, platform.isIOS && BrowserFeatures.pointerEvents ? EventType.POINTER_UP : EventType.MOUSE_UP, handler, useCapture);
}
@@ -502,7 +512,16 @@ export function getClientArea(element: HTMLElement): Dimension {
// If visual view port exits and it's on mobile, it should be used instead of window innerWidth / innerHeight, or document.body.clientWidth / document.body.clientHeight
if (platform.isIOS && (<any>window).visualViewport) {
return new Dimension((<any>window).visualViewport.width, (<any>window).visualViewport.height);
const width = (<any>window).visualViewport.width;
const height = (<any>window).visualViewport.height - (
browser.isStandalone
// in PWA mode, the visual viewport always includes the safe-area-inset-bottom (which is for the home indicator)
// even when you are using the onscreen monitor, the visual viewport will include the area between system statusbar and the onscreen keyboard
// plus the area between onscreen keyboard and the bottom bezel, which is 20px on iOS.
? (20 + 4) // + 4px for body margin
: 0
);
return new Dimension(width, height);
}
// Try innerWidth / innerHeight
@@ -882,6 +901,7 @@ export const EventType = {
MOUSE_LEAVE: 'mouseleave',
POINTER_UP: 'pointerup',
POINTER_DOWN: 'pointerdown',
POINTER_MOVE: 'pointermove',
CONTEXT_MENU: 'contextmenu',
WHEEL: 'wheel',
// Keyboard
+24
View File
@@ -33,6 +33,7 @@ export interface GestureEvent extends MouseEvent {
translationY: number;
pageX: number;
pageY: number;
tapCount: number;
}
interface Touch {
@@ -76,6 +77,11 @@ export class Gesture extends Disposable {
private activeTouches: { [id: number]: TouchData; };
private _lastSetTapCountTime: number;
private static readonly CLEAR_TAP_COUNT_TIME = 400; // ms
private constructor() {
super();
@@ -83,6 +89,7 @@ export class Gesture extends Disposable {
this.handle = null;
this.targets = [];
this.ignoreTargets = [];
this._lastSetTapCountTime = 0;
this._register(DomUtils.addDisposableListener(document, 'touchstart', (e: TouchEvent) => this.onTouchStart(e)));
this._register(DomUtils.addDisposableListener(document, 'touchend', (e: TouchEvent) => this.onTouchEnd(e)));
this._register(DomUtils.addDisposableListener(document, 'touchmove', (e: TouchEvent) => this.onTouchMove(e)));
@@ -243,10 +250,27 @@ export class Gesture extends Disposable {
let event = <GestureEvent>(<any>document.createEvent('CustomEvent'));
event.initEvent(type, false, true);
event.initialTarget = initialTarget;
event.tapCount = 0;
return event;
}
private dispatchEvent(event: GestureEvent): void {
if (event.type === EventType.Tap) {
const currentTime = (new Date()).getTime();
let setTapCount = 0;
if (currentTime - this._lastSetTapCountTime > Gesture.CLEAR_TAP_COUNT_TIME) {
setTapCount = 1;
} else {
setTapCount = 2;
}
this._lastSetTapCountTime = currentTime;
event.tapCount = setTapCount;
} else if (event.type === EventType.Change || event.type === EventType.Contextmenu) {
// tap is canceled by scrolling or context menu
this._lastSetTapCountTime = 0;
}
for (let i = 0; i < this.ignoreTargets.length; i++) {
if (event.initialTarget instanceof Node && this.ignoreTargets[i].contains(event.initialTarget)) {
return;
@@ -5,7 +5,7 @@
@font-face {
font-family: "codicon";
src: url("./codicon.ttf?34cea5159eda573d2422092d6f8c2c77") format("truetype");
src: url("./codicon.ttf?c4e66586cd3ad4acc55fc456c0760dec") format("truetype");
}
.codicon[class*='codicon-'] {
@@ -401,4 +401,8 @@
.codicon-debug-breakpoint-stackframe-focused:before { content: "\eb8b" }
.codicon-debug-breakpoint-unsupported:before { content: "\eb8c" }
.codicon-symbol-string:before { content: "\eb8d" }
.codicon-debug-step-back:before { content: "\f101" }
.codicon-debug-reverse-continue:before { content: "\eb8e" }
.codicon-debug-step-back:before { content: "\eb8f" }
.codicon-debug-restart-frame:before { content: "\eb90" }
.codicon-debug-alternate:before { content: "\eb91" }
.codicon-debug-alt:before { content: "\f101" }
+3 -2
View File
@@ -171,7 +171,7 @@ export class InputBox extends Widget {
this.maxHeight = typeof this.options.flexibleMaxHeight === 'number' ? this.options.flexibleMaxHeight : Number.POSITIVE_INFINITY;
this.mirror = dom.append(wrapper, $('div.mirror'));
this.mirror.innerHTML = '&nbsp;';
this.mirror.innerHTML = '&#160;';
this.scrollableElement = new ScrollableElement(this.element, { vertical: ScrollbarVisibility.Auto });
@@ -305,6 +305,7 @@ export class InputBox extends Widget {
}
public disable(): void {
this.blur();
this.input.disabled = true;
this._hideMessage();
}
@@ -529,7 +530,7 @@ export class InputBox extends Widget {
if (mirrorTextContent) {
this.mirror.textContent = value + suffix;
} else {
this.mirror.innerHTML = '&nbsp;';
this.mirror.innerHTML = '&#160;';
}
this.layout();
+5 -1
View File
@@ -856,7 +856,11 @@ export class ListView<T> implements ISpliceable<T>, IDisposable {
if (feedback[0] === -1) { // entire list feedback
DOM.addClass(this.domNode, 'drop-target');
this.currentDragFeedbackDisposable = toDisposable(() => DOM.removeClass(this.domNode, 'drop-target'));
DOM.addClass(this.rowsContainer, 'drop-target');
this.currentDragFeedbackDisposable = toDisposable(() => {
DOM.removeClass(this.domNode, 'drop-target');
DOM.removeClass(this.rowsContainer, 'drop-target');
});
} else {
for (const index of feedback) {
const item = this.items[index]!;
+2 -1
View File
@@ -715,7 +715,7 @@ export class DefaultStyleController implements IStyleController {
if (styles.listBackground) {
if (styles.listBackground.isOpaque()) {
content.push(`.monaco-list${suffix} .monaco-list-rows { background: ${styles.listBackground}; }`);
} else {
} else if (!platform.isMacintosh) { // subpixel AA doesn't exist in macOS
console.warn(`List with id '${this.selectorSuffix}' was styled with a non-opaque background color. This will break sub-pixel antialiasing.`);
}
}
@@ -796,6 +796,7 @@ export class DefaultStyleController implements IStyleController {
if (styles.listDropBackground) {
content.push(`
.monaco-list${suffix}.drop-target,
.monaco-list${suffix} .monaco-list-rows.drop-target,
.monaco-list${suffix} .monaco-list-row.drop-target { background-color: ${styles.listDropBackground} !important; color: inherit !important; }
`);
}
@@ -3,12 +3,12 @@
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
.monaco-panel-view {
.monaco-pane-view {
width: 100%;
height: 100%;
}
.monaco-panel-view .panel {
.monaco-pane-view .pane {
overflow: hidden;
width: 100%;
height: 100%;
@@ -16,7 +16,7 @@
flex-direction: column;
}
.monaco-panel-view .panel > .panel-header {
.monaco-pane-view .pane > .pane-header {
font-size: 11px;
font-weight: bold;
text-transform: uppercase;
@@ -26,7 +26,7 @@
align-items: center;
}
.monaco-panel-view .panel > .panel-header > .twisties {
.monaco-pane-view .pane > .pane-header > .twisties {
width: 20px;
display: flex;
align-items: center;
@@ -36,26 +36,26 @@
flex-shrink: 0;
}
.monaco-panel-view .panel > .panel-header.expanded > .twisties::before {
.monaco-pane-view .pane > .pane-header.expanded > .twisties::before {
transform: rotate(90deg);
}
/* TODO: actions should be part of the panel, but they aren't yet */
.monaco-panel-view .panel > .panel-header > .actions {
/* TODO: actions should be part of the pane, but they aren't yet */
.monaco-pane-view .pane > .pane-header > .actions {
display: none;
flex: 1;
}
/* TODO: actions should be part of the panel, but they aren't yet */
.monaco-panel-view .panel:hover > .panel-header.expanded > .actions,
.monaco-panel-view .panel > .panel-header.actions-always-visible.expanded > .actions,
.monaco-panel-view .panel > .panel-header.focused.expanded > .actions {
/* TODO: actions should be part of the pane, but they aren't yet */
.monaco-pane-view .pane:hover > .pane-header.expanded > .actions,
.monaco-pane-view .pane > .pane-header.actions-always-visible.expanded > .actions,
.monaco-pane-view .pane > .pane-header.focused.expanded > .actions {
display: initial;
}
/* TODO: actions should be part of the panel, but they aren't yet */
.monaco-panel-view .panel > .panel-header > .actions .action-label.icon,
.monaco-panel-view .panel > .panel-header > .actions .action-label.codicon {
/* TODO: actions should be part of the pane, but they aren't yet */
.monaco-pane-view .pane > .pane-header > .actions .action-label.icon,
.monaco-pane-view .pane > .pane-header > .actions .action-label.codicon {
width: 28px;
height: 22px;
background-size: 16px;
@@ -69,33 +69,33 @@
}
/* Bold font style does not go well with CJK fonts */
.monaco-panel-view:lang(zh-Hans) .panel > .panel-header,
.monaco-panel-view:lang(zh-Hant) .panel > .panel-header,
.monaco-panel-view:lang(ja) .panel > .panel-header,
.monaco-panel-view:lang(ko) .panel > .panel-header {
.monaco-pane-view:lang(zh-Hans) .pane > .pane-header,
.monaco-pane-view:lang(zh-Hant) .pane > .pane-header,
.monaco-pane-view:lang(ja) .pane > .pane-header,
.monaco-pane-view:lang(ko) .pane > .pane-header {
font-weight: normal;
}
.monaco-panel-view .panel > .panel-header.hidden {
.monaco-pane-view .pane > .pane-header.hidden {
display: none;
}
.monaco-panel-view .panel > .panel-body {
.monaco-pane-view .pane > .pane-body {
overflow: hidden;
flex: 1;
}
/* Animation */
.monaco-panel-view.animated .split-view-view {
.monaco-pane-view.animated .split-view-view {
transition-duration: 0.15s;
transition-timing-function: ease-out;
}
.monaco-panel-view.animated.vertical .split-view-view {
.monaco-pane-view.animated.vertical .split-view-view {
transition-property: height;
}
.monaco-panel-view.animated.horizontal .split-view-view {
.monaco-pane-view.animated.horizontal .split-view-view {
transition-property: width;
}
@@ -3,7 +3,7 @@
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import 'vs/css!./panelview';
import 'vs/css!./paneview';
import { IDisposable, Disposable, DisposableStore } from 'vs/base/common/lifecycle';
import { Event, Emitter } from 'vs/base/common/event';
import { domEvent } from 'vs/base/browser/event';
@@ -16,14 +16,14 @@ import { SplitView, IView } from './splitview';
import { isFirefox } from 'vs/base/browser/browser';
import { DataTransfers } from 'vs/base/browser/dnd';
export interface IPanelOptions {
export interface IPaneOptions {
ariaHeaderLabel?: string;
minimumBodySize?: number;
maximumBodySize?: number;
expanded?: boolean;
}
export interface IPanelStyles {
export interface IPaneStyles {
dropBackground?: Color;
headerForeground?: Color;
headerBackground?: Color;
@@ -31,7 +31,7 @@ export interface IPanelStyles {
}
/**
* A Panel is a structured SplitView view.
* A Pane is a structured SplitView view.
*
* WARNING: You must call `render()` after you contruct it.
* It can't be done automatically at the end of the ctor
@@ -39,7 +39,7 @@ export interface IPanelStyles {
* Subclasses wouldn't be able to set own properties
* before the `render()` call, thus forbiding their use.
*/
export abstract class Panel extends Disposable implements IView {
export abstract class Pane extends Disposable implements IView {
private static readonly HEADER_SIZE = 22;
@@ -54,7 +54,7 @@ export abstract class Panel extends Disposable implements IView {
private _minimumBodySize: number;
private _maximumBodySize: number;
private ariaHeaderLabel: string;
private styles: IPanelStyles = {};
private styles: IPaneStyles = {};
private animationTimer: number | undefined = undefined;
private readonly _onDidChange = this._register(new Emitter<number | undefined>());
@@ -95,7 +95,7 @@ export abstract class Panel extends Disposable implements IView {
}
private get headerSize(): number {
return this.headerVisible ? Panel.HEADER_SIZE : 0;
return this.headerVisible ? Pane.HEADER_SIZE : 0;
}
get minimumSize(): number {
@@ -116,14 +116,14 @@ export abstract class Panel extends Disposable implements IView {
width: number = 0;
constructor(options: IPanelOptions = {}) {
constructor(options: IPaneOptions = {}) {
super();
this._expanded = typeof options.expanded === 'undefined' ? true : !!options.expanded;
this.ariaHeaderLabel = options.ariaHeaderLabel || '';
this._minimumBodySize = typeof options.minimumBodySize === 'number' ? options.minimumBodySize : 120;
this._maximumBodySize = typeof options.maximumBodySize === 'number' ? options.maximumBodySize : Number.POSITIVE_INFINITY;
this.element = $('.panel');
this.element = $('.pane');
}
isExpanded(): boolean {
@@ -169,7 +169,7 @@ export abstract class Panel extends Disposable implements IView {
}
render(): void {
this.header = $('.panel-header');
this.header = $('.pane-header');
append(this.element, this.header);
this.header.setAttribute('tabindex', '0');
this.header.setAttribute('role', 'toolbar');
@@ -198,12 +198,12 @@ export abstract class Panel extends Disposable implements IView {
this._register(domEvent(this.header, 'click')
(() => this.setExpanded(!this.isExpanded()), null));
this.body = append(this.element, $('.panel-body'));
this.body = append(this.element, $('.pane-body'));
this.renderBody(this.body);
}
layout(height: number): void {
const headerSize = this.headerVisible ? Panel.HEADER_SIZE : 0;
const headerSize = this.headerVisible ? Pane.HEADER_SIZE : 0;
if (this.isExpanded()) {
this.layoutBody(height - headerSize, this.width);
@@ -211,7 +211,7 @@ export abstract class Panel extends Disposable implements IView {
}
}
style(styles: IPanelStyles): void {
style(styles: IPaneStyles): void {
this.styles = styles;
if (!this.header) {
@@ -242,31 +242,31 @@ export abstract class Panel extends Disposable implements IView {
}
interface IDndContext {
draggable: PanelDraggable | null;
draggable: PaneDraggable | null;
}
class PanelDraggable extends Disposable {
class PaneDraggable extends Disposable {
private static readonly DefaultDragOverBackgroundColor = new Color(new RGBA(128, 128, 128, 0.5));
private dragOverCounter = 0; // see https://github.com/Microsoft/vscode/issues/14470
private _onDidDrop = this._register(new Emitter<{ from: Panel, to: Panel }>());
private _onDidDrop = this._register(new Emitter<{ from: Pane, to: Pane }>());
readonly onDidDrop = this._onDidDrop.event;
constructor(private panel: Panel, private dnd: IPanelDndController, private context: IDndContext) {
constructor(private pane: Pane, private dnd: IPaneDndController, private context: IDndContext) {
super();
panel.draggableElement.draggable = true;
this._register(domEvent(panel.draggableElement, 'dragstart')(this.onDragStart, this));
this._register(domEvent(panel.dropTargetElement, 'dragenter')(this.onDragEnter, this));
this._register(domEvent(panel.dropTargetElement, 'dragleave')(this.onDragLeave, this));
this._register(domEvent(panel.dropTargetElement, 'dragend')(this.onDragEnd, this));
this._register(domEvent(panel.dropTargetElement, 'drop')(this.onDrop, this));
pane.draggableElement.draggable = true;
this._register(domEvent(pane.draggableElement, 'dragstart')(this.onDragStart, this));
this._register(domEvent(pane.dropTargetElement, 'dragenter')(this.onDragEnter, this));
this._register(domEvent(pane.dropTargetElement, 'dragleave')(this.onDragLeave, this));
this._register(domEvent(pane.dropTargetElement, 'dragend')(this.onDragEnd, this));
this._register(domEvent(pane.dropTargetElement, 'drop')(this.onDrop, this));
}
private onDragStart(e: DragEvent): void {
if (!this.dnd.canDrag(this.panel) || !e.dataTransfer) {
if (!this.dnd.canDrag(this.pane) || !e.dataTransfer) {
e.preventDefault();
e.stopPropagation();
return;
@@ -276,10 +276,10 @@ class PanelDraggable extends Disposable {
if (isFirefox) {
// Firefox: requires to set a text data transfer to get going
e.dataTransfer?.setData(DataTransfers.TEXT, this.panel.draggableElement.textContent || '');
e.dataTransfer?.setData(DataTransfers.TEXT, this.pane.draggableElement.textContent || '');
}
const dragImage = append(document.body, $('.monaco-drag-image', {}, this.panel.draggableElement.textContent || ''));
const dragImage = append(document.body, $('.monaco-drag-image', {}, this.pane.draggableElement.textContent || ''));
e.dataTransfer.setDragImage(dragImage, -10, -10);
setTimeout(() => document.body.removeChild(dragImage), 0);
@@ -291,7 +291,7 @@ class PanelDraggable extends Disposable {
return;
}
if (!this.dnd.canDrop(this.context.draggable.panel, this.panel)) {
if (!this.dnd.canDrop(this.context.draggable.pane, this.pane)) {
return;
}
@@ -304,7 +304,7 @@ class PanelDraggable extends Disposable {
return;
}
if (!this.dnd.canDrop(this.context.draggable.panel, this.panel)) {
if (!this.dnd.canDrop(this.context.draggable.pane, this.pane)) {
return;
}
@@ -335,8 +335,8 @@ class PanelDraggable extends Disposable {
this.dragOverCounter = 0;
this.render();
if (this.dnd.canDrop(this.context.draggable.panel, this.panel) && this.context.draggable !== this) {
this._onDidDrop.fire({ from: this.context.draggable.panel, to: this.panel });
if (this.dnd.canDrop(this.context.draggable.pane, this.pane) && this.context.draggable !== this) {
this._onDidDrop.fire({ from: this.context.draggable.pane, to: this.pane });
}
this.context.draggable = null;
@@ -346,106 +346,106 @@ class PanelDraggable extends Disposable {
let backgroundColor: string | null = null;
if (this.dragOverCounter > 0) {
backgroundColor = (this.panel.dropBackground || PanelDraggable.DefaultDragOverBackgroundColor).toString();
backgroundColor = (this.pane.dropBackground || PaneDraggable.DefaultDragOverBackgroundColor).toString();
}
this.panel.dropTargetElement.style.backgroundColor = backgroundColor || '';
this.pane.dropTargetElement.style.backgroundColor = backgroundColor || '';
}
}
export interface IPanelDndController {
canDrag(panel: Panel): boolean;
canDrop(panel: Panel, overPanel: Panel): boolean;
export interface IPaneDndController {
canDrag(pane: Pane): boolean;
canDrop(pane: Pane, overPane: Pane): boolean;
}
export class DefaultPanelDndController implements IPanelDndController {
export class DefaultPaneDndController implements IPaneDndController {
canDrag(panel: Panel): boolean {
canDrag(pane: Pane): boolean {
return true;
}
canDrop(panel: Panel, overPanel: Panel): boolean {
canDrop(pane: Pane, overPane: Pane): boolean {
return true;
}
}
export interface IPanelViewOptions {
dnd?: IPanelDndController;
export interface IPaneViewOptions {
dnd?: IPaneDndController;
}
interface IPanelItem {
panel: Panel;
interface IPaneItem {
pane: Pane;
disposable: IDisposable;
}
export class PanelView extends Disposable {
export class PaneView extends Disposable {
private dnd: IPanelDndController | undefined;
private dnd: IPaneDndController | undefined;
private dndContext: IDndContext = { draggable: null };
private el: HTMLElement;
private panelItems: IPanelItem[] = [];
private paneItems: IPaneItem[] = [];
private width: number = 0;
private splitview: SplitView;
private animationTimer: number | undefined = undefined;
private _onDidDrop = this._register(new Emitter<{ from: Panel, to: Panel }>());
readonly onDidDrop: Event<{ from: Panel, to: Panel }> = this._onDidDrop.event;
private _onDidDrop = this._register(new Emitter<{ from: Pane, to: Pane }>());
readonly onDidDrop: Event<{ from: Pane, to: Pane }> = this._onDidDrop.event;
readonly onDidSashChange: Event<number>;
constructor(container: HTMLElement, options: IPanelViewOptions = {}) {
constructor(container: HTMLElement, options: IPaneViewOptions = {}) {
super();
this.dnd = options.dnd;
this.el = append(container, $('.monaco-panel-view'));
this.el = append(container, $('.monaco-pane-view'));
this.splitview = this._register(new SplitView(this.el));
this.onDidSashChange = this.splitview.onDidSashChange;
}
addPanel(panel: Panel, size: number, index = this.splitview.length): void {
addPane(pane: Pane, size: number, index = this.splitview.length): void {
const disposables = new DisposableStore();
panel.onDidChangeExpansionState(this.setupAnimation, this, disposables);
pane.onDidChangeExpansionState(this.setupAnimation, this, disposables);
const panelItem = { panel, disposable: disposables };
this.panelItems.splice(index, 0, panelItem);
panel.width = this.width;
this.splitview.addView(panel, size, index);
const paneItem = { pane: pane, disposable: disposables };
this.paneItems.splice(index, 0, paneItem);
pane.width = this.width;
this.splitview.addView(pane, size, index);
if (this.dnd) {
const draggable = new PanelDraggable(panel, this.dnd, this.dndContext);
const draggable = new PaneDraggable(pane, this.dnd, this.dndContext);
disposables.add(draggable);
disposables.add(draggable.onDidDrop(this._onDidDrop.fire, this._onDidDrop));
}
}
removePanel(panel: Panel): void {
const index = firstIndex(this.panelItems, item => item.panel === panel);
removePane(pane: Pane): void {
const index = firstIndex(this.paneItems, item => item.pane === pane);
if (index === -1) {
return;
}
this.splitview.removeView(index);
const panelItem = this.panelItems.splice(index, 1)[0];
panelItem.disposable.dispose();
const paneItem = this.paneItems.splice(index, 1)[0];
paneItem.disposable.dispose();
}
movePanel(from: Panel, to: Panel): void {
const fromIndex = firstIndex(this.panelItems, item => item.panel === from);
const toIndex = firstIndex(this.panelItems, item => item.panel === to);
movePane(from: Pane, to: Pane): void {
const fromIndex = firstIndex(this.paneItems, item => item.pane === from);
const toIndex = firstIndex(this.paneItems, item => item.pane === to);
if (fromIndex === -1 || toIndex === -1) {
return;
}
const [panelItem] = this.panelItems.splice(fromIndex, 1);
this.panelItems.splice(toIndex, 0, panelItem);
const [paneItem] = this.paneItems.splice(fromIndex, 1);
this.paneItems.splice(toIndex, 0, paneItem);
this.splitview.moveView(fromIndex, toIndex);
}
resizePanel(panel: Panel, size: number): void {
const index = firstIndex(this.panelItems, item => item.panel === panel);
resizePane(pane: Pane, size: number): void {
const index = firstIndex(this.paneItems, item => item.pane === pane);
if (index === -1) {
return;
@@ -454,8 +454,8 @@ export class PanelView extends Disposable {
this.splitview.resizeView(index, size);
}
getPanelSize(panel: Panel): number {
const index = firstIndex(this.panelItems, item => item.panel === panel);
getPaneSize(pane: Pane): number {
const index = firstIndex(this.paneItems, item => item.pane === pane);
if (index === -1) {
return -1;
@@ -467,8 +467,8 @@ export class PanelView extends Disposable {
layout(height: number, width: number): void {
this.width = width;
for (const panelItem of this.panelItems) {
panelItem.panel.width = width;
for (const paneItem of this.paneItems) {
paneItem.pane.width = width;
}
this.splitview.layout(height);
@@ -490,6 +490,6 @@ export class PanelView extends Disposable {
dispose(): void {
super.dispose();
this.panelItems.forEach(i => i.disposable.dispose());
this.paneItems.forEach(i => i.disposable.dispose());
}
}
+1 -1
View File
@@ -336,7 +336,7 @@ class TreeRenderer<T, TFilterData, TRef, TTemplateData> implements IListRenderer
}
const indent = TreeRenderer.DefaultIndent + (node.depth - 1) * this.indent;
templateData.twistie.style.marginLeft = `${indent}px`;
templateData.twistie.style.paddingLeft = `${indent}px`;
templateData.indent.style.width = `${indent + this.indent - 16}px`;
this.renderTwistie(node, templateData);
@@ -3,7 +3,7 @@
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
.monaco-panel-view .panel > .panel-header h3.title {
.monaco-pane-view .pane > .pane-header h3.title {
white-space: nowrap;
text-overflow: ellipsis;
overflow: hidden;
+1 -1
View File
@@ -41,7 +41,7 @@
.monaco-tl-twistie {
font-size: 10px;
text-align: right;
margin-right: 6px;
padding-right: 6px;
flex-shrink: 0;
width: 16px;
display: flex !important;
+23 -10
View File
@@ -7,6 +7,7 @@ import { onUnexpectedError } from 'vs/base/common/errors';
import { once as onceFn } from 'vs/base/common/functional';
import { Disposable, IDisposable, toDisposable, combinedDisposable, DisposableStore } from 'vs/base/common/lifecycle';
import { LinkedList } from 'vs/base/common/linkedList';
import { CancellationToken } from 'vs/base/common/cancellation';
/**
* To an event a function with one or zero parameters
@@ -653,27 +654,39 @@ export interface IWaitUntil {
export class AsyncEmitter<T extends IWaitUntil> extends Emitter<T> {
private _asyncDeliveryQueue?: [Listener<T>, T, Promise<any>[]][];
private _asyncDeliveryQueue?: LinkedList<[Listener<T>, Omit<T, 'waitUntil'>]>;
async fireAsync(eventFn: (thenables: Promise<any>[], listener: Function) => T): Promise<void> {
async fireAsync(data: Omit<T, 'waitUntil'>, token: CancellationToken, promiseJoin?: (p: Promise<any>, listener: Function) => Promise<any>): Promise<void> {
if (!this._listeners) {
return;
}
// put all [listener,event]-pairs into delivery queue
// then emit all event. an inner/nested event might be
// the driver of this
if (!this._asyncDeliveryQueue) {
this._asyncDeliveryQueue = [];
this._asyncDeliveryQueue = new LinkedList();
}
for (let iter = this._listeners.iterator(), e = iter.next(); !e.done; e = iter.next()) {
const thenables: Promise<void>[] = [];
this._asyncDeliveryQueue.push([e.value, eventFn(thenables, typeof e.value === 'function' ? e.value : e.value[0]), thenables]);
this._asyncDeliveryQueue.push([e.value, data]);
}
while (this._asyncDeliveryQueue.length > 0) {
const [listener, event, thenables] = this._asyncDeliveryQueue.shift()!;
while (this._asyncDeliveryQueue.size > 0 && !token.isCancellationRequested) {
const [listener, data] = this._asyncDeliveryQueue.shift()!;
const thenables: Promise<any>[] = [];
const event = <T>{
...data,
waitUntil: (p: Promise<any>): void => {
if (Object.isFrozen(thenables)) {
throw new Error('waitUntil can NOT be called asynchronous');
}
if (promiseJoin) {
p = promiseJoin(p, typeof listener === 'function' ? listener : listener[0]);
}
thenables.push(p);
}
};
try {
if (typeof listener === 'function') {
listener.call(undefined, event);
+2 -2
View File
@@ -167,7 +167,7 @@ function toNodeEncoding(enc: string | null): string {
return enc;
}
export function detectEncodingByBOMFromBuffer(buffer: Buffer | VSBuffer | null, bytesRead: number): string | null {
export function detectEncodingByBOMFromBuffer(buffer: Buffer | VSBuffer | null, bytesRead: number): typeof UTF8_with_bom | typeof UTF16le | typeof UTF16be | null {
if (!buffer || bytesRead < UTF16be_BOM.length) {
return null;
}
@@ -193,7 +193,7 @@ export function detectEncodingByBOMFromBuffer(buffer: Buffer | VSBuffer | null,
// UTF-8
if (b0 === UTF8_BOM[0] && b1 === UTF8_BOM[1] && b2 === UTF8_BOM[2]) {
return UTF8;
return UTF8_with_bom;
}
return null;
+2 -2
View File
@@ -10,7 +10,7 @@ import { normalizeNFC } from 'vs/base/common/normalization';
import { toDisposable, IDisposable, dispose } from 'vs/base/common/lifecycle';
import { exists, readdir } from 'vs/base/node/pfs';
export function watchFile(path: string, onChange: (type: 'changed' | 'deleted', path: string) => void, onError: (error: string) => void): IDisposable {
export function watchFile(path: string, onChange: (type: 'added' | 'changed' | 'deleted', path: string) => void, onError: (error: string) => void): IDisposable {
return doWatchNonRecursive({ path, isDirectory: false }, onChange, onError);
}
@@ -189,4 +189,4 @@ function doWatchNonRecursive(file: { path: string, isDirectory: boolean }, onCha
watcherDisposables = dispose(watcherDisposables);
});
}
}
+8 -31
View File
@@ -3,10 +3,11 @@
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import * as assert from 'assert';
import { Event, Emitter, EventBufferer, EventMultiplexer, AsyncEmitter, IWaitUntil, PauseableEmitter } from 'vs/base/common/event';
import { Event, Emitter, EventBufferer, EventMultiplexer, IWaitUntil, PauseableEmitter, AsyncEmitter } from 'vs/base/common/event';
import { IDisposable, DisposableStore } from 'vs/base/common/lifecycle';
import * as Errors from 'vs/base/common/errors';
import { timeout } from 'vs/base/common/async';
import { CancellationToken } from 'vs/base/common/cancellation';
namespace Samples {
@@ -174,7 +175,7 @@ suite('Event', function () {
test('Debounce Event', function (done: () => void) {
let doc = new Samples.Document3();
let onDocDidChange = Event.debounce(doc.onDidChange, (prev: string[], cur) => {
let onDocDidChange = Event.debounce(doc.onDidChange, (prev: string[] | undefined, cur) => {
if (!prev) {
prev = [cur];
} else if (prev.indexOf(cur) < 0) {
@@ -272,11 +273,7 @@ suite('AsyncEmitter', function () {
assert.equal(typeof e.waitUntil, 'function');
});
emitter.fireAsync(thenables => ({
foo: true,
bar: 1,
waitUntil(t: Promise<void>) { thenables.push(t); }
}));
emitter.fireAsync({ foo: true, bar: 1, }, CancellationToken.None);
emitter.dispose();
});
@@ -303,12 +300,7 @@ suite('AsyncEmitter', function () {
}));
});
await emitter.fireAsync(thenables => ({
foo: true,
waitUntil(t) {
thenables.push(t);
}
}));
await emitter.fireAsync({ foo: true }, CancellationToken.None);
assert.equal(globalState, 2);
});
@@ -324,12 +316,7 @@ suite('AsyncEmitter', function () {
emitter.event(e => {
e.waitUntil(timeout(10).then(async _ => {
if (e.foo === 1) {
await emitter.fireAsync(thenables => ({
foo: 2,
waitUntil(t) {
thenables.push(t);
}
}));
await emitter.fireAsync({ foo: 2 }, CancellationToken.None);
assert.deepEqual(events, [1, 2]);
done = true;
}
@@ -342,12 +329,7 @@ suite('AsyncEmitter', function () {
e.waitUntil(timeout(7));
});
await emitter.fireAsync(thenables => ({
foo: 1,
waitUntil(t) {
thenables.push(t);
}
}));
await emitter.fireAsync({ foo: 1 }, CancellationToken.None);
assert.ok(done);
});
@@ -372,12 +354,7 @@ suite('AsyncEmitter', function () {
e.waitUntil(timeout(10));
});
await emitter.fireAsync(thenables => ({
foo: true,
waitUntil(t) {
thenables.push(t);
}
})).then(() => {
await emitter.fireAsync({ foo: true }, CancellationToken.None).then(() => {
assert.equal(globalState, 2);
}).catch(e => {
console.log(e);
@@ -9,7 +9,7 @@ import * as encoding from 'vs/base/node/encoding';
import { Readable } from 'stream';
import { getPathFromAmdModule } from 'vs/base/common/amd';
export async function detectEncodingByBOM(file: string): Promise<string | null> {
export async function detectEncodingByBOM(file: string): Promise<typeof encoding.UTF16be | typeof encoding.UTF16le | typeof encoding.UTF8_with_bom | null> {
try {
const { buffer, bytesRead } = await readExactlyByFile(file, 3);
@@ -86,7 +86,7 @@ suite('Encoding', () => {
const file = getPathFromAmdModule(require, './fixtures/some_utf8.css');
const detectedEncoding = await detectEncodingByBOM(file);
assert.equal(detectedEncoding, 'utf8');
assert.equal(detectedEncoding, 'utf8bom');
});
test('detectBOM UTF-16 LE', async () => {
@@ -345,8 +345,8 @@ export class IssueReporter extends Disposable {
const showInfoElements = document.getElementsByClassName('showInfo');
for (let i = 0; i < showInfoElements.length; i++) {
const showInfo = showInfoElements.item(i);
showInfo!.addEventListener('click', (e: MouseEvent) => {
const showInfo = showInfoElements.item(i)!;
(showInfo as HTMLAnchorElement).addEventListener('click', (e: MouseEvent) => {
e.preventDefault();
const label = (<HTMLDivElement>e.target);
if (label) {
@@ -432,9 +432,9 @@ export class IssueReporter extends Disposable {
sendWorkbenchCommand('workbench.action.reloadWindowWithExtensionsDisabled');
});
this.addEventListener('disableExtensions', 'keydown', (e: KeyboardEvent) => {
this.addEventListener('disableExtensions', 'keydown', (e: Event) => {
e.stopPropagation();
if (e.keyCode === 13 || e.keyCode === 32) {
if ((e as KeyboardEvent).keyCode === 13 || (e as KeyboardEvent).keyCode === 32) {
sendWorkbenchCommand('workbench.extensions.action.disableAll');
sendWorkbenchCommand('workbench.action.reloadWindow');
}
@@ -124,7 +124,7 @@ class DomCharWidthReader {
private static _render(testElement: HTMLElement, request: CharWidthRequest): void {
if (request.chr === ' ') {
let htmlString = '&nbsp;';
let htmlString = '&#160;';
// Repeat character 256 (2^8) times
for (let i = 0; i < 8; i++) {
htmlString += htmlString;
@@ -1753,7 +1753,7 @@ registerCommand(new EditorOrNativeTextInputCommand({
kbExpr: null,
primary: KeyMod.CtrlCmd | KeyCode.KEY_A
},
menubarOpts: {
menuOpts: {
menuId: MenuId.MenubarSelectionMenu,
group: '1_basic',
title: nls.localize({ key: 'miSelectAll', comment: ['&& denotes a mnemonic'] }, "&&Select All"),
@@ -1771,7 +1771,7 @@ registerCommand(new EditorOrNativeTextInputCommand({
kbExpr: EditorContextKeys.textInputFocus,
primary: KeyMod.CtrlCmd | KeyCode.KEY_Z
},
menubarOpts: {
menuOpts: {
menuId: MenuId.MenubarEditMenu,
group: '1_do',
title: nls.localize({ key: 'miUndo', comment: ['&& denotes a mnemonic'] }, "&&Undo"),
@@ -1792,7 +1792,7 @@ registerCommand(new EditorOrNativeTextInputCommand({
secondary: [KeyMod.CtrlCmd | KeyMod.Shift | KeyCode.KEY_Z],
mac: { primary: KeyMod.CtrlCmd | KeyMod.Shift | KeyCode.KEY_Z }
},
menubarOpts: {
menuOpts: {
menuId: MenuId.MenubarEditMenu,
group: '1_do',
title: nls.localize({ key: 'miRedo', comment: ['&& denotes a mnemonic'] }, "&&Redo"),
@@ -202,7 +202,7 @@ export class PointerEventHandler extends MouseHandler {
this._lastPointerType = 'mouse';
this.viewHelper.linesContentDomNode.addEventListener('pointerdown', (e: any) => {
this._register(dom.addDisposableListener(this.viewHelper.linesContentDomNode, 'pointerdown', (e: any) => {
const pointerType = <any>e.pointerType;
if (pointerType === 'mouse') {
this._lastPointerType = 'mouse';
@@ -212,7 +212,7 @@ export class PointerEventHandler extends MouseHandler {
} else {
this._lastPointerType = 'pen';
}
});
}));
// PonterEvents
const pointerEvents = new EditorPointerEventFactory(this.viewHelper.viewDomNode);
@@ -226,12 +226,30 @@ export class PointerEventHandler extends MouseHandler {
}
private onTap(event: GestureEvent): void {
if (!event.initialTarget || !this.viewHelper.linesContentDomNode.contains(<any>event.initialTarget)) {
return;
}
event.preventDefault();
this.viewHelper.focusTextArea();
const target = this._createMouseTarget(new EditorMouseEvent(event, this.viewHelper.viewDomNode), false);
if (target.position) {
this.viewController.moveTo(target.position);
// this.viewController.moveTo(target.position);
this.viewController.dispatchMouse({
position: target.position,
mouseColumn: target.position.column,
startedOnLineNumbers: false,
mouseDownCount: event.tapCount,
inSelectionMode: false,
altKey: false,
ctrlKey: false,
metaKey: false,
shiftKey: false,
leftButton: false,
middleButton: false,
});
}
}
@@ -242,9 +260,11 @@ export class PointerEventHandler extends MouseHandler {
}
public _onMouseDown(e: EditorMouseEvent): void {
if (this._lastPointerType !== 'touch') {
super._onMouseDown(e);
if (e.target && this.viewHelper.linesContentDomNode.contains(e.target) && this._lastPointerType === 'touch') {
return;
}
super._onMouseDown(e);
}
}
+6 -1
View File
@@ -6,7 +6,7 @@
import { IKeyboardEvent } from 'vs/base/browser/keyboardEvent';
import { IMouseEvent, IMouseWheelEvent } from 'vs/base/browser/mouseEvent';
import { IDisposable } from 'vs/base/common/lifecycle';
import { OverviewRulerPosition, ConfigurationChangedEvent, EditorLayoutInfo, IComputedEditorOptions, EditorOption, FindComputedEditorOptionValueById, IEditorOptions } from 'vs/editor/common/config/editorOptions';
import { OverviewRulerPosition, ConfigurationChangedEvent, EditorLayoutInfo, IComputedEditorOptions, EditorOption, FindComputedEditorOptionValueById, IEditorOptions, IDiffEditorOptions } from 'vs/editor/common/config/editorOptions';
import { ICursors } from 'vs/editor/common/controller/cursorCommon';
import { ICursorPositionChangedEvent, ICursorSelectionChangedEvent } from 'vs/editor/common/controller/cursorEvents';
import { IPosition, Position } from 'vs/editor/common/core/position';
@@ -938,6 +938,11 @@ export interface IDiffEditor extends editorCommon.IEditor {
* If the diff computation is not finished or the model is missing, will return null.
*/
getDiffLineInformationForModified(lineNumber: number): IDiffLineInformation | null;
/**
* Update the editor's options after the editor has been created.
*/
updateOptions(newOptions: IDiffEditorOptions): void;
}
/**
+58 -37
View File
@@ -42,7 +42,7 @@ export interface ICommandKeybindingsOptions extends IKeybindings {
kbExpr?: ContextKeyExpr | null;
weight: number;
}
export interface ICommandMenubarOptions {
export interface ICommandMenuOptions {
menuId: MenuId;
group: string;
order: number;
@@ -54,36 +54,29 @@ export interface ICommandOptions {
precondition: ContextKeyExpr | undefined;
kbOpts?: ICommandKeybindingsOptions;
description?: ICommandHandlerDescription;
menubarOpts?: ICommandMenubarOptions;
menuOpts?: ICommandMenuOptions | ICommandMenuOptions[];
}
export abstract class Command {
public readonly id: string;
public readonly precondition: ContextKeyExpr | undefined;
private readonly _kbOpts: ICommandKeybindingsOptions | undefined;
private readonly _menubarOpts: ICommandMenubarOptions | undefined;
private readonly _menuOpts: ICommandMenuOptions | ICommandMenuOptions[] | undefined;
private readonly _description: ICommandHandlerDescription | undefined;
constructor(opts: ICommandOptions) {
this.id = opts.id;
this.precondition = opts.precondition;
this._kbOpts = opts.kbOpts;
this._menubarOpts = opts.menubarOpts;
this._menuOpts = opts.menuOpts;
this._description = opts.description;
}
public register(): void {
if (this._menubarOpts) {
MenuRegistry.appendMenuItem(this._menubarOpts.menuId, {
group: this._menubarOpts.group,
command: {
id: this.id,
title: this._menubarOpts.title,
// precondition: this.precondition
},
when: this._menubarOpts.when,
order: this._menubarOpts.order
});
if (Array.isArray(this._menuOpts)) {
this._menuOpts.forEach(this._registerMenuItem, this);
} else if (this._menuOpts) {
this._registerMenuItem(this._menuOpts);
}
if (this._kbOpts) {
@@ -119,6 +112,19 @@ export abstract class Command {
}
}
private _registerMenuItem(item: ICommandMenuOptions): void {
MenuRegistry.appendMenuItem(item.menuId, {
group: item.group,
command: {
id: this.id,
title: item.title,
// precondition: this.precondition
},
when: item.when,
order: item.order
});
}
public abstract runCommand(accessor: ServicesAccessor, args: any): void | Promise<void>;
}
@@ -184,44 +190,59 @@ export abstract class EditorCommand extends Command {
//#region EditorAction
export interface IEditorCommandMenuOptions {
export interface IEditorActionContextMenuOptions {
group: string;
order: number;
when?: ContextKeyExpr;
menuId?: MenuId;
}
export interface IActionOptions extends ICommandOptions {
label: string;
alias: string;
menuOpts?: IEditorCommandMenuOptions;
contextMenuOpts?: IEditorActionContextMenuOptions | IEditorActionContextMenuOptions[];
}
export abstract class EditorAction extends EditorCommand {
private static convertOptions(opts: IActionOptions): ICommandOptions {
let menuOpts: ICommandMenuOptions[];
if (Array.isArray(opts.menuOpts)) {
menuOpts = opts.menuOpts;
} else if (opts.menuOpts) {
menuOpts = [opts.menuOpts];
} else {
menuOpts = [];
}
function withDefaults(item: Partial<ICommandMenuOptions>): ICommandMenuOptions {
if (!item.menuId) {
item.menuId = MenuId.EditorContext;
}
if (!item.title) {
item.title = opts.label;
}
item.when = ContextKeyExpr.and(opts.precondition, item.when);
return <ICommandMenuOptions>item;
}
if (Array.isArray(opts.contextMenuOpts)) {
menuOpts.push(...opts.contextMenuOpts.map(withDefaults));
} else if (opts.contextMenuOpts) {
menuOpts.push(withDefaults(opts.contextMenuOpts));
}
opts.menuOpts = menuOpts;
return <ICommandOptions>opts;
}
public readonly label: string;
public readonly alias: string;
private readonly menuOpts: IEditorCommandMenuOptions | undefined;
constructor(opts: IActionOptions) {
super(opts);
super(EditorAction.convertOptions(opts));
this.label = opts.label;
this.alias = opts.alias;
this.menuOpts = opts.menuOpts;
}
public register(): void {
if (this.menuOpts) {
MenuRegistry.appendMenuItem(MenuId.EditorContext, {
command: {
id: this.id,
title: this.label
},
when: ContextKeyExpr.and(this.precondition, this.menuOpts.when),
group: this.menuOpts.group,
order: this.menuOpts.order
});
}
super.register();
}
public runEditorCommand(accessor: ServicesAccessor, editor: ICodeEditor, args: any): void | Promise<void> {
@@ -1109,7 +1109,7 @@ export class Minimap extends ViewPart {
if (renderMinimap === RenderMinimap.Blocks) {
minimapCharRenderer.blockRenderChar(target, dx, dy, tokenColor, backgroundColor, useLighterFont);
} else { // RenderMinimap.Text
minimapCharRenderer.renderChar(target, dx, dy, charCode, tokenColor, backgroundColor, useLighterFont);
minimapCharRenderer.renderChar(target, dx, dy, charCode, tokenColor, backgroundColor, fontScale, useLighterFont);
}
dx += charWidth;
@@ -32,6 +32,7 @@ export class MinimapCharRenderer {
chCode: number,
color: RGBA8,
backgroundColor: RGBA8,
fontScale: number,
useLighterFont: boolean
): void {
const charWidth = Constants.BASE_CHAR_WIDTH * this.scale;
@@ -42,7 +43,7 @@ export class MinimapCharRenderer {
}
const charData = useLighterFont ? this.charDataLight : this.charDataNormal;
const charIndex = getCharIndex(chCode);
const charIndex = getCharIndex(chCode, fontScale);
const destWidth = target.width * Constants.RGBA_CHANNELS_CNT;
@@ -29,9 +29,13 @@ export const allCharCodes: ReadonlyArray<number> = (() => {
return v;
})();
export const getCharIndex = (chCode: number) => {
export const getCharIndex = (chCode: number, fontScale: number) => {
chCode -= Constants.START_CH_CODE;
if (chCode < 0 || chCode > Constants.CHAR_COUNT) {
if (fontScale <= 2) {
// for smaller scales, we can get away with using any ASCII character...
return (chCode + Constants.CHAR_COUNT) % Constants.CHAR_COUNT;
}
return Constants.CHAR_COUNT - 1; // unknown symbol
}
+3 -3
View File
@@ -695,7 +695,7 @@ export class DiffReview extends Disposable {
if (originalLine !== 0) {
originalLineNumber.appendChild(document.createTextNode(String(originalLine)));
} else {
originalLineNumber.innerHTML = '&nbsp;';
originalLineNumber.innerHTML = '&#160;';
}
cell.appendChild(originalLineNumber);
@@ -707,13 +707,13 @@ export class DiffReview extends Disposable {
if (modifiedLine !== 0) {
modifiedLineNumber.appendChild(document.createTextNode(String(modifiedLine)));
} else {
modifiedLineNumber.innerHTML = '&nbsp;';
modifiedLineNumber.innerHTML = '&#160;';
}
cell.appendChild(modifiedLineNumber);
const spacer = document.createElement('span');
spacer.className = spacerClassName;
spacer.innerHTML = '&nbsp;&nbsp;';
spacer.innerHTML = '&#160;&#160;';
cell.appendChild(spacer);
let lineContent: string;

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