mirror of
https://github.com/Microsoft/vscode
synced 2024-08-27 13:00:58 +00:00
Merge branch 'master' into electron-2.0.x
This commit is contained in:
commit
50f90e4275
4
.github/ISSUE_TEMPLATE/question.md
vendored
4
.github/ISSUE_TEMPLATE/question.md
vendored
|
@ -1,9 +1,9 @@
|
|||
---
|
||||
name: Question
|
||||
about: The issue tracker is not for questions. Please ask questions on https://stackoverflow.com/questions/tagged/vscode.
|
||||
about: The issue tracker is not for questions. Please ask questions on https://stackoverflow.com/questions/tagged/visual-studio-code.
|
||||
|
||||
---
|
||||
|
||||
🚨 The issue tracker is not for questions 🚨
|
||||
|
||||
If you have a question, please ask it on https://stackoverflow.com/questions/tagged/vscode.
|
||||
If you have a question, please ask it on https://stackoverflow.com/questions/tagged/visual-studio-code.
|
||||
|
|
|
@ -1,12 +1,12 @@
|
|||
[
|
||||
{
|
||||
"name": "ms-vscode.node-debug",
|
||||
"version": "1.26.0",
|
||||
"version": "1.26.1",
|
||||
"repo": "https://github.com/Microsoft/vscode-node-debug"
|
||||
},
|
||||
{
|
||||
"name": "ms-vscode.node-debug2",
|
||||
"version": "1.25.5",
|
||||
"version": "1.26.1",
|
||||
"repo": "https://github.com/Microsoft/vscode-node-debug2"
|
||||
}
|
||||
]
|
||||
|
|
|
@ -15,7 +15,6 @@ const cp = require('child_process');
|
|||
|
||||
var root = path.dirname(__dirname);
|
||||
var sha1 = util.getVersion(root);
|
||||
// @ts-ignore Microsoft/TypeScript#21262 complains about a require of a JSON file
|
||||
var semver = require('./monaco/package.json').version;
|
||||
var headerVersion = semver + '(' + sha1 + ')';
|
||||
|
||||
|
@ -230,7 +229,7 @@ gulp.task('editor-distro', ['clean-editor-distro', 'compile-editor-esm', 'minify
|
|||
});
|
||||
|
||||
gulp.task('analyze-editor-distro', function () {
|
||||
// @ts-ignore Microsoft/TypeScript#21262 complains about a require of a JSON file
|
||||
// @ts-ignore
|
||||
var bundleInfo = require('../out-editor/bundleInfo.json');
|
||||
var graph = bundleInfo.graph;
|
||||
var bundles = bundleInfo.bundles;
|
||||
|
|
|
@ -15,7 +15,6 @@ const remote = require('gulp-remote-src');
|
|||
const zip = require('gulp-vinyl-zip');
|
||||
const assign = require('object-assign');
|
||||
|
||||
// @ts-ignore Microsoft/TypeScript#21262 complains about a require of a JSON file
|
||||
const pkg = require('../package.json');
|
||||
|
||||
gulp.task('mixin', function () {
|
||||
|
@ -56,7 +55,6 @@ gulp.task('mixin', function () {
|
|||
.pipe(util.rebase(2))
|
||||
.pipe(productJsonFilter)
|
||||
.pipe(buffer())
|
||||
// @ts-ignore Microsoft/TypeScript#21262 complains about a require of a JSON file
|
||||
.pipe(json(o => assign({}, require('../product.json'), o)))
|
||||
.pipe(productJsonFilter.restore);
|
||||
|
||||
|
|
|
@ -25,9 +25,7 @@ const buildfile = require('../src/buildfile');
|
|||
const common = require('./lib/optimize');
|
||||
const root = path.dirname(__dirname);
|
||||
const commit = util.getVersion(root);
|
||||
// @ts-ignore Microsoft/TypeScript#21262 complains about a require of a JSON file
|
||||
const packageJson = require('../package.json');
|
||||
// @ts-ignore Microsoft/TypeScript#21262 complains about a require of a JSON file
|
||||
const product = require('../product.json');
|
||||
const crypto = require('crypto');
|
||||
const i18n = require('./lib/i18n');
|
||||
|
@ -40,12 +38,12 @@ const productionDependencies = deps.getProductionDependencies(path.dirname(__dir
|
|||
// @ts-ignore
|
||||
const baseModules = Object.keys(process.binding('natives')).filter(n => !/^_|\//.test(n));
|
||||
const nodeModules = ['electron', 'original-fs']
|
||||
// @ts-ignore JSON checking: dependencies property is optional
|
||||
.concat(Object.keys(product.dependencies || {}))
|
||||
.concat(_.uniq(productionDependencies.map(d => d.name)))
|
||||
.concat(baseModules);
|
||||
|
||||
// Build
|
||||
// @ts-ignore Microsoft/TypeScript#21262 complains about a require of a JSON file
|
||||
const builtInExtensions = require('./builtInExtensions.json');
|
||||
|
||||
const excludedExtensions = [
|
||||
|
@ -120,6 +118,8 @@ gulp.task('clean-minified-vscode', util.rimraf('out-vscode-min'));
|
|||
gulp.task('minify-vscode', ['clean-minified-vscode', 'optimize-index-js'], common.minifyTask('out-vscode', baseUrl));
|
||||
|
||||
// Package
|
||||
|
||||
// @ts-ignore JSON checking: darwinCredits is optional
|
||||
const darwinCreditsTemplate = product.darwinCredits && _.template(fs.readFileSync(path.join(root, product.darwinCredits), 'utf8'));
|
||||
|
||||
const config = {
|
||||
|
@ -148,6 +148,8 @@ const config = {
|
|||
linuxExecutableName: product.applicationName,
|
||||
winIcon: 'resources/win32/code.ico',
|
||||
token: process.env['VSCODE_MIXIN_PASSWORD'] || process.env['GITHUB_TOKEN'] || void 0,
|
||||
|
||||
// @ts-ignore JSON checking: electronRepository is optional
|
||||
repo: product.electronRepository || void 0
|
||||
};
|
||||
|
||||
|
@ -255,6 +257,7 @@ function packageTask(platform, arch, opts) {
|
|||
.pipe(filter(['**', '!**/*.js.map']));
|
||||
|
||||
let version = packageJson.version;
|
||||
// @ts-ignore JSON checking: quality is optional
|
||||
const quality = product.quality;
|
||||
|
||||
if (quality && quality !== 'stable') {
|
||||
|
@ -268,10 +271,8 @@ function packageTask(platform, arch, opts) {
|
|||
const date = new Date().toISOString();
|
||||
const productJsonUpdate = { commit, date, checksums };
|
||||
|
||||
try {
|
||||
if (shouldSetupSettingsSearch()) {
|
||||
productJsonUpdate.settingsSearchBuildId = getSettingsSearchBuildId(packageJson);
|
||||
} catch (err) {
|
||||
console.warn(err);
|
||||
}
|
||||
|
||||
const productJsonStream = gulp.src(['product.json'], { base: '.' })
|
||||
|
@ -286,6 +287,7 @@ function packageTask(platform, arch, opts) {
|
|||
|
||||
const depsSrc = [
|
||||
..._.flatten(productionDependencies.map(d => path.relative(root, d.path)).map(d => [`${d}/**`, `!${d}/**/{test,tests}/**`])),
|
||||
// @ts-ignore JSON checking: dependencies is optional
|
||||
..._.flatten(Object.keys(product.dependencies || {}).map(d => [`node_modules/${d}/**`, `!node_modules/${d}/**/{test,tests}/**`]))
|
||||
];
|
||||
|
||||
|
@ -470,9 +472,8 @@ gulp.task('upload-vscode-sourcemaps', ['minify-vscode'], () => {
|
|||
|
||||
const allConfigDetailsPath = path.join(os.tmpdir(), 'configuration.json');
|
||||
gulp.task('upload-vscode-configuration', ['generate-vscode-configuration'], () => {
|
||||
const branch = process.env.BUILD_SOURCEBRANCH;
|
||||
|
||||
if (!/\/master$/.test(branch) && branch.indexOf('/release/') < 0) {
|
||||
if (!shouldSetupSettingsSearch()) {
|
||||
const branch = process.env.BUILD_SOURCEBRANCH;
|
||||
console.log(`Only runs on master and release branches, not ${branch}`);
|
||||
return;
|
||||
}
|
||||
|
@ -495,13 +496,24 @@ gulp.task('upload-vscode-configuration', ['generate-vscode-configuration'], () =
|
|||
}));
|
||||
});
|
||||
|
||||
function getSettingsSearchBuildId(packageJson) {
|
||||
const previous = util.getPreviousVersion(packageJson.version);
|
||||
function shouldSetupSettingsSearch() {
|
||||
const branch = process.env.BUILD_SOURCEBRANCH;
|
||||
return branch && (/\/master$/.test(branch) || branch.indexOf('/release/') >= 0);
|
||||
}
|
||||
|
||||
function getSettingsSearchBuildId(packageJson) {
|
||||
try {
|
||||
const out = cp.execSync(`git rev-list ${previous}..HEAD --count`);
|
||||
const branch = process.env.BUILD_SOURCEBRANCH;
|
||||
const branchId = branch.indexOf('/release/') >= 0 ? 0 :
|
||||
/\/master$/.test(branch) ? 1 :
|
||||
2; // Some unexpected branch
|
||||
|
||||
const out = cp.execSync(`git rev-list HEAD --count`);
|
||||
const count = parseInt(out.toString());
|
||||
return util.versionStringToNumber(packageJson.version) * 1e4 + count;
|
||||
|
||||
// <version number><commit count><branchId (avoid unlikely conflicts)>
|
||||
// 1.25.1, 1,234,567 commits, master = 1250112345671
|
||||
return util.versionStringToNumber(packageJson.version) * 1e8 + count * 10 + branchId;
|
||||
} catch (e) {
|
||||
throw new Error('Could not determine build number: ' + e.toString());
|
||||
}
|
||||
|
|
|
@ -12,11 +12,8 @@ const shell = require('gulp-shell');
|
|||
const es = require('event-stream');
|
||||
const vfs = require('vinyl-fs');
|
||||
const util = require('./lib/util');
|
||||
// @ts-ignore Microsoft/TypeScript#21262 complains about a require of a JSON file
|
||||
const packageJson = require('../package.json');
|
||||
// @ts-ignore Microsoft/TypeScript#21262 complains about a require of a JSON file
|
||||
const product = require('../product.json');
|
||||
// @ts-ignore Microsoft/TypeScript#21262 complains about a require of a JSON file
|
||||
const rpmDependencies = require('../resources/linux/rpm/dependencies.json');
|
||||
|
||||
const linuxPackageRevision = Math.floor(new Date().getTime() / 1000);
|
||||
|
@ -75,7 +72,9 @@ function prepareDebPackage(arch) {
|
|||
const postinst = gulp.src('resources/linux/debian/postinst.template', { base: '.' })
|
||||
.pipe(replace('@@NAME@@', product.applicationName))
|
||||
.pipe(replace('@@ARCHITECTURE@@', debArch))
|
||||
// @ts-ignore JSON checking: quality is optional
|
||||
.pipe(replace('@@QUALITY@@', product.quality || '@@QUALITY@@'))
|
||||
// @ts-ignore JSON checking: updateUrl is optional
|
||||
.pipe(replace('@@UPDATEURL@@', product.updateUrl || '@@UPDATEURL@@'))
|
||||
.pipe(rename('DEBIAN/postinst'));
|
||||
|
||||
|
@ -133,7 +132,9 @@ function prepareRpmPackage(arch) {
|
|||
.pipe(replace('@@RELEASE@@', linuxPackageRevision))
|
||||
.pipe(replace('@@ARCHITECTURE@@', rpmArch))
|
||||
.pipe(replace('@@LICENSE@@', product.licenseName))
|
||||
// @ts-ignore JSON checking: quality is optional
|
||||
.pipe(replace('@@QUALITY@@', product.quality || '@@QUALITY@@'))
|
||||
// @ts-ignore JSON checking: updateUrl is optional
|
||||
.pipe(replace('@@UPDATEURL@@', product.updateUrl || '@@UPDATEURL@@'))
|
||||
.pipe(replace('@@DEPENDENCIES@@', rpmDependencies[rpmArch].join(', ')))
|
||||
.pipe(rename('SPECS/' + product.applicationName + '.spec'));
|
||||
|
|
|
@ -12,9 +12,7 @@ const assert = require('assert');
|
|||
const cp = require('child_process');
|
||||
const _7z = require('7zip')['7z'];
|
||||
const util = require('./lib/util');
|
||||
// @ts-ignore Microsoft/TypeScript#21262 complains about a require of a JSON file
|
||||
const pkg = require('../package.json');
|
||||
// @ts-ignore Microsoft/TypeScript#21262 complains about a require of a JSON file
|
||||
const product = require('../product.json');
|
||||
const vfs = require('vinyl-fs');
|
||||
const mkdirp = require('mkdirp');
|
||||
|
|
|
@ -17,7 +17,6 @@ const ext = require('./extensions');
|
|||
const util = require('gulp-util');
|
||||
|
||||
const root = path.dirname(path.dirname(__dirname));
|
||||
// @ts-ignore Microsoft/TypeScript#21262 complains about a require of a JSON file
|
||||
const builtInExtensions = require('../builtInExtensions.json');
|
||||
const controlFilePath = path.join(os.homedir(), '.vscode-oss-dev', 'extensions', 'control.json');
|
||||
|
||||
|
|
|
@ -22,6 +22,7 @@ import * as gulpUtil from 'gulp-util';
|
|||
import * as flatmap from 'gulp-flatmap';
|
||||
import * as pump from 'pump';
|
||||
import * as sm from 'source-map';
|
||||
import { Language } from './i18n';
|
||||
|
||||
const REPO_ROOT_PATH = path.join(__dirname, '../..');
|
||||
|
||||
|
@ -159,6 +160,10 @@ export interface IOptimizeTaskOpts {
|
|||
* (out folder name)
|
||||
*/
|
||||
out: string;
|
||||
/**
|
||||
* (out folder name)
|
||||
*/
|
||||
languages?: Language[];
|
||||
}
|
||||
|
||||
export function optimizeTask(opts: IOptimizeTaskOpts): () => NodeJS.ReadWriteStream {
|
||||
|
|
|
@ -1,56 +0,0 @@
|
|||
"use strict";
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
var assert = require("assert");
|
||||
var util = require("../util");
|
||||
function getMockTagExists(tags) {
|
||||
return function (tag) { return tags.indexOf(tag) >= 0; };
|
||||
}
|
||||
suite('util tests', function () {
|
||||
test('getPreviousVersion - patch', function () {
|
||||
assert.equal(util.getPreviousVersion('1.2.3', getMockTagExists(['1.2.2', '1.2.1', '1.2.0', '1.1.0'])), '1.2.2');
|
||||
});
|
||||
test('getPreviousVersion - patch invalid', function () {
|
||||
try {
|
||||
util.getPreviousVersion('1.2.2', getMockTagExists(['1.2.0', '1.1.0']));
|
||||
}
|
||||
catch (e) {
|
||||
// expected
|
||||
return;
|
||||
}
|
||||
throw new Error('Expected an exception');
|
||||
});
|
||||
test('getPreviousVersion - minor', function () {
|
||||
assert.equal(util.getPreviousVersion('1.2.0', getMockTagExists(['1.1.0', '1.1.1', '1.1.2', '1.1.3'])), '1.1.3');
|
||||
assert.equal(util.getPreviousVersion('1.2.0', getMockTagExists(['1.1.0', '1.0.0'])), '1.1.0');
|
||||
});
|
||||
test('getPreviousVersion - minor gap', function () {
|
||||
assert.equal(util.getPreviousVersion('1.2.0', getMockTagExists(['1.1.0', '1.1.1', '1.1.3'])), '1.1.1');
|
||||
});
|
||||
test('getPreviousVersion - minor invalid', function () {
|
||||
try {
|
||||
util.getPreviousVersion('1.2.0', getMockTagExists(['1.0.0']));
|
||||
}
|
||||
catch (e) {
|
||||
// expected
|
||||
return;
|
||||
}
|
||||
throw new Error('Expected an exception');
|
||||
});
|
||||
test('getPreviousVersion - major', function () {
|
||||
assert.equal(util.getPreviousVersion('2.0.0', getMockTagExists(['1.0.0', '1.1.0', '1.2.0', '1.2.1', '1.2.2'])), '1.2.2');
|
||||
});
|
||||
test('getPreviousVersion - major invalid', function () {
|
||||
try {
|
||||
util.getPreviousVersion('3.0.0', getMockTagExists(['1.0.0']));
|
||||
}
|
||||
catch (e) {
|
||||
// expected
|
||||
return;
|
||||
}
|
||||
throw new Error('Expected an exception');
|
||||
});
|
||||
});
|
|
@ -1,79 +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 assert = require('assert');
|
||||
import util = require('../util');
|
||||
|
||||
function getMockTagExists(tags: string[]) {
|
||||
return (tag: string) => tags.indexOf(tag) >= 0;
|
||||
}
|
||||
|
||||
suite('util tests', () => {
|
||||
test('getPreviousVersion - patch', () => {
|
||||
assert.equal(
|
||||
util.getPreviousVersion('1.2.3', getMockTagExists(['1.2.2', '1.2.1', '1.2.0', '1.1.0'])),
|
||||
'1.2.2'
|
||||
);
|
||||
});
|
||||
|
||||
test('getPreviousVersion - patch invalid', () => {
|
||||
try {
|
||||
util.getPreviousVersion('1.2.2', getMockTagExists(['1.2.0', '1.1.0']));
|
||||
} catch (e) {
|
||||
// expected
|
||||
return;
|
||||
}
|
||||
|
||||
throw new Error('Expected an exception');
|
||||
});
|
||||
|
||||
test('getPreviousVersion - minor', () => {
|
||||
assert.equal(
|
||||
util.getPreviousVersion('1.2.0', getMockTagExists(['1.1.0', '1.1.1', '1.1.2', '1.1.3'])),
|
||||
'1.1.3'
|
||||
);
|
||||
|
||||
assert.equal(
|
||||
util.getPreviousVersion('1.2.0', getMockTagExists(['1.1.0', '1.0.0'])),
|
||||
'1.1.0'
|
||||
);
|
||||
});
|
||||
|
||||
test('getPreviousVersion - minor gap', () => {
|
||||
assert.equal(
|
||||
util.getPreviousVersion('1.2.0', getMockTagExists(['1.1.0', '1.1.1', '1.1.3'])),
|
||||
'1.1.1'
|
||||
);
|
||||
});
|
||||
|
||||
test('getPreviousVersion - minor invalid', () => {
|
||||
try {
|
||||
util.getPreviousVersion('1.2.0', getMockTagExists(['1.0.0']));
|
||||
} catch (e) {
|
||||
// expected
|
||||
return;
|
||||
}
|
||||
|
||||
throw new Error('Expected an exception');
|
||||
});
|
||||
|
||||
test('getPreviousVersion - major', () => {
|
||||
assert.equal(
|
||||
util.getPreviousVersion('2.0.0', getMockTagExists(['1.0.0', '1.1.0', '1.2.0', '1.2.1', '1.2.2'])),
|
||||
'1.2.2'
|
||||
);
|
||||
});
|
||||
|
||||
test('getPreviousVersion - major invalid', () => {
|
||||
try {
|
||||
util.getPreviousVersion('3.0.0', getMockTagExists(['1.0.0']));
|
||||
} catch (e) {
|
||||
// expected
|
||||
return;
|
||||
}
|
||||
|
||||
throw new Error('Expected an exception');
|
||||
});
|
||||
});
|
|
@ -14,7 +14,6 @@ var fs = require("fs");
|
|||
var _rimraf = require("rimraf");
|
||||
var git = require("./git");
|
||||
var VinylFile = require("vinyl");
|
||||
var cp = require("child_process");
|
||||
var NoCancellationToken = { isCancellationRequested: function () { return false; } };
|
||||
function incremental(streamProvider, initial, supportsCancellation) {
|
||||
var input = es.through();
|
||||
|
@ -211,62 +210,6 @@ function filter(fn) {
|
|||
return result;
|
||||
}
|
||||
exports.filter = filter;
|
||||
function tagExists(tagName) {
|
||||
try {
|
||||
cp.execSync("git rev-parse " + tagName, { stdio: 'ignore' });
|
||||
return true;
|
||||
}
|
||||
catch (e) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
/**
|
||||
* Returns the version previous to the given version. Throws if a git tag for that version doesn't exist.
|
||||
* Given 1.17.2, return 1.17.1
|
||||
* 1.18.0 => 1.17.2. (or the highest 1.17.x)
|
||||
* 2.0.0 => 1.18.0 (or the highest 1.x)
|
||||
*/
|
||||
function getPreviousVersion(versionStr, _tagExists) {
|
||||
if (_tagExists === void 0) { _tagExists = tagExists; }
|
||||
function getLatestTagFromBase(semverArr, componentToTest) {
|
||||
var baseVersion = semverArr.join('.');
|
||||
if (!_tagExists(baseVersion)) {
|
||||
throw new Error('Failed to find git tag for base version, ' + baseVersion);
|
||||
}
|
||||
var goodTag;
|
||||
do {
|
||||
goodTag = semverArr.join('.');
|
||||
semverArr[componentToTest]++;
|
||||
} while (_tagExists(semverArr.join('.')));
|
||||
return goodTag;
|
||||
}
|
||||
var semverArr = versionStringToNumberArray(versionStr);
|
||||
if (semverArr[2] > 0) {
|
||||
semverArr[2]--;
|
||||
var previous = semverArr.join('.');
|
||||
if (!_tagExists(previous)) {
|
||||
throw new Error('Failed to find git tag for previous version, ' + previous);
|
||||
}
|
||||
return previous;
|
||||
}
|
||||
else if (semverArr[1] > 0) {
|
||||
semverArr[1]--;
|
||||
return getLatestTagFromBase(semverArr, 2);
|
||||
}
|
||||
else {
|
||||
semverArr[0]--;
|
||||
// Find 1.x.0 for latest x
|
||||
var latestMinorVersion = getLatestTagFromBase(semverArr, 1);
|
||||
// Find 1.x.y for latest y
|
||||
return getLatestTagFromBase(versionStringToNumberArray(latestMinorVersion), 2);
|
||||
}
|
||||
}
|
||||
exports.getPreviousVersion = getPreviousVersion;
|
||||
function versionStringToNumberArray(versionStr) {
|
||||
return versionStr
|
||||
.split('.')
|
||||
.map(function (s) { return parseInt(s); });
|
||||
}
|
||||
function versionStringToNumber(versionStr) {
|
||||
var semverRegex = /(\d+)\.(\d+)\.(\d+)/;
|
||||
var match = versionStr.match(semverRegex);
|
||||
|
|
|
@ -17,7 +17,6 @@ import * as git from './git';
|
|||
import * as VinylFile from 'vinyl';
|
||||
import { ThroughStream } from 'through';
|
||||
import * as sm from 'source-map';
|
||||
import * as cp from 'child_process';
|
||||
|
||||
export interface ICancellationToken {
|
||||
isCancellationRequested(): boolean;
|
||||
|
@ -271,66 +270,6 @@ export function filter(fn: (data: any) => boolean): FilterStream {
|
|||
return result;
|
||||
}
|
||||
|
||||
function tagExists(tagName: string): boolean {
|
||||
try {
|
||||
cp.execSync(`git rev-parse ${tagName}`, { stdio: 'ignore' });
|
||||
return true;
|
||||
} catch (e) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the version previous to the given version. Throws if a git tag for that version doesn't exist.
|
||||
* Given 1.17.2, return 1.17.1
|
||||
* 1.18.0 => 1.17.2. (or the highest 1.17.x)
|
||||
* 2.0.0 => 1.18.0 (or the highest 1.x)
|
||||
*/
|
||||
export function getPreviousVersion(versionStr: string, _tagExists = tagExists) {
|
||||
function getLatestTagFromBase(semverArr: number[], componentToTest: number): string {
|
||||
const baseVersion = semverArr.join('.');
|
||||
if (!_tagExists(baseVersion)) {
|
||||
throw new Error('Failed to find git tag for base version, ' + baseVersion);
|
||||
}
|
||||
|
||||
let goodTag;
|
||||
do {
|
||||
goodTag = semverArr.join('.');
|
||||
semverArr[componentToTest]++;
|
||||
} while (_tagExists(semverArr.join('.')));
|
||||
|
||||
return goodTag;
|
||||
}
|
||||
|
||||
const semverArr = versionStringToNumberArray(versionStr);
|
||||
if (semverArr[2] > 0) {
|
||||
semverArr[2]--;
|
||||
const previous = semverArr.join('.');
|
||||
if (!_tagExists(previous)) {
|
||||
throw new Error('Failed to find git tag for previous version, ' + previous);
|
||||
}
|
||||
|
||||
return previous;
|
||||
} else if (semverArr[1] > 0) {
|
||||
semverArr[1]--;
|
||||
return getLatestTagFromBase(semverArr, 2);
|
||||
} else {
|
||||
semverArr[0]--;
|
||||
|
||||
// Find 1.x.0 for latest x
|
||||
const latestMinorVersion = getLatestTagFromBase(semverArr, 1);
|
||||
|
||||
// Find 1.x.y for latest y
|
||||
return getLatestTagFromBase(versionStringToNumberArray(latestMinorVersion), 2);
|
||||
}
|
||||
}
|
||||
|
||||
function versionStringToNumberArray(versionStr: string): number[] {
|
||||
return versionStr
|
||||
.split('.')
|
||||
.map(s => parseInt(s));
|
||||
}
|
||||
|
||||
export function versionStringToNumber(versionStr: string) {
|
||||
const semverRegex = /(\d+)\.(\d+)\.(\d+)/;
|
||||
const match = versionStr.match(semverRegex);
|
||||
|
|
|
@ -6,6 +6,7 @@
|
|||
"removeComments": false,
|
||||
"preserveConstEnums": true,
|
||||
"sourceMap": false,
|
||||
"resolveJsonModule": true,
|
||||
"experimentalDecorators": true,
|
||||
// enable JavaScript type checking for the language service
|
||||
// use the tsconfig.build.json for compiling wich disable JavaScript
|
||||
|
|
|
@ -545,33 +545,6 @@
|
|||
],
|
||||
"isProd": true
|
||||
},
|
||||
{
|
||||
"name": "retep998/winapi-rs",
|
||||
"version": "0.4.0",
|
||||
"repositoryUrl": "https://github.com/retep998/winapi-rs",
|
||||
"licenseDetail": [
|
||||
"Copyright (c) 2015 The winapi-rs Developers",
|
||||
"",
|
||||
"Permission is hereby granted, free of charge, to any person obtaining a copy",
|
||||
"of this software and associated documentation files (the \"Software\"), to deal",
|
||||
"in the Software without restriction, including without limitation the rights",
|
||||
"to use, copy, modify, merge, publish, distribute, sublicense, and/or sell",
|
||||
"copies of the Software, and to permit persons to whom the Software is",
|
||||
"furnished to do so, subject to the following conditions:",
|
||||
"",
|
||||
"The above copyright notice and this permission notice shall be included in all",
|
||||
"copies or substantial portions of the Software.",
|
||||
"",
|
||||
"THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR",
|
||||
"IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,",
|
||||
"FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE",
|
||||
"AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER",
|
||||
"LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,",
|
||||
"OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE",
|
||||
"SOFTWARE."
|
||||
],
|
||||
"isProd": true
|
||||
},
|
||||
{
|
||||
"name": "retep998/winapi-rs",
|
||||
"version": "0.2.8",
|
||||
|
@ -601,7 +574,7 @@
|
|||
},
|
||||
{
|
||||
"name": "retep998/winapi-rs",
|
||||
"version": "0.2.2",
|
||||
"version": "0.1.1",
|
||||
"repositoryUrl": "https://github.com/retep998/winapi-rs",
|
||||
"licenseDetail": [
|
||||
"Copyright (c) 2015 The winapi-rs Developers",
|
||||
|
@ -655,7 +628,34 @@
|
|||
},
|
||||
{
|
||||
"name": "retep998/winapi-rs",
|
||||
"version": "0.1.1",
|
||||
"version": "0.4.0",
|
||||
"repositoryUrl": "https://github.com/retep998/winapi-rs",
|
||||
"licenseDetail": [
|
||||
"Copyright (c) 2015 The winapi-rs Developers",
|
||||
"",
|
||||
"Permission is hereby granted, free of charge, to any person obtaining a copy",
|
||||
"of this software and associated documentation files (the \"Software\"), to deal",
|
||||
"in the Software without restriction, including without limitation the rights",
|
||||
"to use, copy, modify, merge, publish, distribute, sublicense, and/or sell",
|
||||
"copies of the Software, and to permit persons to whom the Software is",
|
||||
"furnished to do so, subject to the following conditions:",
|
||||
"",
|
||||
"The above copyright notice and this permission notice shall be included in all",
|
||||
"copies or substantial portions of the Software.",
|
||||
"",
|
||||
"THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR",
|
||||
"IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,",
|
||||
"FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE",
|
||||
"AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER",
|
||||
"LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,",
|
||||
"OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE",
|
||||
"SOFTWARE."
|
||||
],
|
||||
"isProd": true
|
||||
},
|
||||
{
|
||||
"name": "retep998/winapi-rs",
|
||||
"version": "0.2.2",
|
||||
"repositoryUrl": "https://github.com/retep998/winapi-rs",
|
||||
"licenseDetail": [
|
||||
"Copyright (c) 2015 The winapi-rs Developers",
|
||||
|
@ -1791,4 +1791,4 @@
|
|||
],
|
||||
"isProd": true
|
||||
}
|
||||
]
|
||||
]
|
|
@ -92,7 +92,7 @@ Filename: "{app}\{#ExeBasename}.exe"; Description: "{cm:LaunchProgram,{#NameLong
|
|||
#if "user" == InstallTarget
|
||||
#define SoftwareClassesRootKey "HKCU"
|
||||
#else
|
||||
#define SoftwareClassesRootKey "HKCR"
|
||||
#define SoftwareClassesRootKey "HKLM"
|
||||
#endif
|
||||
|
||||
Root: {#SoftwareClassesRootKey}; Subkey: "Software\Classes\.ascx\OpenWithProgids"; ValueType: none; ValueName: "{#RegValueName}"; Flags: deletevalue uninsdeletevalue; Tasks: associatewithfiles
|
||||
|
@ -946,7 +946,7 @@ Root: {#SoftwareClassesRootKey}; Subkey: "Software\Classes\Drive\shell\{#RegValu
|
|||
#define Uninstall64RootKey "HKCU64"
|
||||
#define Uninstall32RootKey "HKCU32"
|
||||
#else
|
||||
#define EnvironmentRootKey "HKCR"
|
||||
#define EnvironmentRootKey "HKLM"
|
||||
#define EnvironmentKey "System\CurrentControlSet\Control\Session Manager\Environment"
|
||||
#define Uninstall64RootKey "HKLM64"
|
||||
#define Uninstall32RootKey "HKLM32"
|
||||
|
|
Binary file not shown.
|
@ -18,7 +18,7 @@
|
|||
},
|
||||
"dependencies": {
|
||||
"jsonc-parser": "^1.0.0",
|
||||
"vscode-nls": "^3.2.1"
|
||||
"vscode-nls": "^3.2.4"
|
||||
},
|
||||
"contributes": {
|
||||
"languages": [
|
||||
|
|
|
@ -10,6 +10,6 @@ jsonc-parser@^1.0.0:
|
|||
version "1.0.0"
|
||||
resolved "https://registry.yarnpkg.com/jsonc-parser/-/jsonc-parser-1.0.0.tgz#ddcc864ae708e60a7a6dd36daea00172fa8d9272"
|
||||
|
||||
vscode-nls@^3.2.1:
|
||||
version "3.2.1"
|
||||
resolved "https://registry.yarnpkg.com/vscode-nls/-/vscode-nls-3.2.1.tgz#b1f3e04e8a94a715d5a7bcbc8339c51e6d74ca51"
|
||||
vscode-nls@^3.2.4:
|
||||
version "3.2.4"
|
||||
resolved "https://registry.yarnpkg.com/vscode-nls/-/vscode-nls-3.2.4.tgz#2166b4183c8aea884d20727f5449e62be69fd398"
|
||||
|
|
|
@ -709,7 +709,7 @@
|
|||
"dependencies": {
|
||||
"vscode-languageclient": "^4.1.4",
|
||||
"vscode-languageserver-protocol-foldingprovider": "^2.0.1",
|
||||
"vscode-nls": "^3.2.2"
|
||||
"vscode-nls": "^3.2.4"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/node": "7.0.43",
|
||||
|
|
|
@ -161,9 +161,9 @@ vscode-languageserver-types@^3.7.2:
|
|||
version "3.7.2"
|
||||
resolved "https://registry.yarnpkg.com/vscode-languageserver-types/-/vscode-languageserver-types-3.7.2.tgz#aad8846f8e3e27962648554de5a8417e358f34eb"
|
||||
|
||||
vscode-nls@^3.2.2:
|
||||
version "3.2.2"
|
||||
resolved "https://registry.yarnpkg.com/vscode-nls/-/vscode-nls-3.2.2.tgz#3817eca5b985c2393de325197cf4e15eb2aa5350"
|
||||
vscode-nls@^3.2.4:
|
||||
version "3.2.4"
|
||||
resolved "https://registry.yarnpkg.com/vscode-nls/-/vscode-nls-3.2.4.tgz#2166b4183c8aea884d20727f5449e62be69fd398"
|
||||
|
||||
wrappy@1:
|
||||
version "1.0.2"
|
||||
|
|
|
@ -449,6 +449,6 @@
|
|||
"image-size": "^0.5.2",
|
||||
"vscode-emmet-helper": "^1.2.10",
|
||||
"vscode-languageserver-types": "^3.5.0",
|
||||
"vscode-nls": "3.2.1"
|
||||
"vscode-nls": "3.2.4"
|
||||
}
|
||||
}
|
||||
|
|
|
@ -2131,9 +2131,9 @@ vscode-languageserver-types@^3.6.0-next.1:
|
|||
version "3.6.0-next.1"
|
||||
resolved "https://registry.yarnpkg.com/vscode-languageserver-types/-/vscode-languageserver-types-3.6.0-next.1.tgz#98e488d3f87b666b4ee1a3d89f0023e246d358f3"
|
||||
|
||||
vscode-nls@3.2.1:
|
||||
version "3.2.1"
|
||||
resolved "https://registry.yarnpkg.com/vscode-nls/-/vscode-nls-3.2.1.tgz#b1f3e04e8a94a715d5a7bcbc8339c51e6d74ca51"
|
||||
vscode-nls@3.2.4:
|
||||
version "3.2.4"
|
||||
resolved "https://registry.yarnpkg.com/vscode-nls/-/vscode-nls-3.2.4.tgz#2166b4183c8aea884d20727f5449e62be69fd398"
|
||||
|
||||
vscode@1.0.1:
|
||||
version "1.0.1"
|
||||
|
|
|
@ -21,7 +21,7 @@
|
|||
"jsonc-parser": "^1.0.0",
|
||||
"markdown-it": "^8.3.1",
|
||||
"parse5": "^3.0.2",
|
||||
"vscode-nls": "^3.2.1"
|
||||
"vscode-nls": "^3.2.4"
|
||||
},
|
||||
"contributes": {
|
||||
"jsonValidation": [
|
||||
|
|
|
@ -58,6 +58,6 @@ uc.micro@^1.0.1, uc.micro@^1.0.3:
|
|||
version "1.0.3"
|
||||
resolved "https://registry.yarnpkg.com/uc.micro/-/uc.micro-1.0.3.tgz#7ed50d5e0f9a9fb0a573379259f2a77458d50192"
|
||||
|
||||
vscode-nls@^3.2.1:
|
||||
version "3.2.1"
|
||||
resolved "https://registry.yarnpkg.com/vscode-nls/-/vscode-nls-3.2.1.tgz#b1f3e04e8a94a715d5a7bcbc8339c51e6d74ca51"
|
||||
vscode-nls@^3.2.4:
|
||||
version "3.2.4"
|
||||
resolved "https://registry.yarnpkg.com/vscode-nls/-/vscode-nls-3.2.4.tgz#2166b4183c8aea884d20727f5449e62be69fd398"
|
||||
|
|
|
@ -38,6 +38,11 @@
|
|||
"dark": "resources/icons/dark/git.svg"
|
||||
}
|
||||
},
|
||||
{
|
||||
"command": "git.openRepository",
|
||||
"title": "%command.openRepository%",
|
||||
"category": "Git"
|
||||
},
|
||||
{
|
||||
"command": "git.close",
|
||||
"title": "%command.close%",
|
||||
|
@ -336,6 +341,10 @@
|
|||
"command": "git.init",
|
||||
"when": "config.git.enabled"
|
||||
},
|
||||
{
|
||||
"command": "git.openRepository",
|
||||
"when": "config.git.enabled"
|
||||
},
|
||||
{
|
||||
"command": "git.close",
|
||||
"when": "config.git.enabled && gitOpenRepositoryCount != 0"
|
||||
|
@ -881,7 +890,16 @@
|
|||
"scope": "application"
|
||||
},
|
||||
"git.autoRepositoryDetection": {
|
||||
"type": "boolean",
|
||||
"type": [
|
||||
"boolean",
|
||||
"string"
|
||||
],
|
||||
"enum": [
|
||||
true,
|
||||
false,
|
||||
"subFolders",
|
||||
"openEditors"
|
||||
],
|
||||
"description": "%config.autoRepositoryDetection%",
|
||||
"default": true
|
||||
},
|
||||
|
@ -943,11 +961,13 @@
|
|||
},
|
||||
"git.enableSmartCommit": {
|
||||
"type": "boolean",
|
||||
"scope": "resource",
|
||||
"description": "%config.enableSmartCommit%",
|
||||
"default": false
|
||||
},
|
||||
"git.enableCommitSigning": {
|
||||
"type": "boolean",
|
||||
"scope": "resource",
|
||||
"description": "%config.enableCommitSigning%",
|
||||
"default": false
|
||||
},
|
||||
|
@ -958,6 +978,7 @@
|
|||
},
|
||||
"git.promptToSaveFilesBeforeCommit": {
|
||||
"type": "boolean",
|
||||
"scope": "resource",
|
||||
"default": false,
|
||||
"description": "%config.promptToSaveFilesBeforeCommit%"
|
||||
},
|
||||
|
@ -966,6 +987,11 @@
|
|||
"default": true,
|
||||
"description": "%config.showInlineOpenFileAction%"
|
||||
},
|
||||
"git.showPushSuccessNotification": {
|
||||
"type": "boolean",
|
||||
"description": "%config.showPushSuccessNotification%",
|
||||
"default": false
|
||||
},
|
||||
"git.inputValidation": {
|
||||
"type": "string",
|
||||
"enum": [
|
||||
|
@ -987,6 +1013,18 @@
|
|||
"scope": "resource",
|
||||
"default": 10,
|
||||
"description": "%config.detectSubmodulesLimit%"
|
||||
},
|
||||
"git.alwaysSignOff": {
|
||||
"type": "boolean",
|
||||
"scope": "resource",
|
||||
"default": false,
|
||||
"description": "%config.alwaysSignOff%"
|
||||
},
|
||||
"git.ignoredRepositories": {
|
||||
"type": "array",
|
||||
"default": [],
|
||||
"scope": "window",
|
||||
"description": "%config.ignoredRepositories%"
|
||||
}
|
||||
}
|
||||
},
|
||||
|
@ -1140,7 +1178,7 @@
|
|||
"iconv-lite": "0.4.19",
|
||||
"jschardet": "^1.6.0",
|
||||
"vscode-extension-telemetry": "0.0.17",
|
||||
"vscode-nls": "^3.2.1",
|
||||
"vscode-nls": "^3.2.4",
|
||||
"which": "^1.3.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
|
@ -1151,4 +1189,4 @@
|
|||
"@types/which": "^1.0.28",
|
||||
"mocha": "^3.2.0"
|
||||
}
|
||||
}
|
||||
}
|
|
@ -3,6 +3,7 @@
|
|||
"description": "Git SCM Integration",
|
||||
"command.clone": "Clone",
|
||||
"command.init": "Initialize Repository",
|
||||
"command.openRepository": "Open Repository",
|
||||
"command.close": "Close Repository",
|
||||
"command.refresh": "Refresh",
|
||||
"command.openChange": "Open Changes",
|
||||
|
@ -51,7 +52,7 @@
|
|||
"command.stashPopLatest": "Pop Latest Stash",
|
||||
"config.enabled": "Whether git is enabled",
|
||||
"config.path": "Path to the git executable",
|
||||
"config.autoRepositoryDetection": "Whether repositories should be automatically detected",
|
||||
"config.autoRepositoryDetection": "Configures when repositories should be automatically detected.",
|
||||
"config.autorefresh": "Whether auto refreshing is enabled",
|
||||
"config.autofetch": "Whether auto fetching is enabled",
|
||||
"config.enableLongCommitWarning": "Whether long commit messages should be warned about",
|
||||
|
@ -68,10 +69,13 @@
|
|||
"config.decorations.enabled": "Controls if Git contributes colors and badges to the explorer and the open editors view.",
|
||||
"config.promptToSaveFilesBeforeCommit": "Controls whether Git should check for unsaved files before committing.",
|
||||
"config.showInlineOpenFileAction": "Controls whether to show an inline Open File action in the Git changes view.",
|
||||
"config.showPushSuccessNotification": "Controls whether to show a notification when a push is successful.",
|
||||
"config.inputValidation": "Controls when to show commit message input validation.",
|
||||
"config.detectSubmodules": "Controls whether to automatically detect git submodules.",
|
||||
"colors.added": "Color for added resources.",
|
||||
"config.detectSubmodulesLimit": "Controls the limit of git submodules detected.",
|
||||
"config.alwaysSignOff": "Controls the signoff flag for all commits",
|
||||
"config.ignoredRepositories": "List of git repositories to ignore",
|
||||
"colors.modified": "Color for modified resources.",
|
||||
"colors.deleted": "Color for deleted resources.",
|
||||
"colors.untracked": "Color for untracked resources.",
|
||||
|
|
|
@ -137,6 +137,22 @@ const ImageMimetypes = [
|
|||
'image/bmp'
|
||||
];
|
||||
|
||||
async function categorizeResourceByResolution(resources: Resource[]): Promise<{ merge: Resource[], resolved: Resource[], unresolved: Resource[] }> {
|
||||
const selection = resources.filter(s => s instanceof Resource) as Resource[];
|
||||
const merge = selection.filter(s => s.resourceGroupType === ResourceGroupType.Merge);
|
||||
const isBothAddedOrModified = (s: Resource) => s.type === Status.BOTH_MODIFIED || s.type === Status.BOTH_ADDED;
|
||||
const possibleUnresolved = merge.filter(isBothAddedOrModified);
|
||||
const promises = possibleUnresolved.map(s => grep(s.resourceUri.fsPath, /^<{7}|^={7}|^>{7}/));
|
||||
const unresolvedBothModified = await Promise.all<boolean>(promises);
|
||||
const resolved = possibleUnresolved.filter((s, i) => !unresolvedBothModified[i]);
|
||||
const unresolved = [
|
||||
...merge.filter(s => !isBothAddedOrModified(s)),
|
||||
...possibleUnresolved.filter((s, i) => unresolvedBothModified[i])
|
||||
];
|
||||
|
||||
return { merge, resolved, unresolved };
|
||||
}
|
||||
|
||||
export class CommandCenter {
|
||||
|
||||
private disposables: Disposable[];
|
||||
|
@ -236,7 +252,7 @@ export class CommandCenter {
|
|||
gitRef = indexStatus ? '' : 'HEAD';
|
||||
}
|
||||
|
||||
const { size, object } = await repository.lstree(gitRef, uri.fsPath);
|
||||
const { size, object } = await repository.getObjectDetails(gitRef, uri.fsPath);
|
||||
const { mimetype } = await repository.detectObjectType(object);
|
||||
|
||||
if (mimetype === 'text/plain') {
|
||||
|
@ -485,7 +501,28 @@ export class CommandCenter {
|
|||
}
|
||||
|
||||
await this.git.init(path);
|
||||
await this.model.tryOpenRepository(path);
|
||||
await this.model.openRepository(path);
|
||||
}
|
||||
|
||||
@command('git.openRepository', { repository: false })
|
||||
async openRepository(path?: string): Promise<void> {
|
||||
if (!path) {
|
||||
const result = await window.showOpenDialog({
|
||||
canSelectFiles: false,
|
||||
canSelectFolders: true,
|
||||
canSelectMany: false,
|
||||
defaultUri: Uri.file(os.homedir()),
|
||||
openLabel: localize('open repo', "Open Repository")
|
||||
});
|
||||
|
||||
if (!result || result.length === 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
path = result[0].fsPath;
|
||||
}
|
||||
|
||||
await this.model.openRepository(path);
|
||||
}
|
||||
|
||||
@command('git.close', { repository: true })
|
||||
|
@ -629,20 +666,12 @@ export class CommandCenter {
|
|||
}
|
||||
|
||||
const selection = resourceStates.filter(s => s instanceof Resource) as Resource[];
|
||||
const merge = selection.filter(s => s.resourceGroupType === ResourceGroupType.Merge);
|
||||
const bothModified = merge.filter(s => s.type === Status.BOTH_MODIFIED);
|
||||
const promises = bothModified.map(s => grep(s.resourceUri.fsPath, /^<{7}|^={7}|^>{7}/));
|
||||
const unresolvedBothModified = await Promise.all<boolean>(promises);
|
||||
const resolvedConflicts = bothModified.filter((s, i) => !unresolvedBothModified[i]);
|
||||
const unresolvedConflicts = [
|
||||
...merge.filter(s => s.type !== Status.BOTH_MODIFIED),
|
||||
...bothModified.filter((s, i) => unresolvedBothModified[i])
|
||||
];
|
||||
const { resolved, unresolved } = await categorizeResourceByResolution(selection);
|
||||
|
||||
if (unresolvedConflicts.length > 0) {
|
||||
const message = unresolvedConflicts.length > 1
|
||||
? localize('confirm stage files with merge conflicts', "Are you sure you want to stage {0} files with merge conflicts?", unresolvedConflicts.length)
|
||||
: localize('confirm stage file with merge conflicts', "Are you sure you want to stage {0} with merge conflicts?", path.basename(unresolvedConflicts[0].resourceUri.fsPath));
|
||||
if (unresolved.length > 0) {
|
||||
const message = unresolved.length > 1
|
||||
? localize('confirm stage files with merge conflicts', "Are you sure you want to stage {0} files with merge conflicts?", unresolved.length)
|
||||
: localize('confirm stage file with merge conflicts', "Are you sure you want to stage {0} with merge conflicts?", path.basename(unresolved[0].resourceUri.fsPath));
|
||||
|
||||
const yes = localize('yes', "Yes");
|
||||
const pick = await window.showWarningMessage(message, { modal: true }, yes);
|
||||
|
@ -653,7 +682,7 @@ export class CommandCenter {
|
|||
}
|
||||
|
||||
const workingTree = selection.filter(s => s.resourceGroupType === ResourceGroupType.WorkingTree);
|
||||
const scmResources = [...workingTree, ...resolvedConflicts, ...unresolvedConflicts];
|
||||
const scmResources = [...workingTree, ...resolved, ...unresolved];
|
||||
|
||||
this.outputChannel.appendLine(`git.stage.scmResources ${scmResources.length}`);
|
||||
if (!scmResources.length) {
|
||||
|
@ -667,12 +696,12 @@ export class CommandCenter {
|
|||
@command('git.stageAll', { repository: true })
|
||||
async stageAll(repository: Repository): Promise<void> {
|
||||
const resources = repository.mergeGroup.resourceStates.filter(s => s instanceof Resource) as Resource[];
|
||||
const mergeConflicts = resources.filter(s => s.resourceGroupType === ResourceGroupType.Merge);
|
||||
const { merge, unresolved } = await categorizeResourceByResolution(resources);
|
||||
|
||||
if (mergeConflicts.length > 0) {
|
||||
const message = mergeConflicts.length > 1
|
||||
? localize('confirm stage files with merge conflicts', "Are you sure you want to stage {0} files with merge conflicts?", mergeConflicts.length)
|
||||
: localize('confirm stage file with merge conflicts', "Are you sure you want to stage {0} with merge conflicts?", path.basename(mergeConflicts[0].resourceUri.fsPath));
|
||||
if (unresolved.length > 0) {
|
||||
const message = unresolved.length > 1
|
||||
? localize('confirm stage files with merge conflicts', "Are you sure you want to stage {0} files with merge conflicts?", merge.length)
|
||||
: localize('confirm stage file with merge conflicts', "Are you sure you want to stage {0} with merge conflicts?", path.basename(merge[0].resourceUri.fsPath));
|
||||
|
||||
const yes = localize('yes', "Yes");
|
||||
const pick = await window.showWarningMessage(message, { modal: true }, yes);
|
||||
|
@ -775,11 +804,18 @@ export class CommandCenter {
|
|||
|
||||
const originalUri = toGitUri(modifiedUri, '~');
|
||||
const originalDocument = await workspace.openTextDocument(originalUri);
|
||||
const selectionsBeforeRevert = textEditor.selections;
|
||||
const visibleRangesBeforeRevert = textEditor.visibleRanges;
|
||||
const result = applyLineChanges(originalDocument, modifiedDocument, changes);
|
||||
|
||||
const edit = new WorkspaceEdit();
|
||||
edit.replace(modifiedUri, new Range(new Position(0, 0), modifiedDocument.lineAt(modifiedDocument.lineCount - 1).range.end), result);
|
||||
workspace.applyEdit(edit);
|
||||
|
||||
await modifiedDocument.save();
|
||||
|
||||
textEditor.selections = selectionsBeforeRevert;
|
||||
textEditor.revealRange(visibleRangesBeforeRevert[0]);
|
||||
}
|
||||
|
||||
@command('git.unstage')
|
||||
|
@ -976,7 +1012,7 @@ export class CommandCenter {
|
|||
getCommitMessage: () => Promise<string | undefined>,
|
||||
opts?: CommitOptions
|
||||
): Promise<boolean> {
|
||||
const config = workspace.getConfiguration('git');
|
||||
const config = workspace.getConfiguration('git', Uri.file(repository.root));
|
||||
const promptToSaveFilesBeforeCommit = config.get<boolean>('promptToSaveFilesBeforeCommit') === true;
|
||||
|
||||
if (promptToSaveFilesBeforeCommit) {
|
||||
|
@ -1030,6 +1066,10 @@ export class CommandCenter {
|
|||
// enable signing of commits if configurated
|
||||
opts.signCommit = enableCommitSigning;
|
||||
|
||||
if (config.get<boolean>('alwaysSignOff')) {
|
||||
opts.signoff = true;
|
||||
}
|
||||
|
||||
if (
|
||||
// no changes
|
||||
(noStagedChanges && noUnstagedChanges)
|
||||
|
@ -1132,11 +1172,19 @@ export class CommandCenter {
|
|||
const HEAD = repository.HEAD;
|
||||
|
||||
if (!HEAD || !HEAD.commit) {
|
||||
window.showWarningMessage(localize('no more', "Can't undo because HEAD doesn't point to any commit."));
|
||||
return;
|
||||
}
|
||||
|
||||
const commit = await repository.getCommit('HEAD');
|
||||
await repository.reset('HEAD~');
|
||||
|
||||
if (commit.parents.length > 0) {
|
||||
await repository.reset('HEAD~');
|
||||
} else {
|
||||
await repository.deleteRef('HEAD');
|
||||
await this.unstageAll(repository);
|
||||
}
|
||||
|
||||
repository.inputBox.value = commit.message;
|
||||
}
|
||||
|
||||
|
@ -1273,16 +1321,7 @@ export class CommandCenter {
|
|||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
await choice.run(repository);
|
||||
} catch (err) {
|
||||
if (err.gitErrorCode !== GitErrorCodes.Conflict) {
|
||||
throw err;
|
||||
}
|
||||
|
||||
const message = localize('merge conflicts', "There are merge conflicts. Resolve them before committing.");
|
||||
await window.showWarningMessage(message);
|
||||
}
|
||||
await choice.run(repository);
|
||||
}
|
||||
|
||||
@command('git.createTag', { repository: true })
|
||||
|
@ -1655,10 +1694,11 @@ export class CommandCenter {
|
|||
|
||||
return result.catch(async err => {
|
||||
const options: MessageOptions = {
|
||||
modal: err.gitErrorCode === GitErrorCodes.DirtyWorkTree
|
||||
modal: true
|
||||
};
|
||||
|
||||
let message: string;
|
||||
let type: 'error' | 'warning' = 'error';
|
||||
|
||||
switch (err.gitErrorCode) {
|
||||
case GitErrorCodes.DirtyWorkTree:
|
||||
|
@ -1667,6 +1707,11 @@ export class CommandCenter {
|
|||
case GitErrorCodes.PushRejected:
|
||||
message = localize('cant push', "Can't push refs to remote. Try running 'Pull' first to integrate your changes.");
|
||||
break;
|
||||
case GitErrorCodes.Conflict:
|
||||
message = localize('merge conflicts', "There are merge conflicts. Resolve them before committing.");
|
||||
type = 'warning';
|
||||
options.modal = false;
|
||||
break;
|
||||
default:
|
||||
const hint = (err.stderr || err.message || String(err))
|
||||
.replace(/^error: /mi, '')
|
||||
|
@ -1687,11 +1732,11 @@ export class CommandCenter {
|
|||
return;
|
||||
}
|
||||
|
||||
options.modal = true;
|
||||
|
||||
const outputChannel = this.outputChannel as OutputChannel;
|
||||
const openOutputChannelChoice = localize('open git log', "Open Git Log");
|
||||
const choice = await window.showErrorMessage(message, options, openOutputChannelChoice);
|
||||
const choice = type === 'error'
|
||||
? await window.showErrorMessage(message, options, openOutputChannelChoice)
|
||||
: await window.showWarningMessage(message, options, openOutputChannelChoice);
|
||||
|
||||
if (choice === openOutputChannelChoice) {
|
||||
outputChannel.show();
|
||||
|
|
|
@ -336,7 +336,8 @@ export const GitErrorCodes = {
|
|||
NoStashFound: 'NoStashFound',
|
||||
LocalChangesOverwritten: 'LocalChangesOverwritten',
|
||||
NoUpstreamBranch: 'NoUpstreamBranch',
|
||||
IsInSubmodule: 'IsInSubmodule'
|
||||
IsInSubmodule: 'IsInSubmodule',
|
||||
WrongCase: 'WrongCase',
|
||||
};
|
||||
|
||||
function getGitErrorCode(stderr: string): string | undefined {
|
||||
|
@ -501,6 +502,7 @@ export class Git {
|
|||
export interface Commit {
|
||||
hash: string;
|
||||
message: string;
|
||||
parents: string[];
|
||||
}
|
||||
|
||||
export class GitStatusParser {
|
||||
|
@ -631,6 +633,47 @@ export function parseGitmodules(raw: string): Submodule[] {
|
|||
return result;
|
||||
}
|
||||
|
||||
export function parseGitCommit(raw: string): Commit | null {
|
||||
const match = /^([0-9a-f]{40})\n(.*)\n([^]*)$/m.exec(raw.trim());
|
||||
if (!match) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const parents = match[2] ? match[2].split(' ') : [];
|
||||
return { hash: match[1], message: match[3], parents };
|
||||
}
|
||||
|
||||
interface LsTreeElement {
|
||||
mode: string;
|
||||
type: string;
|
||||
object: string;
|
||||
size: string;
|
||||
file: string;
|
||||
}
|
||||
|
||||
export function parseLsTree(raw: string): LsTreeElement[] {
|
||||
return raw.split('\n')
|
||||
.filter(l => !!l)
|
||||
.map(line => /^(\S+)\s+(\S+)\s+(\S+)\s+(\S+)\s+(.*)$/.exec(line)!)
|
||||
.filter(m => !!m)
|
||||
.map(([, mode, type, object, size, file]) => ({ mode, type, object, size, file }));
|
||||
}
|
||||
|
||||
interface LsFilesElement {
|
||||
mode: string;
|
||||
object: string;
|
||||
stage: string;
|
||||
file: string;
|
||||
}
|
||||
|
||||
export function parseLsFiles(raw: string): LsFilesElement[] {
|
||||
return raw.split('\n')
|
||||
.filter(l => !!l)
|
||||
.map(line => /^(\S+)\s+(\S+)\s+(\S+)\s+(.*)$/.exec(line)!)
|
||||
.filter(m => !!m)
|
||||
.map(([, mode, object, stage, file]) => ({ mode, object, stage, file }));
|
||||
}
|
||||
|
||||
export interface DiffOptions {
|
||||
cached?: boolean;
|
||||
}
|
||||
|
@ -699,47 +742,72 @@ export class Repository {
|
|||
return Promise.reject<Buffer>('Can\'t open file from git');
|
||||
}
|
||||
|
||||
const { exitCode, stdout } = await exec(child);
|
||||
const { exitCode, stdout, stderr } = await exec(child);
|
||||
|
||||
if (exitCode) {
|
||||
return Promise.reject<Buffer>(new GitError({
|
||||
const err = new GitError({
|
||||
message: 'Could not show object.',
|
||||
exitCode
|
||||
}));
|
||||
});
|
||||
|
||||
if (/exists on disk, but not in/.test(stderr)) {
|
||||
err.gitErrorCode = GitErrorCodes.WrongCase;
|
||||
}
|
||||
|
||||
return Promise.reject<Buffer>(err);
|
||||
}
|
||||
|
||||
return stdout;
|
||||
}
|
||||
|
||||
async lstree(treeish: string, path: string): Promise<{ mode: string, object: string, size: number }> {
|
||||
async getObjectDetails(treeish: string, path: string): Promise<{ mode: string, object: string, size: number }> {
|
||||
if (!treeish) { // index
|
||||
const { stdout } = await this.run(['ls-files', '--stage', '--', path]);
|
||||
const elements = await this.lsfiles(path);
|
||||
|
||||
const match = /^(\d+)\s+([0-9a-f]{40})\s+(\d+)/.exec(stdout);
|
||||
|
||||
if (!match) {
|
||||
if (elements.length === 0) {
|
||||
throw new GitError({ message: 'Error running ls-files' });
|
||||
}
|
||||
|
||||
const [, mode, object] = match;
|
||||
const { mode, object } = elements[0];
|
||||
const catFile = await this.run(['cat-file', '-s', object]);
|
||||
const size = parseInt(catFile.stdout);
|
||||
|
||||
return { mode, object, size };
|
||||
}
|
||||
|
||||
const { stdout } = await this.run(['ls-tree', '-l', treeish, '--', path]);
|
||||
const elements = await this.lstree(treeish, path);
|
||||
|
||||
const match = /^(\d+)\s+(\w+)\s+([0-9a-f]{40})\s+(\d+)/.exec(stdout);
|
||||
|
||||
if (!match) {
|
||||
throw new GitError({ message: 'Error running ls-tree' });
|
||||
if (elements.length === 0) {
|
||||
throw new GitError({ message: 'Error running ls-files' });
|
||||
}
|
||||
|
||||
const [, mode, , object, size] = match;
|
||||
const { mode, object, size } = elements[0];
|
||||
return { mode, object, size: parseInt(size) };
|
||||
}
|
||||
|
||||
async lstree(treeish: string, path: string): Promise<LsTreeElement[]> {
|
||||
const { stdout } = await this.run(['ls-tree', '-l', treeish, '--', path]);
|
||||
return parseLsTree(stdout);
|
||||
}
|
||||
|
||||
async lsfiles(path: string): Promise<LsFilesElement[]> {
|
||||
const { stdout } = await this.run(['ls-files', '--stage', '--', path]);
|
||||
return parseLsFiles(stdout);
|
||||
}
|
||||
|
||||
async getGitRelativePath(ref: string, relativePath: string): Promise<string> {
|
||||
const relativePathLowercase = relativePath.toLowerCase();
|
||||
const dirname = path.posix.dirname(relativePath) + '/';
|
||||
const elements: { file: string; }[] = ref ? await this.lstree(ref, dirname) : await this.lsfiles(dirname);
|
||||
const element = elements.filter(file => file.file.toLowerCase() === relativePathLowercase)[0];
|
||||
|
||||
if (!element) {
|
||||
throw new GitError({ message: 'Git relative path not found.' });
|
||||
}
|
||||
|
||||
return element.file;
|
||||
}
|
||||
|
||||
async detectObjectType(object: string): Promise<{ mimetype: string, encoding?: string }> {
|
||||
const child = await this.stream(['show', object]);
|
||||
const buffer = await readBytes(child.stdout, 4100);
|
||||
|
@ -822,7 +890,7 @@ export class Repository {
|
|||
let mode: string;
|
||||
|
||||
try {
|
||||
const details = await this.lstree('HEAD', path);
|
||||
const details = await this.getObjectDetails('HEAD', path);
|
||||
mode = details.mode;
|
||||
} catch (err) {
|
||||
mode = '100644';
|
||||
|
@ -876,27 +944,41 @@ export class Repository {
|
|||
try {
|
||||
await this.run(args, { input: message || '' });
|
||||
} catch (commitErr) {
|
||||
if (/not possible because you have unmerged files/.test(commitErr.stderr || '')) {
|
||||
commitErr.gitErrorCode = GitErrorCodes.UnmergedChanges;
|
||||
throw commitErr;
|
||||
}
|
||||
await this.handleCommitError(commitErr);
|
||||
}
|
||||
}
|
||||
|
||||
try {
|
||||
await this.run(['config', '--get-all', 'user.name']);
|
||||
} catch (err) {
|
||||
err.gitErrorCode = GitErrorCodes.NoUserNameConfigured;
|
||||
throw err;
|
||||
}
|
||||
async rebaseContinue(): Promise<void> {
|
||||
const args = ['rebase', '--continue'];
|
||||
|
||||
try {
|
||||
await this.run(['config', '--get-all', 'user.email']);
|
||||
} catch (err) {
|
||||
err.gitErrorCode = GitErrorCodes.NoUserEmailConfigured;
|
||||
throw err;
|
||||
}
|
||||
try {
|
||||
await this.run(args);
|
||||
} catch (commitErr) {
|
||||
await this.handleCommitError(commitErr);
|
||||
}
|
||||
}
|
||||
|
||||
private async handleCommitError(commitErr: any): Promise<void> {
|
||||
if (/not possible because you have unmerged files/.test(commitErr.stderr || '')) {
|
||||
commitErr.gitErrorCode = GitErrorCodes.UnmergedChanges;
|
||||
throw commitErr;
|
||||
}
|
||||
|
||||
try {
|
||||
await this.run(['config', '--get-all', 'user.name']);
|
||||
} catch (err) {
|
||||
err.gitErrorCode = GitErrorCodes.NoUserNameConfigured;
|
||||
throw err;
|
||||
}
|
||||
|
||||
try {
|
||||
await this.run(['config', '--get-all', 'user.email']);
|
||||
} catch (err) {
|
||||
err.gitErrorCode = GitErrorCodes.NoUserEmailConfigured;
|
||||
throw err;
|
||||
}
|
||||
|
||||
throw commitErr;
|
||||
}
|
||||
|
||||
async branch(name: string, checkout: boolean): Promise<void> {
|
||||
|
@ -914,6 +996,11 @@ export class Repository {
|
|||
await this.run(args);
|
||||
}
|
||||
|
||||
async deleteRef(ref: string): Promise<void> {
|
||||
const args = ['update-ref', '-d', ref];
|
||||
await this.run(args);
|
||||
}
|
||||
|
||||
async merge(ref: string): Promise<void> {
|
||||
const args = ['merge', ref];
|
||||
|
||||
|
@ -1328,14 +1415,8 @@ export class Repository {
|
|||
}
|
||||
|
||||
async getCommit(ref: string): Promise<Commit> {
|
||||
const result = await this.run(['show', '-s', '--format=%H\n%B', ref]);
|
||||
const match = /^([0-9a-f]{40})\n([^]*)$/m.exec(result.stdout.trim());
|
||||
|
||||
if (!match) {
|
||||
return Promise.reject<Commit>('bad commit format');
|
||||
}
|
||||
|
||||
return { hash: match[1], message: match[2] };
|
||||
const result = await this.run(['show', '-s', '--format=%H\n%P\n%B', ref]);
|
||||
return parseGitCommit(result.stdout) || Promise.reject<Commit>('bad commit format');
|
||||
}
|
||||
|
||||
async updateSubmodules(paths: string[]): Promise<void> {
|
||||
|
|
|
@ -91,6 +91,13 @@ export class Model {
|
|||
* for git repositories.
|
||||
*/
|
||||
private async scanWorkspaceFolders(): Promise<void> {
|
||||
const config = workspace.getConfiguration('git');
|
||||
const autoRepositoryDetection = config.get<boolean | 'subFolders' | 'openEditors'>('autoRepositoryDetection');
|
||||
|
||||
if (autoRepositoryDetection !== true && autoRepositoryDetection !== 'subFolders') {
|
||||
return;
|
||||
}
|
||||
|
||||
for (const folder of workspace.workspaceFolders || []) {
|
||||
const root = folder.uri.fsPath;
|
||||
|
||||
|
@ -99,7 +106,7 @@ export class Model {
|
|||
|
||||
children
|
||||
.filter(child => child !== '.git')
|
||||
.forEach(child => this.tryOpenRepository(path.join(root, child)));
|
||||
.forEach(child => this.openRepository(path.join(root, child)));
|
||||
} catch (err) {
|
||||
// noop
|
||||
}
|
||||
|
@ -118,7 +125,7 @@ export class Model {
|
|||
@debounce(500)
|
||||
private eventuallyScanPossibleGitRepositories(): void {
|
||||
for (const path of this.possibleGitRepositoryPaths) {
|
||||
this.tryOpenRepository(path);
|
||||
this.openRepository(path);
|
||||
}
|
||||
|
||||
this.possibleGitRepositoryPaths.clear();
|
||||
|
@ -139,7 +146,7 @@ export class Model {
|
|||
.filter(r => !activeRepositories.has(r!.repository))
|
||||
.filter(r => !(workspace.workspaceFolders || []).some(f => isDescendant(f.uri.fsPath, r!.repository.root))) as OpenRepository[];
|
||||
|
||||
possibleRepositoryFolders.forEach(p => this.tryOpenRepository(p.uri.fsPath));
|
||||
possibleRepositoryFolders.forEach(p => this.openRepository(p.uri.fsPath));
|
||||
openRepositoriesToDispose.forEach(r => r.dispose());
|
||||
}
|
||||
|
||||
|
@ -153,15 +160,15 @@ export class Model {
|
|||
.filter(({ root }) => workspace.getConfiguration('git', root).get<boolean>('enabled') !== true)
|
||||
.map(({ repository }) => repository);
|
||||
|
||||
possibleRepositoryFolders.forEach(p => this.tryOpenRepository(p.uri.fsPath));
|
||||
possibleRepositoryFolders.forEach(p => this.openRepository(p.uri.fsPath));
|
||||
openRepositoriesToDispose.forEach(r => r.dispose());
|
||||
}
|
||||
|
||||
private onDidChangeVisibleTextEditors(editors: TextEditor[]): void {
|
||||
const config = workspace.getConfiguration('git');
|
||||
const enabled = config.get<boolean>('autoRepositoryDetection') === true;
|
||||
const autoRepositoryDetection = config.get<boolean | 'subFolders' | 'openEditors'>('autoRepositoryDetection');
|
||||
|
||||
if (!enabled) {
|
||||
if (autoRepositoryDetection !== true && autoRepositoryDetection !== 'openEditors') {
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -178,12 +185,12 @@ export class Model {
|
|||
return;
|
||||
}
|
||||
|
||||
this.tryOpenRepository(path.dirname(uri.fsPath));
|
||||
this.openRepository(path.dirname(uri.fsPath));
|
||||
});
|
||||
}
|
||||
|
||||
@sequentialize
|
||||
async tryOpenRepository(path: string): Promise<void> {
|
||||
async openRepository(path: string): Promise<void> {
|
||||
if (this.getRepository(path)) {
|
||||
return;
|
||||
}
|
||||
|
@ -207,6 +214,13 @@ export class Model {
|
|||
return;
|
||||
}
|
||||
|
||||
const config = workspace.getConfiguration('git');
|
||||
const ignoredRepos = new Set(config.get<Array<string>>('ignoredRepositories'));
|
||||
|
||||
if (ignoredRepos.has(rawRoot)) {
|
||||
return;
|
||||
}
|
||||
|
||||
const repository = new Repository(this.git.open(repositoryRoot), this.globalState);
|
||||
|
||||
this.open(repository);
|
||||
|
|
|
@ -5,16 +5,16 @@
|
|||
|
||||
'use strict';
|
||||
|
||||
import { ProtocolHandler, Uri, window, Disposable, commands } from 'vscode';
|
||||
import { UriHandler, Uri, window, Disposable, commands } from 'vscode';
|
||||
import { dispose } from './util';
|
||||
import * as querystring from 'querystring';
|
||||
|
||||
export class GitProtocolHandler implements ProtocolHandler {
|
||||
export class GitProtocolHandler implements UriHandler {
|
||||
|
||||
private disposables: Disposable[] = [];
|
||||
|
||||
constructor() {
|
||||
this.disposables.push(window.registerProtocolHandler(this));
|
||||
this.disposables.push(window.registerUriHandler(this));
|
||||
}
|
||||
|
||||
handleUri(uri: Uri): void {
|
||||
|
|
|
@ -293,13 +293,15 @@ export enum Operation {
|
|||
GetCommitTemplate = 'GetCommitTemplate',
|
||||
DeleteBranch = 'DeleteBranch',
|
||||
RenameBranch = 'RenameBranch',
|
||||
DeleteRef = 'DeleteRef',
|
||||
Merge = 'Merge',
|
||||
Ignore = 'Ignore',
|
||||
Tag = 'Tag',
|
||||
Stash = 'Stash',
|
||||
CheckIgnore = 'CheckIgnore',
|
||||
LSTree = 'LSTree',
|
||||
SubmoduleUpdate = 'SubmoduleUpdate'
|
||||
GetObjectDetails = 'GetObjectDetails',
|
||||
SubmoduleUpdate = 'SubmoduleUpdate',
|
||||
RebaseContinue = 'RebaseContinue',
|
||||
}
|
||||
|
||||
function isReadOnly(operation: Operation): boolean {
|
||||
|
@ -307,7 +309,7 @@ function isReadOnly(operation: Operation): boolean {
|
|||
case Operation.Show:
|
||||
case Operation.GetCommitTemplate:
|
||||
case Operation.CheckIgnore:
|
||||
case Operation.LSTree:
|
||||
case Operation.GetObjectDetails:
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
|
@ -318,7 +320,7 @@ function shouldShowProgress(operation: Operation): boolean {
|
|||
switch (operation) {
|
||||
case Operation.Fetch:
|
||||
case Operation.CheckIgnore:
|
||||
case Operation.LSTree:
|
||||
case Operation.GetObjectDetails:
|
||||
case Operation.Show:
|
||||
return false;
|
||||
default:
|
||||
|
@ -479,6 +481,22 @@ export class Repository implements Disposable {
|
|||
return this._submodules;
|
||||
}
|
||||
|
||||
private _rebaseCommit: Commit | undefined = undefined;
|
||||
|
||||
set rebaseCommit(rebaseCommit: Commit | undefined) {
|
||||
if (this._rebaseCommit && !rebaseCommit) {
|
||||
this.inputBox.value = '';
|
||||
} else if (rebaseCommit && (!this._rebaseCommit || this._rebaseCommit.hash !== rebaseCommit.hash)) {
|
||||
this.inputBox.value = rebaseCommit.message;
|
||||
}
|
||||
|
||||
this._rebaseCommit = rebaseCommit;
|
||||
}
|
||||
|
||||
get rebaseCommit(): Commit | undefined {
|
||||
return this._rebaseCommit;
|
||||
}
|
||||
|
||||
private _operations = new OperationsImpl();
|
||||
get operations(): Operations { return this._operations; }
|
||||
|
||||
|
@ -540,6 +558,16 @@ export class Repository implements Disposable {
|
|||
|
||||
this.disposables.push(new AutoFetcher(this, globalState));
|
||||
|
||||
// https://github.com/Microsoft/vscode/issues/39039
|
||||
const onSuccessfulPush = filterEvent(this.onDidRunOperation, e => e.operation === Operation.Push && !e.error);
|
||||
onSuccessfulPush(() => {
|
||||
const gitConfig = workspace.getConfiguration('git');
|
||||
|
||||
if (gitConfig.get<boolean>('showPushSuccessNotification')) {
|
||||
window.showInformationMessage(localize('push success', "Successfully pushed."));
|
||||
}
|
||||
}, null, this.disposables);
|
||||
|
||||
const statusBar = new StatusBarCommands(this);
|
||||
this.disposables.push(statusBar);
|
||||
statusBar.onDidChange(() => this._sourceControl.statusBarCommands = statusBar.commands, null, this.disposables);
|
||||
|
@ -553,6 +581,15 @@ export class Repository implements Disposable {
|
|||
}
|
||||
|
||||
validateInput(text: string, position: number): SourceControlInputBoxValidation | undefined {
|
||||
if (this.rebaseCommit) {
|
||||
if (this.rebaseCommit.message !== text) {
|
||||
return {
|
||||
message: localize('commit in rebase', "It's not possible to change the commit message in the middle of a rebase. Please complete the rebase operation and use interactive rebase instead."),
|
||||
type: SourceControlInputBoxValidationType.Warning
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
const config = workspace.getConfiguration('git');
|
||||
const setting = config.get<'always' | 'warn' | 'off'>('inputValidation');
|
||||
|
||||
|
@ -636,13 +673,23 @@ export class Repository implements Disposable {
|
|||
}
|
||||
|
||||
async commit(message: string, opts: CommitOptions = Object.create(null)): Promise<void> {
|
||||
await this.run(Operation.Commit, async () => {
|
||||
if (opts.all) {
|
||||
await this.repository.add([]);
|
||||
}
|
||||
if (this.rebaseCommit) {
|
||||
await this.run(Operation.RebaseContinue, async () => {
|
||||
if (opts.all) {
|
||||
await this.repository.add([]);
|
||||
}
|
||||
|
||||
await this.repository.commit(message, opts);
|
||||
});
|
||||
await this.repository.rebaseContinue();
|
||||
});
|
||||
} else {
|
||||
await this.run(Operation.Commit, async () => {
|
||||
if (opts.all) {
|
||||
await this.repository.add([]);
|
||||
}
|
||||
|
||||
await this.repository.commit(message, opts);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
async clean(resources: Uri[]): Promise<void> {
|
||||
|
@ -730,6 +777,10 @@ export class Repository implements Disposable {
|
|||
await this.run(Operation.Reset, () => this.repository.reset(treeish, hard));
|
||||
}
|
||||
|
||||
async deleteRef(ref: string): Promise<void> {
|
||||
await this.run(Operation.DeleteRef, () => this.repository.deleteRef(ref));
|
||||
}
|
||||
|
||||
@throttle
|
||||
async fetch(): Promise<void> {
|
||||
await this.run(Operation.Fetch, () => this.repository.fetch());
|
||||
|
@ -825,13 +876,22 @@ export class Repository implements Disposable {
|
|||
}
|
||||
|
||||
async show(ref: string, filePath: string): Promise<string> {
|
||||
return this.run(Operation.Show, () => {
|
||||
return await this.run(Operation.Show, async () => {
|
||||
const relativePath = path.relative(this.repository.root, filePath).replace(/\\/g, '/');
|
||||
const configFiles = workspace.getConfiguration('files', Uri.file(filePath));
|
||||
const defaultEncoding = configFiles.get<string>('encoding');
|
||||
const autoGuessEncoding = configFiles.get<boolean>('autoGuessEncoding');
|
||||
|
||||
return this.repository.bufferString(`${ref}:${relativePath}`, defaultEncoding, autoGuessEncoding);
|
||||
try {
|
||||
return await this.repository.bufferString(`${ref}:${relativePath}`, defaultEncoding, autoGuessEncoding);
|
||||
} catch (err) {
|
||||
if (err.gitErrorCode === GitErrorCodes.WrongCase) {
|
||||
const gitRelativePath = await this.repository.getGitRelativePath(ref, relativePath);
|
||||
return await this.repository.bufferString(`${ref}:${gitRelativePath}`, defaultEncoding, autoGuessEncoding);
|
||||
}
|
||||
|
||||
throw err;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -842,8 +902,8 @@ export class Repository implements Disposable {
|
|||
});
|
||||
}
|
||||
|
||||
lstree(ref: string, filePath: string): Promise<{ mode: string, object: string, size: number }> {
|
||||
return this.run(Operation.LSTree, () => this.repository.lstree(ref, filePath));
|
||||
getObjectDetails(ref: string, filePath: string): Promise<{ mode: string, object: string, size: number }> {
|
||||
return this.run(Operation.GetObjectDetails, () => this.repository.getObjectDetails(ref, filePath));
|
||||
}
|
||||
|
||||
detectObjectType(object: string): Promise<{ mimetype: string, encoding?: string }> {
|
||||
|
@ -1025,12 +1085,13 @@ export class Repository implements Disposable {
|
|||
// noop
|
||||
}
|
||||
|
||||
const [refs, remotes, submodules] = await Promise.all([this.repository.getRefs(), this.repository.getRemotes(), this.repository.getSubmodules()]);
|
||||
const [refs, remotes, submodules, rebaseCommit] = await Promise.all([this.repository.getRefs(), this.repository.getRemotes(), this.repository.getSubmodules(), this.getRebaseCommit()]);
|
||||
|
||||
this._HEAD = HEAD;
|
||||
this._refs = refs;
|
||||
this._remotes = remotes;
|
||||
this._submodules = submodules;
|
||||
this.rebaseCommit = rebaseCommit;
|
||||
|
||||
const index: Resource[] = [];
|
||||
const workingTree: Resource[] = [];
|
||||
|
@ -1089,6 +1150,17 @@ export class Repository implements Disposable {
|
|||
this._onDidChangeStatus.fire();
|
||||
}
|
||||
|
||||
private async getRebaseCommit(): Promise<Commit | undefined> {
|
||||
const rebaseHeadPath = path.join(this.repository.root, '.git', 'REBASE_HEAD');
|
||||
|
||||
try {
|
||||
const rebaseHead = await new Promise<string>((c, e) => fs.readFile(rebaseHeadPath, 'utf8', (err, result) => err ? e(err) : c(result)));
|
||||
return await this.getCommit(rebaseHead.trim());
|
||||
} catch (err) {
|
||||
return undefined;
|
||||
}
|
||||
}
|
||||
|
||||
private onFSChange(uri: Uri): void {
|
||||
const config = workspace.getConfiguration('git');
|
||||
const autorefresh = config.get<boolean>('autorefresh');
|
||||
|
|
|
@ -24,7 +24,8 @@ class CheckoutStatusBar {
|
|||
}
|
||||
|
||||
get command(): Command | undefined {
|
||||
const title = `$(git-branch) ${this.repository.headLabel}`;
|
||||
const rebasing = !!this.repository.rebaseCommit;
|
||||
const title = `$(git-branch) ${this.repository.headLabel}${rebasing ? ` (${localize('rebasing', 'Rebasing')})` : ''}`;
|
||||
|
||||
return {
|
||||
command: 'git.checkout',
|
||||
|
|
|
@ -6,7 +6,7 @@
|
|||
'use strict';
|
||||
|
||||
import 'mocha';
|
||||
import { GitStatusParser, parseGitmodules } from '../git';
|
||||
import { GitStatusParser, parseGitCommit, parseGitmodules, parseLsTree, parseLsFiles } from '../git';
|
||||
import * as assert from 'assert';
|
||||
|
||||
suite('git', () => {
|
||||
|
@ -175,4 +175,106 @@ suite('git', () => {
|
|||
]);
|
||||
});
|
||||
});
|
||||
|
||||
suite('parseGitCommit', () => {
|
||||
test('single parent commit', function () {
|
||||
const GIT_OUTPUT_SINGLE_PARENT = `52c293a05038d865604c2284aa8698bd087915a1
|
||||
8e5a374372b8393906c7e380dbb09349c5385554
|
||||
This is a commit message.`;
|
||||
|
||||
assert.deepEqual(parseGitCommit(GIT_OUTPUT_SINGLE_PARENT), {
|
||||
hash: '52c293a05038d865604c2284aa8698bd087915a1',
|
||||
message: 'This is a commit message.',
|
||||
parents: ['8e5a374372b8393906c7e380dbb09349c5385554']
|
||||
});
|
||||
});
|
||||
|
||||
test('multiple parent commits', function () {
|
||||
const GIT_OUTPUT_MULTIPLE_PARENTS = `52c293a05038d865604c2284aa8698bd087915a1
|
||||
8e5a374372b8393906c7e380dbb09349c5385554 df27d8c75b129ab9b178b386077da2822101b217
|
||||
This is a commit message.`;
|
||||
|
||||
assert.deepEqual(parseGitCommit(GIT_OUTPUT_MULTIPLE_PARENTS), {
|
||||
hash: '52c293a05038d865604c2284aa8698bd087915a1',
|
||||
message: 'This is a commit message.',
|
||||
parents: ['8e5a374372b8393906c7e380dbb09349c5385554', 'df27d8c75b129ab9b178b386077da2822101b217']
|
||||
});
|
||||
});
|
||||
|
||||
test('no parent commits', function () {
|
||||
const GIT_OUTPUT_NO_PARENTS = `52c293a05038d865604c2284aa8698bd087915a1
|
||||
|
||||
This is a commit message.`;
|
||||
|
||||
assert.deepEqual(parseGitCommit(GIT_OUTPUT_NO_PARENTS), {
|
||||
hash: '52c293a05038d865604c2284aa8698bd087915a1',
|
||||
message: 'This is a commit message.',
|
||||
parents: []
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
suite('parseLsTree', function () {
|
||||
test('sample', function () {
|
||||
const input = `040000 tree 0274a81f8ee9ca3669295dc40f510bd2021d0043 - .vscode
|
||||
100644 blob 1d487c1817262e4f20efbfa1d04c18f51b0046f6 491570 Screen Shot 2018-06-01 at 14.48.05.png
|
||||
100644 blob 686c16e4f019b734655a2576ce8b98749a9ffdb9 764420 Screen Shot 2018-06-07 at 20.04.59.png
|
||||
100644 blob 257cc5642cb1a054f08cc83f2d943e56fd3ebe99 4 boom.txt
|
||||
100644 blob 86dc360dd25f13fa50ffdc8259e9653921f4f2b7 11 boomcaboom.txt
|
||||
100644 blob a68b14060589b16d7ac75f67b905c918c03c06eb 24 file.js
|
||||
100644 blob f7bcfb05af46850d780f88c069edcd57481d822d 201 file.md
|
||||
100644 blob ab8b86114a051f6490f1ec5e3141b9a632fb46b5 8 hello.js
|
||||
100644 blob 257cc5642cb1a054f08cc83f2d943e56fd3ebe99 4 what.js
|
||||
100644 blob be859e3f412fa86513cd8bebe8189d1ea1a3e46d 24 what.txt
|
||||
100644 blob 56ec42c9dc6fcf4534788f0fe34b36e09f37d085 261186 what.txt2`;
|
||||
|
||||
const output = parseLsTree(input);
|
||||
|
||||
assert.deepEqual(output, [
|
||||
{ mode: '040000', type: 'tree', object: '0274a81f8ee9ca3669295dc40f510bd2021d0043', size: '-', file: '.vscode' },
|
||||
{ mode: '100644', type: 'blob', object: '1d487c1817262e4f20efbfa1d04c18f51b0046f6', size: '491570', file: 'Screen Shot 2018-06-01 at 14.48.05.png' },
|
||||
{ mode: '100644', type: 'blob', object: '686c16e4f019b734655a2576ce8b98749a9ffdb9', size: '764420', file: 'Screen Shot 2018-06-07 at 20.04.59.png' },
|
||||
{ mode: '100644', type: 'blob', object: '257cc5642cb1a054f08cc83f2d943e56fd3ebe99', size: '4', file: 'boom.txt' },
|
||||
{ mode: '100644', type: 'blob', object: '86dc360dd25f13fa50ffdc8259e9653921f4f2b7', size: '11', file: 'boomcaboom.txt' },
|
||||
{ mode: '100644', type: 'blob', object: 'a68b14060589b16d7ac75f67b905c918c03c06eb', size: '24', file: 'file.js' },
|
||||
{ mode: '100644', type: 'blob', object: 'f7bcfb05af46850d780f88c069edcd57481d822d', size: '201', file: 'file.md' },
|
||||
{ mode: '100644', type: 'blob', object: 'ab8b86114a051f6490f1ec5e3141b9a632fb46b5', size: '8', file: 'hello.js' },
|
||||
{ mode: '100644', type: 'blob', object: '257cc5642cb1a054f08cc83f2d943e56fd3ebe99', size: '4', file: 'what.js' },
|
||||
{ mode: '100644', type: 'blob', object: 'be859e3f412fa86513cd8bebe8189d1ea1a3e46d', size: '24', file: 'what.txt' },
|
||||
{ mode: '100644', type: 'blob', object: '56ec42c9dc6fcf4534788f0fe34b36e09f37d085', size: '261186', file: 'what.txt2' }
|
||||
]);
|
||||
});
|
||||
});
|
||||
|
||||
suite('parseLsFiles', function () {
|
||||
test('sample', function () {
|
||||
const input = `100644 7a73a41bfdf76d6f793007240d80983a52f15f97 0 .vscode/settings.json
|
||||
100644 1d487c1817262e4f20efbfa1d04c18f51b0046f6 0 Screen Shot 2018-06-01 at 14.48.05.png
|
||||
100644 686c16e4f019b734655a2576ce8b98749a9ffdb9 0 Screen Shot 2018-06-07 at 20.04.59.png
|
||||
100644 257cc5642cb1a054f08cc83f2d943e56fd3ebe99 0 boom.txt
|
||||
100644 86dc360dd25f13fa50ffdc8259e9653921f4f2b7 0 boomcaboom.txt
|
||||
100644 a68b14060589b16d7ac75f67b905c918c03c06eb 0 file.js
|
||||
100644 f7bcfb05af46850d780f88c069edcd57481d822d 0 file.md
|
||||
100644 ab8b86114a051f6490f1ec5e3141b9a632fb46b5 0 hello.js
|
||||
100644 257cc5642cb1a054f08cc83f2d943e56fd3ebe99 0 what.js
|
||||
100644 be859e3f412fa86513cd8bebe8189d1ea1a3e46d 0 what.txt
|
||||
100644 56ec42c9dc6fcf4534788f0fe34b36e09f37d085 0 what.txt2`;
|
||||
|
||||
const output = parseLsFiles(input);
|
||||
|
||||
assert.deepEqual(output, [
|
||||
{ mode: '100644', object: '7a73a41bfdf76d6f793007240d80983a52f15f97', stage: '0', file: '.vscode/settings.json' },
|
||||
{ mode: '100644', object: '1d487c1817262e4f20efbfa1d04c18f51b0046f6', stage: '0', file: 'Screen Shot 2018-06-01 at 14.48.05.png' },
|
||||
{ mode: '100644', object: '686c16e4f019b734655a2576ce8b98749a9ffdb9', stage: '0', file: 'Screen Shot 2018-06-07 at 20.04.59.png' },
|
||||
{ mode: '100644', object: '257cc5642cb1a054f08cc83f2d943e56fd3ebe99', stage: '0', file: 'boom.txt' },
|
||||
{ mode: '100644', object: '86dc360dd25f13fa50ffdc8259e9653921f4f2b7', stage: '0', file: 'boomcaboom.txt' },
|
||||
{ mode: '100644', object: 'a68b14060589b16d7ac75f67b905c918c03c06eb', stage: '0', file: 'file.js' },
|
||||
{ mode: '100644', object: 'f7bcfb05af46850d780f88c069edcd57481d822d', stage: '0', file: 'file.md' },
|
||||
{ mode: '100644', object: 'ab8b86114a051f6490f1ec5e3141b9a632fb46b5', stage: '0', file: 'hello.js' },
|
||||
{ mode: '100644', object: '257cc5642cb1a054f08cc83f2d943e56fd3ebe99', stage: '0', file: 'what.js' },
|
||||
{ mode: '100644', object: 'be859e3f412fa86513cd8bebe8189d1ea1a3e46d', stage: '0', file: 'what.txt' },
|
||||
{ mode: '100644', object: '56ec42c9dc6fcf4534788f0fe34b36e09f37d085', stage: '0', file: 'what.txt2' },
|
||||
]);
|
||||
});
|
||||
});
|
||||
});
|
|
@ -263,9 +263,9 @@ vscode-extension-telemetry@0.0.17:
|
|||
dependencies:
|
||||
applicationinsights "1.0.1"
|
||||
|
||||
vscode-nls@^3.2.1:
|
||||
version "3.2.1"
|
||||
resolved "https://registry.yarnpkg.com/vscode-nls/-/vscode-nls-3.2.1.tgz#b1f3e04e8a94a715d5a7bcbc8339c51e6d74ca51"
|
||||
vscode-nls@^3.2.4:
|
||||
version "3.2.4"
|
||||
resolved "https://registry.yarnpkg.com/vscode-nls/-/vscode-nls-3.2.4.tgz#2166b4183c8aea884d20727f5449e62be69fd398"
|
||||
|
||||
which@^1.3.0:
|
||||
version "1.3.0"
|
||||
|
|
|
@ -16,7 +16,7 @@
|
|||
"watch": "gulp watch-extension:grunt"
|
||||
},
|
||||
"dependencies": {
|
||||
"vscode-nls": "^3.2.1"
|
||||
"vscode-nls": "^3.2.4"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/node": "7.0.43"
|
||||
|
|
|
@ -6,6 +6,6 @@
|
|||
version "7.0.43"
|
||||
resolved "https://registry.yarnpkg.com/@types/node/-/node-7.0.43.tgz#a187e08495a075f200ca946079c914e1a5fe962c"
|
||||
|
||||
vscode-nls@^3.2.1:
|
||||
version "3.2.1"
|
||||
resolved "https://registry.yarnpkg.com/vscode-nls/-/vscode-nls-3.2.1.tgz#b1f3e04e8a94a715d5a7bcbc8339c51e6d74ca51"
|
||||
vscode-nls@^3.2.4:
|
||||
version "3.2.4"
|
||||
resolved "https://registry.yarnpkg.com/vscode-nls/-/vscode-nls-3.2.4.tgz#2166b4183c8aea884d20727f5449e62be69fd398"
|
||||
|
|
|
@ -16,7 +16,7 @@
|
|||
"watch": "gulp watch-extension:gulp"
|
||||
},
|
||||
"dependencies": {
|
||||
"vscode-nls": "^3.2.1"
|
||||
"vscode-nls": "^3.2.4"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/node": "7.0.43"
|
||||
|
|
|
@ -6,6 +6,6 @@
|
|||
version "7.0.43"
|
||||
resolved "https://registry.yarnpkg.com/@types/node/-/node-7.0.43.tgz#a187e08495a075f200ca946079c914e1a5fe962c"
|
||||
|
||||
vscode-nls@^3.2.1:
|
||||
version "3.2.1"
|
||||
resolved "https://registry.yarnpkg.com/vscode-nls/-/vscode-nls-3.2.1.tgz#b1f3e04e8a94a715d5a7bcbc8339c51e6d74ca51"
|
||||
vscode-nls@^3.2.4:
|
||||
version "3.2.4"
|
||||
resolved "https://registry.yarnpkg.com/vscode-nls/-/vscode-nls-3.2.4.tgz#2166b4183c8aea884d20727f5449e62be69fd398"
|
||||
|
|
|
@ -176,7 +176,7 @@
|
|||
"vscode-extension-telemetry": "0.0.17",
|
||||
"vscode-languageclient": "^4.1.4",
|
||||
"vscode-languageserver-protocol-foldingprovider": "^2.0.1",
|
||||
"vscode-nls": "^3.2.2"
|
||||
"vscode-nls": "^3.2.4"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/node": "7.0.43"
|
||||
|
|
|
@ -13,7 +13,7 @@
|
|||
"vscode-languageserver": "^4.1.3",
|
||||
"vscode-languageserver-protocol-foldingprovider": "^2.0.1",
|
||||
"vscode-languageserver-types": "^3.7.2",
|
||||
"vscode-nls": "^3.2.2",
|
||||
"vscode-nls": "^3.2.4",
|
||||
"vscode-uri": "^1.0.3"
|
||||
},
|
||||
"devDependencies": {
|
||||
|
|
|
@ -242,6 +242,10 @@ vscode-nls@^3.2.2:
|
|||
version "3.2.2"
|
||||
resolved "https://registry.yarnpkg.com/vscode-nls/-/vscode-nls-3.2.2.tgz#3817eca5b985c2393de325197cf4e15eb2aa5350"
|
||||
|
||||
vscode-nls@^3.2.4:
|
||||
version "3.2.4"
|
||||
resolved "https://registry.yarnpkg.com/vscode-nls/-/vscode-nls-3.2.4.tgz#2166b4183c8aea884d20727f5449e62be69fd398"
|
||||
|
||||
vscode-uri@^1.0.1:
|
||||
version "1.0.1"
|
||||
resolved "https://registry.yarnpkg.com/vscode-uri/-/vscode-uri-1.0.1.tgz#11a86befeac3c4aa3ec08623651a3c81a6d0bbc8"
|
||||
|
|
|
@ -62,9 +62,9 @@ vscode-languageserver-types@^3.7.2:
|
|||
version "3.7.2"
|
||||
resolved "https://registry.yarnpkg.com/vscode-languageserver-types/-/vscode-languageserver-types-3.7.2.tgz#aad8846f8e3e27962648554de5a8417e358f34eb"
|
||||
|
||||
vscode-nls@^3.2.2:
|
||||
version "3.2.2"
|
||||
resolved "https://registry.yarnpkg.com/vscode-nls/-/vscode-nls-3.2.2.tgz#3817eca5b985c2393de325197cf4e15eb2aa5350"
|
||||
vscode-nls@^3.2.4:
|
||||
version "3.2.4"
|
||||
resolved "https://registry.yarnpkg.com/vscode-nls/-/vscode-nls-3.2.4.tgz#2166b4183c8aea884d20727f5449e62be69fd398"
|
||||
|
||||
zone.js@0.7.6:
|
||||
version "0.7.6"
|
||||
|
|
|
@ -16,7 +16,7 @@
|
|||
"watch": "gulp watch-extension:jake"
|
||||
},
|
||||
"dependencies": {
|
||||
"vscode-nls": "^3.2.1"
|
||||
"vscode-nls": "^3.2.4"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/node": "7.0.43"
|
||||
|
|
|
@ -6,6 +6,6 @@
|
|||
version "7.0.43"
|
||||
resolved "https://registry.yarnpkg.com/@types/node/-/node-7.0.43.tgz#a187e08495a075f200ca946079c914e1a5fe962c"
|
||||
|
||||
vscode-nls@^3.2.1:
|
||||
version "3.2.1"
|
||||
resolved "https://registry.yarnpkg.com/vscode-nls/-/vscode-nls-3.2.1.tgz#b1f3e04e8a94a715d5a7bcbc8339c51e6d74ca51"
|
||||
vscode-nls@^3.2.4:
|
||||
version "3.2.4"
|
||||
resolved "https://registry.yarnpkg.com/vscode-nls/-/vscode-nls-3.2.4.tgz#2166b4183c8aea884d20727f5449e62be69fd398"
|
||||
|
|
|
@ -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/7bf8960f7042474b10b519f39339fc527907ce16",
|
||||
"version": "https://github.com/Microsoft/TypeScript-TmLanguage/commit/88217b1c7d36ed5d35adc3099ba7978aabe2531b",
|
||||
"name": "JavaScript (with React support)",
|
||||
"scopeName": "source.js",
|
||||
"patterns": [
|
||||
|
@ -4115,7 +4115,7 @@
|
|||
},
|
||||
"directives": {
|
||||
"name": "comment.line.triple-slash.directive.js",
|
||||
"begin": "^(///)\\s*(?=<(reference|amd-dependency|amd-module)(\\s+(path|types|no-default-lib|name)\\s*=\\s*((\\'([^\\'\\\\]|\\\\\\'|\\\\)*\\')|(\\\"([^\\\"\\\\]|\\\\\\\"|\\\\)*\\\")))+\\s*/>\\s*$)",
|
||||
"begin": "^(///)\\s*(?=<(reference|amd-dependency|amd-module)(\\s+(path|types|no-default-lib|lib|name)\\s*=\\s*((\\'([^\\'\\\\]|\\\\\\'|\\\\)*\\')|(\\\"([^\\\"\\\\]|\\\\\\\"|\\\\)*\\\")))+\\s*/>\\s*$)",
|
||||
"beginCaptures": {
|
||||
"1": {
|
||||
"name": "punctuation.definition.comment.js"
|
||||
|
@ -4143,7 +4143,7 @@
|
|||
"patterns": [
|
||||
{
|
||||
"name": "entity.other.attribute-name.directive.js",
|
||||
"match": "path|types|no-default-lib|name"
|
||||
"match": "path|types|no-default-lib|lib|name"
|
||||
},
|
||||
{
|
||||
"name": "keyword.operator.assignment.js",
|
||||
|
@ -4664,8 +4664,8 @@
|
|||
]
|
||||
},
|
||||
"jsx-tag-in-expression": {
|
||||
"begin": "(?x)\n (?<!\\+\\+|--)(?<=[({\\[,?=>:*]|&&|\\|\\||\\?|^return|[^\\._$[:alnum:]]return|^default|[^\\._$[:alnum:]]default|^)\\s*\n (?!<\\s*[_$[:alpha:]][_$[:alnum:]]*((\\s+extends\\s+[^=>])|,)) # look ahead is not type parameter of arrow\n (?=(<)\\s*(?:([_$a-zA-Z][-$\\w.]*)(?<!\\.|-)(:))?((?:[a-z][a-z0-9]*|([_$a-zA-Z][-$\\w.]*))(?<!\\.|-))(?=((<\\s*(((keyof|infer)\\s+)|(([_$[:alpha:]][_$[:alnum:]]*|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\])|(\\'[^\\']*\\')|(\\\"[^\\\"]*\\\")|(\\`[^\\`]*\\`))(?=\\s*([\\<\\>\\,\\.\\[=]|&(?!&)|\\|(?!\\|)))))([^<>\\(]|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(?<==)\\>|\\<\\s*(((keyof|infer)\\s+)|(([_$[:alpha:]][_$[:alnum:]]*|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\])|(\\'[^\\']*\\')|(\\\"[^\\\"]*\\\")|(\\`[^\\`]*\\`))(?=\\s*([\\<\\>\\,\\.\\[=]|&(?!&)|\\|(?!\\|)))))([^<>\\(]|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(?<==)\\>)*(?!=)\\>)*(?!=)>\\s*)|(\\s+))(?!\\?)|\\/?>))",
|
||||
"end": "(?!(<)\\s*(?:([_$a-zA-Z][-$\\w.]*)(?<!\\.|-)(:))?((?:[a-z][a-z0-9]*|([_$a-zA-Z][-$\\w.]*))(?<!\\.|-))(?=((<\\s*(((keyof|infer)\\s+)|(([_$[:alpha:]][_$[:alnum:]]*|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\])|(\\'[^\\']*\\')|(\\\"[^\\\"]*\\\")|(\\`[^\\`]*\\`))(?=\\s*([\\<\\>\\,\\.\\[=]|&(?!&)|\\|(?!\\|)))))([^<>\\(]|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(?<==)\\>|\\<\\s*(((keyof|infer)\\s+)|(([_$[:alpha:]][_$[:alnum:]]*|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\])|(\\'[^\\']*\\')|(\\\"[^\\\"]*\\\")|(\\`[^\\`]*\\`))(?=\\s*([\\<\\>\\,\\.\\[=]|&(?!&)|\\|(?!\\|)))))([^<>\\(]|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(?<==)\\>)*(?!=)\\>)*(?!=)>\\s*)|(\\s+))(?!\\?)|\\/?>))",
|
||||
"begin": "(?x)\n (?<!\\+\\+|--)(?<=[({\\[,?=>:*]|&&|\\|\\||\\?|^return|[^\\._$[:alnum:]]return|^default|[^\\._$[:alnum:]]default|^)\\s*\n (?!<\\s*[_$[:alpha:]][_$[:alnum:]]*((\\s+extends\\s+[^=>])|,)) # look ahead is not type parameter of arrow\n (?=(<)\\s*(?:([_$a-zA-Z][-$\\w.]*)(?<!\\.|-)(:))?((?:[a-z][a-z0-9]*|([_$a-zA-Z][-$\\w.]*))(?<!\\.|-))(?=((<\\s*)|(\\s+))(?!\\?)|\\/?>))",
|
||||
"end": "(?!(<)\\s*(?:([_$a-zA-Z][-$\\w.]*)(?<!\\.|-)(:))?((?:[a-z][a-z0-9]*|([_$a-zA-Z][-$\\w.]*))(?<!\\.|-))(?=((<\\s*)|(\\s+))(?!\\?)|\\/?>))",
|
||||
"patterns": [
|
||||
{
|
||||
"include": "#jsx-tag"
|
||||
|
@ -4674,7 +4674,7 @@
|
|||
},
|
||||
"jsx-tag": {
|
||||
"name": "meta.tag.js",
|
||||
"begin": "(?=(<)\\s*(?:([_$a-zA-Z][-$\\w.]*)(?<!\\.|-)(:))?((?:[a-z][a-z0-9]*|([_$a-zA-Z][-$\\w.]*))(?<!\\.|-))(?=((<\\s*(((keyof|infer)\\s+)|(([_$[:alpha:]][_$[:alnum:]]*|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\])|(\\'[^\\']*\\')|(\\\"[^\\\"]*\\\")|(\\`[^\\`]*\\`))(?=\\s*([\\<\\>\\,\\.\\[=]|&(?!&)|\\|(?!\\|)))))([^<>\\(]|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(?<==)\\>|\\<\\s*(((keyof|infer)\\s+)|(([_$[:alpha:]][_$[:alnum:]]*|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\])|(\\'[^\\']*\\')|(\\\"[^\\\"]*\\\")|(\\`[^\\`]*\\`))(?=\\s*([\\<\\>\\,\\.\\[=]|&(?!&)|\\|(?!\\|)))))([^<>\\(]|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(?<==)\\>)*(?!=)\\>)*(?!=)>\\s*)|(\\s+))(?!\\?)|\\/?>))",
|
||||
"begin": "(?=(<)\\s*(?:([_$a-zA-Z][-$\\w.]*)(?<!\\.|-)(:))?((?:[a-z][a-z0-9]*|([_$a-zA-Z][-$\\w.]*))(?<!\\.|-))(?=((<\\s*)|(\\s+))(?!\\?)|\\/?>))",
|
||||
"end": "(/>)|(?:(</)\\s*(?:([_$a-zA-Z][-$\\w.]*)(?<!\\.|-)(:))?((?:[a-z][a-z0-9]*|([_$a-zA-Z][-$\\w.]*))(?<!\\.|-))?\\s*(>))",
|
||||
"endCaptures": {
|
||||
"1": {
|
||||
|
@ -4701,7 +4701,7 @@
|
|||
},
|
||||
"patterns": [
|
||||
{
|
||||
"begin": "(<)\\s*(?:([_$a-zA-Z][-$\\w.]*)(?<!\\.|-)(:))?((?:[a-z][a-z0-9]*|([_$a-zA-Z][-$\\w.]*))(?<!\\.|-))(?=((<\\s*(((keyof|infer)\\s+)|(([_$[:alpha:]][_$[:alnum:]]*|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\])|(\\'[^\\']*\\')|(\\\"[^\\\"]*\\\")|(\\`[^\\`]*\\`))(?=\\s*([\\<\\>\\,\\.\\[=]|&(?!&)|\\|(?!\\|)))))([^<>\\(]|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(?<==)\\>|\\<\\s*(((keyof|infer)\\s+)|(([_$[:alpha:]][_$[:alnum:]]*|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\])|(\\'[^\\']*\\')|(\\\"[^\\\"]*\\\")|(\\`[^\\`]*\\`))(?=\\s*([\\<\\>\\,\\.\\[=]|&(?!&)|\\|(?!\\|)))))([^<>\\(]|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(?<==)\\>)*(?!=)\\>)*(?!=)>\\s*)|(\\s+))(?!\\?)|\\/?>)",
|
||||
"begin": "(<)\\s*(?:([_$a-zA-Z][-$\\w.]*)(?<!\\.|-)(:))?((?:[a-z][a-z0-9]*|([_$a-zA-Z][-$\\w.]*))(?<!\\.|-))(?=((<\\s*)|(\\s+))(?!\\?)|\\/?>)",
|
||||
"beginCaptures": {
|
||||
"1": {
|
||||
"name": "punctuation.definition.tag.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/7bf8960f7042474b10b519f39339fc527907ce16",
|
||||
"version": "https://github.com/Microsoft/TypeScript-TmLanguage/commit/88217b1c7d36ed5d35adc3099ba7978aabe2531b",
|
||||
"name": "JavaScript (with React support)",
|
||||
"scopeName": "source.js.jsx",
|
||||
"patterns": [
|
||||
|
@ -4115,7 +4115,7 @@
|
|||
},
|
||||
"directives": {
|
||||
"name": "comment.line.triple-slash.directive.js.jsx",
|
||||
"begin": "^(///)\\s*(?=<(reference|amd-dependency|amd-module)(\\s+(path|types|no-default-lib|name)\\s*=\\s*((\\'([^\\'\\\\]|\\\\\\'|\\\\)*\\')|(\\\"([^\\\"\\\\]|\\\\\\\"|\\\\)*\\\")))+\\s*/>\\s*$)",
|
||||
"begin": "^(///)\\s*(?=<(reference|amd-dependency|amd-module)(\\s+(path|types|no-default-lib|lib|name)\\s*=\\s*((\\'([^\\'\\\\]|\\\\\\'|\\\\)*\\')|(\\\"([^\\\"\\\\]|\\\\\\\"|\\\\)*\\\")))+\\s*/>\\s*$)",
|
||||
"beginCaptures": {
|
||||
"1": {
|
||||
"name": "punctuation.definition.comment.js.jsx"
|
||||
|
@ -4143,7 +4143,7 @@
|
|||
"patterns": [
|
||||
{
|
||||
"name": "entity.other.attribute-name.directive.js.jsx",
|
||||
"match": "path|types|no-default-lib|name"
|
||||
"match": "path|types|no-default-lib|lib|name"
|
||||
},
|
||||
{
|
||||
"name": "keyword.operator.assignment.js.jsx",
|
||||
|
@ -4664,8 +4664,8 @@
|
|||
]
|
||||
},
|
||||
"jsx-tag-in-expression": {
|
||||
"begin": "(?x)\n (?<!\\+\\+|--)(?<=[({\\[,?=>:*]|&&|\\|\\||\\?|^return|[^\\._$[:alnum:]]return|^default|[^\\._$[:alnum:]]default|^)\\s*\n (?!<\\s*[_$[:alpha:]][_$[:alnum:]]*((\\s+extends\\s+[^=>])|,)) # look ahead is not type parameter of arrow\n (?=(<)\\s*(?:([_$a-zA-Z][-$\\w.]*)(?<!\\.|-)(:))?((?:[a-z][a-z0-9]*|([_$a-zA-Z][-$\\w.]*))(?<!\\.|-))(?=((<\\s*(((keyof|infer)\\s+)|(([_$[:alpha:]][_$[:alnum:]]*|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\])|(\\'[^\\']*\\')|(\\\"[^\\\"]*\\\")|(\\`[^\\`]*\\`))(?=\\s*([\\<\\>\\,\\.\\[=]|&(?!&)|\\|(?!\\|)))))([^<>\\(]|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(?<==)\\>|\\<\\s*(((keyof|infer)\\s+)|(([_$[:alpha:]][_$[:alnum:]]*|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\])|(\\'[^\\']*\\')|(\\\"[^\\\"]*\\\")|(\\`[^\\`]*\\`))(?=\\s*([\\<\\>\\,\\.\\[=]|&(?!&)|\\|(?!\\|)))))([^<>\\(]|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(?<==)\\>)*(?!=)\\>)*(?!=)>\\s*)|(\\s+))(?!\\?)|\\/?>))",
|
||||
"end": "(?!(<)\\s*(?:([_$a-zA-Z][-$\\w.]*)(?<!\\.|-)(:))?((?:[a-z][a-z0-9]*|([_$a-zA-Z][-$\\w.]*))(?<!\\.|-))(?=((<\\s*(((keyof|infer)\\s+)|(([_$[:alpha:]][_$[:alnum:]]*|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\])|(\\'[^\\']*\\')|(\\\"[^\\\"]*\\\")|(\\`[^\\`]*\\`))(?=\\s*([\\<\\>\\,\\.\\[=]|&(?!&)|\\|(?!\\|)))))([^<>\\(]|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(?<==)\\>|\\<\\s*(((keyof|infer)\\s+)|(([_$[:alpha:]][_$[:alnum:]]*|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\])|(\\'[^\\']*\\')|(\\\"[^\\\"]*\\\")|(\\`[^\\`]*\\`))(?=\\s*([\\<\\>\\,\\.\\[=]|&(?!&)|\\|(?!\\|)))))([^<>\\(]|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(?<==)\\>)*(?!=)\\>)*(?!=)>\\s*)|(\\s+))(?!\\?)|\\/?>))",
|
||||
"begin": "(?x)\n (?<!\\+\\+|--)(?<=[({\\[,?=>:*]|&&|\\|\\||\\?|^return|[^\\._$[:alnum:]]return|^default|[^\\._$[:alnum:]]default|^)\\s*\n (?!<\\s*[_$[:alpha:]][_$[:alnum:]]*((\\s+extends\\s+[^=>])|,)) # look ahead is not type parameter of arrow\n (?=(<)\\s*(?:([_$a-zA-Z][-$\\w.]*)(?<!\\.|-)(:))?((?:[a-z][a-z0-9]*|([_$a-zA-Z][-$\\w.]*))(?<!\\.|-))(?=((<\\s*)|(\\s+))(?!\\?)|\\/?>))",
|
||||
"end": "(?!(<)\\s*(?:([_$a-zA-Z][-$\\w.]*)(?<!\\.|-)(:))?((?:[a-z][a-z0-9]*|([_$a-zA-Z][-$\\w.]*))(?<!\\.|-))(?=((<\\s*)|(\\s+))(?!\\?)|\\/?>))",
|
||||
"patterns": [
|
||||
{
|
||||
"include": "#jsx-tag"
|
||||
|
@ -4674,7 +4674,7 @@
|
|||
},
|
||||
"jsx-tag": {
|
||||
"name": "meta.tag.js.jsx",
|
||||
"begin": "(?=(<)\\s*(?:([_$a-zA-Z][-$\\w.]*)(?<!\\.|-)(:))?((?:[a-z][a-z0-9]*|([_$a-zA-Z][-$\\w.]*))(?<!\\.|-))(?=((<\\s*(((keyof|infer)\\s+)|(([_$[:alpha:]][_$[:alnum:]]*|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\])|(\\'[^\\']*\\')|(\\\"[^\\\"]*\\\")|(\\`[^\\`]*\\`))(?=\\s*([\\<\\>\\,\\.\\[=]|&(?!&)|\\|(?!\\|)))))([^<>\\(]|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(?<==)\\>|\\<\\s*(((keyof|infer)\\s+)|(([_$[:alpha:]][_$[:alnum:]]*|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\])|(\\'[^\\']*\\')|(\\\"[^\\\"]*\\\")|(\\`[^\\`]*\\`))(?=\\s*([\\<\\>\\,\\.\\[=]|&(?!&)|\\|(?!\\|)))))([^<>\\(]|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(?<==)\\>)*(?!=)\\>)*(?!=)>\\s*)|(\\s+))(?!\\?)|\\/?>))",
|
||||
"begin": "(?=(<)\\s*(?:([_$a-zA-Z][-$\\w.]*)(?<!\\.|-)(:))?((?:[a-z][a-z0-9]*|([_$a-zA-Z][-$\\w.]*))(?<!\\.|-))(?=((<\\s*)|(\\s+))(?!\\?)|\\/?>))",
|
||||
"end": "(/>)|(?:(</)\\s*(?:([_$a-zA-Z][-$\\w.]*)(?<!\\.|-)(:))?((?:[a-z][a-z0-9]*|([_$a-zA-Z][-$\\w.]*))(?<!\\.|-))?\\s*(>))",
|
||||
"endCaptures": {
|
||||
"1": {
|
||||
|
@ -4701,7 +4701,7 @@
|
|||
},
|
||||
"patterns": [
|
||||
{
|
||||
"begin": "(<)\\s*(?:([_$a-zA-Z][-$\\w.]*)(?<!\\.|-)(:))?((?:[a-z][a-z0-9]*|([_$a-zA-Z][-$\\w.]*))(?<!\\.|-))(?=((<\\s*(((keyof|infer)\\s+)|(([_$[:alpha:]][_$[:alnum:]]*|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\])|(\\'[^\\']*\\')|(\\\"[^\\\"]*\\\")|(\\`[^\\`]*\\`))(?=\\s*([\\<\\>\\,\\.\\[=]|&(?!&)|\\|(?!\\|)))))([^<>\\(]|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(?<==)\\>|\\<\\s*(((keyof|infer)\\s+)|(([_$[:alpha:]][_$[:alnum:]]*|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\])|(\\'[^\\']*\\')|(\\\"[^\\\"]*\\\")|(\\`[^\\`]*\\`))(?=\\s*([\\<\\>\\,\\.\\[=]|&(?!&)|\\|(?!\\|)))))([^<>\\(]|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(?<==)\\>)*(?!=)\\>)*(?!=)>\\s*)|(\\s+))(?!\\?)|\\/?>)",
|
||||
"begin": "(<)\\s*(?:([_$a-zA-Z][-$\\w.]*)(?<!\\.|-)(:))?((?:[a-z][a-z0-9]*|([_$a-zA-Z][-$\\w.]*))(?<!\\.|-))(?=((<\\s*)|(\\s+))(?!\\?)|\\/?>)",
|
||||
"beginCaptures": {
|
||||
"1": {
|
||||
"name": "punctuation.definition.tag.begin.js.jsx"
|
||||
|
|
|
@ -103,7 +103,7 @@
|
|||
"vscode-extension-telemetry": "0.0.17",
|
||||
"vscode-languageclient": "^4.1.4",
|
||||
"vscode-languageserver-protocol-foldingprovider": "^2.0.1",
|
||||
"vscode-nls": "^3.2.2"
|
||||
"vscode-nls": "^3.2.4"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/node": "7.0.43"
|
||||
|
|
|
@ -16,7 +16,7 @@
|
|||
"vscode-json-languageservice": "^3.1.2",
|
||||
"vscode-languageserver": "^4.1.3",
|
||||
"vscode-languageserver-protocol-foldingprovider": "^2.0.1",
|
||||
"vscode-nls": "^3.2.2",
|
||||
"vscode-nls": "^3.2.4",
|
||||
"vscode-uri": "^1.0.3"
|
||||
},
|
||||
"devDependencies": {
|
||||
|
|
|
@ -118,6 +118,10 @@ vscode-nls@^3.2.2:
|
|||
version "3.2.2"
|
||||
resolved "https://registry.yarnpkg.com/vscode-nls/-/vscode-nls-3.2.2.tgz#3817eca5b985c2393de325197cf4e15eb2aa5350"
|
||||
|
||||
vscode-nls@^3.2.4:
|
||||
version "3.2.4"
|
||||
resolved "https://registry.yarnpkg.com/vscode-nls/-/vscode-nls-3.2.4.tgz#2166b4183c8aea884d20727f5449e62be69fd398"
|
||||
|
||||
vscode-uri@^1.0.1:
|
||||
version "1.0.1"
|
||||
resolved "https://registry.yarnpkg.com/vscode-uri/-/vscode-uri-1.0.1.tgz#11a86befeac3c4aa3ec08623651a3c81a6d0bbc8"
|
||||
|
|
|
@ -62,9 +62,9 @@ vscode-languageserver-types@^3.7.2:
|
|||
version "3.7.2"
|
||||
resolved "https://registry.yarnpkg.com/vscode-languageserver-types/-/vscode-languageserver-types-3.7.2.tgz#aad8846f8e3e27962648554de5a8417e358f34eb"
|
||||
|
||||
vscode-nls@^3.2.2:
|
||||
version "3.2.2"
|
||||
resolved "https://registry.yarnpkg.com/vscode-nls/-/vscode-nls-3.2.2.tgz#3817eca5b985c2393de325197cf4e15eb2aa5350"
|
||||
vscode-nls@^3.2.4:
|
||||
version "3.2.4"
|
||||
resolved "https://registry.yarnpkg.com/vscode-nls/-/vscode-nls-3.2.4.tgz#2166b4183c8aea884d20727f5449e62be69fd398"
|
||||
|
||||
zone.js@0.7.6:
|
||||
version "0.7.6"
|
||||
|
|
|
@ -296,7 +296,7 @@
|
|||
"markdown-it": "^8.4.1",
|
||||
"markdown-it-named-headers": "0.0.4",
|
||||
"vscode-extension-telemetry": "0.0.17",
|
||||
"vscode-nls": "^3.2.1"
|
||||
"vscode-nls": "^3.2.4"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/highlight.js": "9.1.10",
|
||||
|
|
|
@ -5462,9 +5462,9 @@ vscode-extension-telemetry@0.0.17:
|
|||
dependencies:
|
||||
applicationinsights "1.0.1"
|
||||
|
||||
vscode-nls@^3.2.1:
|
||||
version "3.2.1"
|
||||
resolved "https://registry.yarnpkg.com/vscode-nls/-/vscode-nls-3.2.1.tgz#b1f3e04e8a94a715d5a7bcbc8339c51e6d74ca51"
|
||||
vscode-nls@^3.2.4:
|
||||
version "3.2.4"
|
||||
resolved "https://registry.yarnpkg.com/vscode-nls/-/vscode-nls-3.2.4.tgz#2166b4183c8aea884d20727f5449e62be69fd398"
|
||||
|
||||
vscode@^1.1.10:
|
||||
version "1.1.10"
|
||||
|
|
|
@ -100,7 +100,7 @@
|
|||
}
|
||||
},
|
||||
"dependencies": {
|
||||
"vscode-nls": "^3.2.1"
|
||||
"vscode-nls": "^3.2.4"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/node": "8.0.33"
|
||||
|
|
|
@ -6,6 +6,6 @@
|
|||
version "8.0.33"
|
||||
resolved "https://registry.yarnpkg.com/@types/node/-/node-8.0.33.tgz#1126e94374014e54478092830704f6ea89df04cd"
|
||||
|
||||
vscode-nls@^3.2.1:
|
||||
version "3.2.1"
|
||||
resolved "https://registry.yarnpkg.com/vscode-nls/-/vscode-nls-3.2.1.tgz#b1f3e04e8a94a715d5a7bcbc8339c51e6d74ca51"
|
||||
vscode-nls@^3.2.4:
|
||||
version "3.2.4"
|
||||
resolved "https://registry.yarnpkg.com/vscode-nls/-/vscode-nls-3.2.4.tgz#2166b4183c8aea884d20727f5449e62be69fd398"
|
||||
|
|
|
@ -20,7 +20,7 @@
|
|||
"jsonc-parser": "^1.0.0",
|
||||
"minimatch": "^3.0.4",
|
||||
"request-light": "^0.2.2",
|
||||
"vscode-nls": "^3.2.1"
|
||||
"vscode-nls": "^3.2.4"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/minimatch": "^3.0.3",
|
||||
|
|
|
@ -164,10 +164,14 @@ export class NpmScriptsTreeDataProvider implements TreeDataProvider<TreeItem> {
|
|||
private extractDebugArg(scripts: any, task: Task): [string, number] | undefined {
|
||||
let script: string = scripts[task.name];
|
||||
|
||||
let match = script.match(/--(inspect|debug)(-brk)?(=(\d*))?/);
|
||||
// matches --debug, --debug=1234, --debug-brk, debug-brk=1234, --inspect,
|
||||
// --inspect=1234, --inspect-brk, --inspect-brk=1234,
|
||||
// --inspect=localhost:1245, --inspect=127.0.0.1:1234, --inspect=[aa:1:0:0:0]:1234, --inspect=:1234
|
||||
let match = script.match(/--(inspect|debug)(-brk)?(=((\[[0-9a-fA-F:]*\]|[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+|[a-zA-Z0-9\.]*):)?(\d+))?/);
|
||||
|
||||
if (match) {
|
||||
if (match[4]) {
|
||||
return [match[1], parseInt(match[4])];
|
||||
if (match[6]) {
|
||||
return [match[1], parseInt(match[6])];
|
||||
}
|
||||
if (match[1] === 'inspect') {
|
||||
return [match[1], 9229];
|
||||
|
|
|
@ -93,6 +93,6 @@ vscode-nls@^2.0.2:
|
|||
version "2.0.2"
|
||||
resolved "https://registry.yarnpkg.com/vscode-nls/-/vscode-nls-2.0.2.tgz#808522380844b8ad153499af5c3b03921aea02da"
|
||||
|
||||
vscode-nls@^3.2.1:
|
||||
version "3.2.1"
|
||||
resolved "https://registry.yarnpkg.com/vscode-nls/-/vscode-nls-3.2.1.tgz#b1f3e04e8a94a715d5a7bcbc8339c51e6d74ca51"
|
||||
vscode-nls@^3.2.4:
|
||||
version "3.2.4"
|
||||
resolved "https://registry.yarnpkg.com/vscode-nls/-/vscode-nls-3.2.4.tgz#2166b4183c8aea884d20727f5449e62be69fd398"
|
||||
|
|
|
@ -77,7 +77,7 @@
|
|||
"watch": "gulp watch-extension:php"
|
||||
},
|
||||
"dependencies": {
|
||||
"vscode-nls": "^3.2.1"
|
||||
"vscode-nls": "^3.2.4"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/node": "7.0.43"
|
||||
|
|
|
@ -6,6 +6,6 @@
|
|||
version "7.0.43"
|
||||
resolved "https://registry.yarnpkg.com/@types/node/-/node-7.0.43.tgz#a187e08495a075f200ca946079c914e1a5fe962c"
|
||||
|
||||
vscode-nls@^3.2.1:
|
||||
version "3.2.1"
|
||||
resolved "https://registry.yarnpkg.com/vscode-nls/-/vscode-nls-3.2.1.tgz#b1f3e04e8a94a715d5a7bcbc8339c51e6d74ca51"
|
||||
vscode-nls@^3.2.4:
|
||||
version "3.2.4"
|
||||
resolved "https://registry.yarnpkg.com/vscode-nls/-/vscode-nls-3.2.4.tgz#2166b4183c8aea884d20727f5449e62be69fd398"
|
||||
|
|
|
@ -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/PowerShell/EditorSyntax/commit/6f5438611c54922ea94c81532a2dcfee72190039",
|
||||
"version": "https://github.com/PowerShell/EditorSyntax/commit/146e421358945dbfbd24a9dcf56d759bdb0693db",
|
||||
"name": "PowerShell",
|
||||
"scopeName": "source.powershell",
|
||||
"patterns": [
|
||||
|
@ -71,7 +71,17 @@
|
|||
},
|
||||
{
|
||||
"begin": "(?<!')'",
|
||||
"beginCaptures": {
|
||||
"0": {
|
||||
"name": "punctuation.definition.string.begin.powershell"
|
||||
}
|
||||
},
|
||||
"end": "'(?!')",
|
||||
"endCaptures": {
|
||||
"0": {
|
||||
"name": "punctuation.definition.string.end.powershell"
|
||||
}
|
||||
},
|
||||
"name": "string.quoted.single.powershell",
|
||||
"patterns": [
|
||||
{
|
||||
|
@ -137,7 +147,7 @@
|
|||
"begin": "(\\$)(\\()",
|
||||
"beginCaptures": {
|
||||
"1": {
|
||||
"name": "keyword.other.variable.definition.powershell"
|
||||
"name": "punctuation.definition.variable.powershell"
|
||||
},
|
||||
"2": {
|
||||
"name": "punctuation.section.group.begin.powershell"
|
||||
|
@ -170,8 +180,20 @@
|
|||
"name": "keyword.control.powershell"
|
||||
},
|
||||
{
|
||||
"match": "(?<!\\w)(--%)(?!\\w)",
|
||||
"name": "keyword.control.powershell"
|
||||
"begin": "(?<!\\w)(--%)(?!\\w)",
|
||||
"beginCaptures": {
|
||||
"1": {
|
||||
"name": "keyword.control.powershell"
|
||||
}
|
||||
},
|
||||
"end": "$",
|
||||
"patterns": [
|
||||
{
|
||||
"match": ".+",
|
||||
"name": "string.unquoted.powershell"
|
||||
}
|
||||
],
|
||||
"comment": "This should be moved to the repository at some point."
|
||||
},
|
||||
{
|
||||
"comment": "This should only be relevant inside a class but will require a rework of how classes are matched. This is a temp fix.",
|
||||
|
@ -220,7 +242,7 @@
|
|||
},
|
||||
{
|
||||
"match": "\\|{2}|&{2}|;",
|
||||
"name": "keyword.other.statement-separator.powershell"
|
||||
"name": "punctuation.terminator.statement.powershell"
|
||||
},
|
||||
{
|
||||
"match": "&|(?<!\\w)\\.(?= )|`|,|\\|",
|
||||
|
@ -326,7 +348,17 @@
|
|||
},
|
||||
{
|
||||
"begin": "(?<!')'",
|
||||
"beginCaptures": {
|
||||
"0": {
|
||||
"name": "punctuation.definition.string.begin.powershell"
|
||||
}
|
||||
},
|
||||
"end": "'(?!')",
|
||||
"endCaptures": {
|
||||
"0": {
|
||||
"name": "punctuation.definition.string.end.powershell"
|
||||
}
|
||||
},
|
||||
"name": "string.quoted.single.powershell",
|
||||
"patterns": [
|
||||
{
|
||||
|
@ -379,7 +411,7 @@
|
|||
"name": "keyword.operator.documentation.powershell"
|
||||
}
|
||||
},
|
||||
"match": "(?i:\\s*(\\.)(COMPONENT|DESCRIPTION|EXAMPLE|EXTERNALHELP|FORWARDHELPCATEGORY|FORWARDHELPTARGETNAME|FUNCTIONALITY|INPUTS|LINK|NOTES|OUTPUTS|REMOTEHELPRUNSPACE|ROLE|SYNOPSIS))",
|
||||
"match": "^(?i:(?:\\s*|#)+(\\.)(COMPONENT|DESCRIPTION|EXAMPLE|EXTERNALHELP|FORWARDHELPCATEGORY|FORWARDHELPTARGETNAME|FUNCTIONALITY|INPUTS|LINK|NOTES|OUTPUTS|REMOTEHELPRUNSPACE|ROLE|SYNOPSIS))",
|
||||
"name": "comment.documentation.embedded.powershell"
|
||||
},
|
||||
{
|
||||
|
@ -464,7 +496,7 @@
|
|||
"begin": "(\\$)(\\()",
|
||||
"beginCaptures": {
|
||||
"1": {
|
||||
"name": "keyword.other.variable.definition.powershell"
|
||||
"name": "punctuation.definition.variable.powershell"
|
||||
},
|
||||
"2": {
|
||||
"name": "punctuation.section.group.begin.powershell"
|
||||
|
@ -617,11 +649,11 @@
|
|||
"patterns": [
|
||||
{
|
||||
"captures": {
|
||||
"1": {
|
||||
"name": "keyword.other.variable.definition.powershell"
|
||||
},
|
||||
"2": {
|
||||
"0": {
|
||||
"name": "constant.language.powershell"
|
||||
},
|
||||
"1": {
|
||||
"name": "punctuation.definition.variable.powershell"
|
||||
}
|
||||
},
|
||||
"comment": "These are special constants.",
|
||||
|
@ -629,14 +661,14 @@
|
|||
},
|
||||
{
|
||||
"captures": {
|
||||
"1": {
|
||||
"name": "keyword.other.variable.definition.powershell"
|
||||
},
|
||||
"2": {
|
||||
"0": {
|
||||
"name": "support.constant.variable.powershell"
|
||||
},
|
||||
"1": {
|
||||
"name": "punctuation.definition.variable.powershell"
|
||||
},
|
||||
"3": {
|
||||
"name": "entity.name.function.invocation.powershell"
|
||||
"name": "variable.other.member.powershell"
|
||||
}
|
||||
},
|
||||
"comment": "These are the other built-in constants.",
|
||||
|
@ -644,14 +676,14 @@
|
|||
},
|
||||
{
|
||||
"captures": {
|
||||
"1": {
|
||||
"name": "keyword.other.variable.definition.powershell"
|
||||
},
|
||||
"2": {
|
||||
"0": {
|
||||
"name": "support.constant.automatic.powershell"
|
||||
},
|
||||
"1": {
|
||||
"name": "punctuation.definition.variable.powershell"
|
||||
},
|
||||
"3": {
|
||||
"name": "entity.name.function.invocation.powershell"
|
||||
"name": "variable.other.member.powershell"
|
||||
}
|
||||
},
|
||||
"comment": "Automatic variables are not constants, but they are read-only. In monokai (default) color schema support.variable doesn't have color, so we use constant.",
|
||||
|
@ -659,14 +691,14 @@
|
|||
},
|
||||
{
|
||||
"captures": {
|
||||
"1": {
|
||||
"name": "keyword.other.variable.definition.powershell"
|
||||
},
|
||||
"2": {
|
||||
"0": {
|
||||
"name": "variable.language.powershell"
|
||||
},
|
||||
"1": {
|
||||
"name": "punctuation.definition.variable.powershell"
|
||||
},
|
||||
"3": {
|
||||
"name": "entity.name.function.invocation.powershell"
|
||||
"name": "variable.other.member.powershell"
|
||||
}
|
||||
},
|
||||
"comment": "Style preference variables as language variables so that they stand out.",
|
||||
|
@ -674,25 +706,28 @@
|
|||
},
|
||||
{
|
||||
"captures": {
|
||||
"0": {
|
||||
"name": "variable.other.readwrite.powershell"
|
||||
},
|
||||
"1": {
|
||||
"name": "keyword.other.variable.definition.powershell"
|
||||
"name": "punctuation.definition.variable.powershell"
|
||||
},
|
||||
"2": {
|
||||
"name": "storage.modifier.scope.powershell"
|
||||
},
|
||||
"3": {
|
||||
"name": "variable.other.readwrite.powershell"
|
||||
},
|
||||
"4": {
|
||||
"name": "entity.name.function.invocation.powershell"
|
||||
"name": "variable.other.member.powershell"
|
||||
}
|
||||
},
|
||||
"match": "(?i:(\\$|@)(global|local|private|script|using|workflow):((?:\\p{L}|\\d|_)+))((?:\\.(?:\\p{L}|\\d|_)+)*\\b)?"
|
||||
},
|
||||
{
|
||||
"captures": {
|
||||
"0": {
|
||||
"name": "variable.other.readwrite.powershell"
|
||||
},
|
||||
"1": {
|
||||
"name": "keyword.other.variable.definition.powershell"
|
||||
"name": "punctuation.definition.variable.powershell"
|
||||
},
|
||||
"2": {
|
||||
"name": "punctuation.section.braces.begin.powershell"
|
||||
|
@ -700,39 +735,39 @@
|
|||
"3": {
|
||||
"name": "storage.modifier.scope.powershell"
|
||||
},
|
||||
"4": {
|
||||
"name": "variable.other.readwrite.powershell"
|
||||
},
|
||||
"5": {
|
||||
"name": "punctuation.section.braces.end.powershell"
|
||||
},
|
||||
"6": {
|
||||
"name": "entity.name.function.invocation.powershell"
|
||||
"name": "variable.other.member.powershell"
|
||||
}
|
||||
},
|
||||
"match": "(?i:(\\$)(\\{)(global|local|private|script|using|workflow):([^}]*[^}`])(\\}))((?:\\.(?:\\p{L}|\\d|_)+)*\\b)?"
|
||||
},
|
||||
{
|
||||
"captures": {
|
||||
"0": {
|
||||
"name": "variable.other.readwrite.powershell"
|
||||
},
|
||||
"1": {
|
||||
"name": "keyword.other.variable.definition.powershell"
|
||||
"name": "punctuation.definition.variable.powershell"
|
||||
},
|
||||
"2": {
|
||||
"name": "support.variable.drive.powershell"
|
||||
},
|
||||
"3": {
|
||||
"name": "variable.other.readwrite.powershell"
|
||||
},
|
||||
"4": {
|
||||
"name": "entity.name.function.invocation.powershell"
|
||||
"name": "variable.other.member.powershell"
|
||||
}
|
||||
},
|
||||
"match": "(?i:(\\$|@)((?:\\p{L}|\\d|_)+:)?((?:\\p{L}|\\d|_)+))((?:\\.(?:\\p{L}|\\d|_)+)*\\b)?"
|
||||
},
|
||||
{
|
||||
"captures": {
|
||||
"0": {
|
||||
"name": "variable.other.readwrite.powershell"
|
||||
},
|
||||
"1": {
|
||||
"name": "keyword.other.variable.definition.powershell"
|
||||
"name": "punctuation.definition.variable.powershell"
|
||||
},
|
||||
"2": {
|
||||
"name": "punctuation.section.braces.begin.powershell"
|
||||
|
@ -740,14 +775,11 @@
|
|||
"3": {
|
||||
"name": "support.variable.drive.powershell"
|
||||
},
|
||||
"4": {
|
||||
"name": "variable.other.readwrite.powershell"
|
||||
},
|
||||
"5": {
|
||||
"name": "punctuation.section.braces.end.powershell"
|
||||
},
|
||||
"6": {
|
||||
"name": "entity.name.function.invocation.powershell"
|
||||
"name": "variable.other.member.powershell"
|
||||
}
|
||||
},
|
||||
"match": "(?i:(\\$)(\\{)((?:\\p{L}|\\d|_)+:)?([^}]*[^}`])(\\}))((?:\\.(?:\\p{L}|\\d|_)+)*\\b)?"
|
||||
|
@ -795,11 +827,11 @@
|
|||
"patterns": [
|
||||
{
|
||||
"captures": {
|
||||
"1": {
|
||||
"name": "keyword.other.variable.definition.powershell"
|
||||
},
|
||||
"2": {
|
||||
"0": {
|
||||
"name": "constant.language.powershell"
|
||||
},
|
||||
"1": {
|
||||
"name": "punctuation.definition.variable.powershell"
|
||||
}
|
||||
},
|
||||
"comment": "These are special constants.",
|
||||
|
@ -807,14 +839,14 @@
|
|||
},
|
||||
{
|
||||
"captures": {
|
||||
"1": {
|
||||
"name": "keyword.other.variable.definition.powershell"
|
||||
},
|
||||
"2": {
|
||||
"0": {
|
||||
"name": "support.constant.variable.powershell"
|
||||
},
|
||||
"1": {
|
||||
"name": "punctuation.definition.variable.powershell"
|
||||
},
|
||||
"3": {
|
||||
"name": "entity.name.function.invocation.powershell"
|
||||
"name": "variable.other.member.powershell"
|
||||
}
|
||||
},
|
||||
"comment": "These are the other built-in constants.",
|
||||
|
@ -822,14 +854,14 @@
|
|||
},
|
||||
{
|
||||
"captures": {
|
||||
"1": {
|
||||
"name": "keyword.other.variable.definition.powershell"
|
||||
},
|
||||
"2": {
|
||||
"0": {
|
||||
"name": "support.variable.automatic.powershell"
|
||||
},
|
||||
"1": {
|
||||
"name": "punctuation.definition.variable.powershell"
|
||||
},
|
||||
"3": {
|
||||
"name": "entity.name.function.invocation.powershell"
|
||||
"name": "variable.other.member.powershell"
|
||||
}
|
||||
},
|
||||
"comment": "Automatic variables are not constants, but they are read-only...",
|
||||
|
@ -837,14 +869,14 @@
|
|||
},
|
||||
{
|
||||
"captures": {
|
||||
"1": {
|
||||
"name": "keyword.other.variable.definition.powershell"
|
||||
},
|
||||
"2": {
|
||||
"0": {
|
||||
"name": "variable.language.powershell"
|
||||
},
|
||||
"1": {
|
||||
"name": "punctuation.definition.variable.powershell"
|
||||
},
|
||||
"3": {
|
||||
"name": "entity.name.function.invocation.powershell"
|
||||
"name": "variable.other.member.powershell"
|
||||
}
|
||||
},
|
||||
"comment": "Style preference variables as language variables so that they stand out.",
|
||||
|
@ -852,62 +884,65 @@
|
|||
},
|
||||
{
|
||||
"captures": {
|
||||
"0": {
|
||||
"name": "variable.other.readwrite.powershell"
|
||||
},
|
||||
"1": {
|
||||
"name": "keyword.other.variable.definition.powershell"
|
||||
"name": "punctuation.definition.variable.powershell"
|
||||
},
|
||||
"2": {
|
||||
"name": "storage.modifier.scope.powershell"
|
||||
},
|
||||
"3": {
|
||||
"name": "variable.other.readwrite.powershell"
|
||||
},
|
||||
"4": {
|
||||
"name": "entity.name.function.invocation.powershell"
|
||||
"name": "variable.other.member.powershell"
|
||||
}
|
||||
},
|
||||
"match": "(?i:(\\$|@)(global|local|private|script|using|workflow):((?:\\p{L}|\\d|_)+))"
|
||||
},
|
||||
{
|
||||
"captures": {
|
||||
"0": {
|
||||
"name": "variable.other.readwrite.powershell"
|
||||
},
|
||||
"1": {
|
||||
"name": "keyword.other.variable.definition.powershell"
|
||||
"name": "punctuation.definition.variable.powershell"
|
||||
},
|
||||
"2": {
|
||||
"name": "storage.modifier.scope.powershell"
|
||||
},
|
||||
"3": {
|
||||
"name": "variable.other.readwrite.powershell"
|
||||
},
|
||||
"4": {
|
||||
"name": "keyword.other.powershell"
|
||||
},
|
||||
"5": {
|
||||
"name": "entity.name.function.invocation.powershell"
|
||||
"name": "variable.other.member.powershell"
|
||||
}
|
||||
},
|
||||
"match": "(?i:(\\$)(\\{)(global|local|private|script|using|workflow):([^}]*[^}`])(\\}))"
|
||||
},
|
||||
{
|
||||
"captures": {
|
||||
"0": {
|
||||
"name": "variable.other.readwrite.powershell"
|
||||
},
|
||||
"1": {
|
||||
"name": "keyword.other.variable.definition.powershell"
|
||||
"name": "punctuation.definition.variable.powershell"
|
||||
},
|
||||
"2": {
|
||||
"name": "support.variable.drive.powershell"
|
||||
},
|
||||
"3": {
|
||||
"name": "variable.other.readwrite.powershell"
|
||||
},
|
||||
"4": {
|
||||
"name": "entity.name.function.invocation.powershell"
|
||||
"name": "variable.other.member.powershell"
|
||||
}
|
||||
},
|
||||
"match": "(?i:(\\$)((?:\\p{L}|\\d|_)+:)?((?:\\p{L}|\\d|_)+))"
|
||||
},
|
||||
{
|
||||
"captures": {
|
||||
"0": {
|
||||
"name": "variable.other.readwrite.powershell"
|
||||
},
|
||||
"1": {
|
||||
"name": "keyword.other.variable.definition.powershell"
|
||||
"name": "punctuation.definition.variable.powershell"
|
||||
},
|
||||
"2": {
|
||||
"name": "punctuation.section.braces.begin"
|
||||
|
@ -915,9 +950,6 @@
|
|||
"3": {
|
||||
"name": "support.variable.drive.powershell"
|
||||
},
|
||||
"4": {
|
||||
"name": "variable.other.readwrite.powershell"
|
||||
},
|
||||
"5": {
|
||||
"name": "punctuation.section.braces.end"
|
||||
}
|
||||
|
@ -972,7 +1004,17 @@
|
|||
},
|
||||
"doubleQuotedString": {
|
||||
"begin": "(?<!(?<!`)\")\"",
|
||||
"beginCaptures": {
|
||||
"0": {
|
||||
"name": "punctuation.definition.string.begin.powershell"
|
||||
}
|
||||
},
|
||||
"end": "\"(?!\")",
|
||||
"endCaptures": {
|
||||
"0": {
|
||||
"name": "punctuation.definition.string.end.powershell"
|
||||
}
|
||||
},
|
||||
"name": "string.quoted.double.powershell",
|
||||
"patterns": [
|
||||
{
|
||||
|
|
|
@ -155,13 +155,13 @@
|
|||
},
|
||||
{
|
||||
"c": "$",
|
||||
"t": "source.powershell meta.scriptblock.powershell meta.scriptblock.powershell keyword.other.variable.definition.powershell",
|
||||
"t": "source.powershell meta.scriptblock.powershell meta.scriptblock.powershell variable.other.readwrite.powershell punctuation.definition.variable.powershell",
|
||||
"r": {
|
||||
"dark_plus": "keyword: #569CD6",
|
||||
"light_plus": "keyword: #0000FF",
|
||||
"dark_vs": "keyword: #569CD6",
|
||||
"light_vs": "keyword: #0000FF",
|
||||
"hc_black": "keyword: #569CD6"
|
||||
"dark_plus": "variable: #9CDCFE",
|
||||
"light_plus": "variable: #001080",
|
||||
"dark_vs": "default: #D4D4D4",
|
||||
"light_vs": "default: #000000",
|
||||
"hc_black": "variable: #9CDCFE"
|
||||
}
|
||||
},
|
||||
{
|
||||
|
@ -287,13 +287,13 @@
|
|||
},
|
||||
{
|
||||
"c": "$",
|
||||
"t": "source.powershell meta.scriptblock.powershell meta.scriptblock.powershell keyword.other.variable.definition.powershell",
|
||||
"t": "source.powershell meta.scriptblock.powershell meta.scriptblock.powershell variable.other.readwrite.powershell punctuation.definition.variable.powershell",
|
||||
"r": {
|
||||
"dark_plus": "keyword: #569CD6",
|
||||
"light_plus": "keyword: #0000FF",
|
||||
"dark_vs": "keyword: #569CD6",
|
||||
"light_vs": "keyword: #0000FF",
|
||||
"hc_black": "keyword: #569CD6"
|
||||
"dark_plus": "variable: #9CDCFE",
|
||||
"light_plus": "variable: #001080",
|
||||
"dark_vs": "default: #D4D4D4",
|
||||
"light_vs": "default: #000000",
|
||||
"hc_black": "variable: #9CDCFE"
|
||||
}
|
||||
},
|
||||
{
|
||||
|
@ -386,13 +386,13 @@
|
|||
},
|
||||
{
|
||||
"c": "$",
|
||||
"t": "source.powershell meta.scriptblock.powershell meta.scriptblock.powershell keyword.other.variable.definition.powershell",
|
||||
"t": "source.powershell meta.scriptblock.powershell meta.scriptblock.powershell variable.other.readwrite.powershell punctuation.definition.variable.powershell",
|
||||
"r": {
|
||||
"dark_plus": "keyword: #569CD6",
|
||||
"light_plus": "keyword: #0000FF",
|
||||
"dark_vs": "keyword: #569CD6",
|
||||
"light_vs": "keyword: #0000FF",
|
||||
"hc_black": "keyword: #569CD6"
|
||||
"dark_plus": "variable: #9CDCFE",
|
||||
"light_plus": "variable: #001080",
|
||||
"dark_vs": "default: #D4D4D4",
|
||||
"light_vs": "default: #000000",
|
||||
"hc_black": "variable: #9CDCFE"
|
||||
}
|
||||
},
|
||||
{
|
||||
|
@ -441,13 +441,13 @@
|
|||
},
|
||||
{
|
||||
"c": "$",
|
||||
"t": "source.powershell meta.scriptblock.powershell meta.scriptblock.powershell keyword.other.variable.definition.powershell",
|
||||
"t": "source.powershell meta.scriptblock.powershell meta.scriptblock.powershell variable.other.readwrite.powershell punctuation.definition.variable.powershell",
|
||||
"r": {
|
||||
"dark_plus": "keyword: #569CD6",
|
||||
"light_plus": "keyword: #0000FF",
|
||||
"dark_vs": "keyword: #569CD6",
|
||||
"light_vs": "keyword: #0000FF",
|
||||
"hc_black": "keyword: #569CD6"
|
||||
"dark_plus": "variable: #9CDCFE",
|
||||
"light_plus": "variable: #001080",
|
||||
"dark_vs": "default: #D4D4D4",
|
||||
"light_vs": "default: #000000",
|
||||
"hc_black": "variable: #9CDCFE"
|
||||
}
|
||||
},
|
||||
{
|
||||
|
@ -463,13 +463,13 @@
|
|||
},
|
||||
{
|
||||
"c": ".IsInRole",
|
||||
"t": "source.powershell meta.scriptblock.powershell meta.scriptblock.powershell entity.name.function.invocation.powershell",
|
||||
"t": "source.powershell meta.scriptblock.powershell meta.scriptblock.powershell variable.other.readwrite.powershell variable.other.member.powershell",
|
||||
"r": {
|
||||
"dark_plus": "entity.name.function: #DCDCAA",
|
||||
"light_plus": "entity.name.function: #795E26",
|
||||
"dark_plus": "variable: #9CDCFE",
|
||||
"light_plus": "variable: #001080",
|
||||
"dark_vs": "default: #D4D4D4",
|
||||
"light_vs": "default: #000000",
|
||||
"hc_black": "entity.name.function: #DCDCAA"
|
||||
"hc_black": "variable: #9CDCFE"
|
||||
}
|
||||
},
|
||||
{
|
||||
|
@ -649,7 +649,18 @@
|
|||
}
|
||||
},
|
||||
{
|
||||
"c": "\"Failed to determine if the current user has elevated privileges. The error was: '{0}'.\"",
|
||||
"c": "\"",
|
||||
"t": "source.powershell meta.scriptblock.powershell meta.scriptblock.powershell string.quoted.double.powershell punctuation.definition.string.begin.powershell",
|
||||
"r": {
|
||||
"dark_plus": "string: #CE9178",
|
||||
"light_plus": "string: #A31515",
|
||||
"dark_vs": "string: #CE9178",
|
||||
"light_vs": "string: #A31515",
|
||||
"hc_black": "string: #CE9178"
|
||||
}
|
||||
},
|
||||
{
|
||||
"c": "Failed to determine if the current user has elevated privileges. The error was: '{0}'.",
|
||||
"t": "source.powershell meta.scriptblock.powershell meta.scriptblock.powershell string.quoted.double.powershell",
|
||||
"r": {
|
||||
"dark_plus": "string: #CE9178",
|
||||
|
@ -659,6 +670,17 @@
|
|||
"hc_black": "string: #CE9178"
|
||||
}
|
||||
},
|
||||
{
|
||||
"c": "\"",
|
||||
"t": "source.powershell meta.scriptblock.powershell meta.scriptblock.powershell string.quoted.double.powershell punctuation.definition.string.end.powershell",
|
||||
"r": {
|
||||
"dark_plus": "string: #CE9178",
|
||||
"light_plus": "string: #A31515",
|
||||
"dark_vs": "string: #CE9178",
|
||||
"light_vs": "string: #A31515",
|
||||
"hc_black": "string: #CE9178"
|
||||
}
|
||||
},
|
||||
{
|
||||
"c": " ",
|
||||
"t": "source.powershell meta.scriptblock.powershell meta.scriptblock.powershell",
|
||||
|
@ -694,13 +716,13 @@
|
|||
},
|
||||
{
|
||||
"c": "$",
|
||||
"t": "source.powershell meta.scriptblock.powershell meta.scriptblock.powershell keyword.other.variable.definition.powershell",
|
||||
"t": "source.powershell meta.scriptblock.powershell meta.scriptblock.powershell support.constant.automatic.powershell punctuation.definition.variable.powershell",
|
||||
"r": {
|
||||
"dark_plus": "keyword: #569CD6",
|
||||
"light_plus": "keyword: #0000FF",
|
||||
"dark_vs": "keyword: #569CD6",
|
||||
"light_vs": "keyword: #0000FF",
|
||||
"hc_black": "keyword: #569CD6"
|
||||
"dark_plus": "default: #D4D4D4",
|
||||
"light_plus": "default: #000000",
|
||||
"dark_vs": "default: #D4D4D4",
|
||||
"light_vs": "default: #000000",
|
||||
"hc_black": "default: #FFFFFF"
|
||||
}
|
||||
},
|
||||
{
|
||||
|
@ -991,13 +1013,13 @@
|
|||
},
|
||||
{
|
||||
"c": "$",
|
||||
"t": "source.powershell meta.scriptblock.powershell interpolated.simple.source.powershell keyword.other.variable.definition.powershell",
|
||||
"t": "source.powershell meta.scriptblock.powershell interpolated.simple.source.powershell variable.other.readwrite.powershell punctuation.definition.variable.powershell",
|
||||
"r": {
|
||||
"dark_plus": "keyword: #569CD6",
|
||||
"light_plus": "keyword: #0000FF",
|
||||
"dark_vs": "keyword: #569CD6",
|
||||
"light_vs": "keyword: #0000FF",
|
||||
"hc_black": "keyword: #569CD6"
|
||||
"dark_plus": "variable: #9CDCFE",
|
||||
"light_plus": "variable: #001080",
|
||||
"dark_vs": "default: #D4D4D4",
|
||||
"light_vs": "default: #000000",
|
||||
"hc_black": "variable: #9CDCFE"
|
||||
}
|
||||
},
|
||||
{
|
||||
|
@ -1068,13 +1090,13 @@
|
|||
},
|
||||
{
|
||||
"c": "$",
|
||||
"t": "source.powershell meta.scriptblock.powershell interpolated.simple.source.powershell keyword.other.variable.definition.powershell",
|
||||
"t": "source.powershell meta.scriptblock.powershell interpolated.simple.source.powershell support.constant.automatic.powershell punctuation.definition.variable.powershell",
|
||||
"r": {
|
||||
"dark_plus": "keyword: #569CD6",
|
||||
"light_plus": "keyword: #0000FF",
|
||||
"dark_vs": "keyword: #569CD6",
|
||||
"light_vs": "keyword: #0000FF",
|
||||
"hc_black": "keyword: #569CD6"
|
||||
"dark_plus": "default: #D4D4D4",
|
||||
"light_plus": "default: #000000",
|
||||
"dark_vs": "default: #D4D4D4",
|
||||
"light_vs": "default: #000000",
|
||||
"hc_black": "default: #FFFFFF"
|
||||
}
|
||||
},
|
||||
{
|
||||
|
@ -1145,7 +1167,7 @@
|
|||
},
|
||||
{
|
||||
"c": "\"",
|
||||
"t": "source.powershell meta.scriptblock.powershell interpolated.simple.source.powershell string.quoted.double.powershell",
|
||||
"t": "source.powershell meta.scriptblock.powershell interpolated.simple.source.powershell string.quoted.double.powershell punctuation.definition.string.begin.powershell",
|
||||
"r": {
|
||||
"dark_plus": "string: #CE9178",
|
||||
"light_plus": "string: #A31515",
|
||||
|
@ -1156,13 +1178,13 @@
|
|||
},
|
||||
{
|
||||
"c": "$",
|
||||
"t": "source.powershell meta.scriptblock.powershell interpolated.simple.source.powershell string.quoted.double.powershell keyword.other.variable.definition.powershell",
|
||||
"t": "source.powershell meta.scriptblock.powershell interpolated.simple.source.powershell string.quoted.double.powershell variable.other.readwrite.powershell punctuation.definition.variable.powershell",
|
||||
"r": {
|
||||
"dark_plus": "keyword: #569CD6",
|
||||
"light_plus": "keyword: #0000FF",
|
||||
"dark_vs": "keyword: #569CD6",
|
||||
"light_vs": "keyword: #0000FF",
|
||||
"hc_black": "keyword: #569CD6"
|
||||
"dark_plus": "variable: #9CDCFE",
|
||||
"light_plus": "variable: #001080",
|
||||
"dark_vs": "string: #CE9178",
|
||||
"light_vs": "string: #A31515",
|
||||
"hc_black": "variable: #9CDCFE"
|
||||
}
|
||||
},
|
||||
{
|
||||
|
@ -1177,7 +1199,7 @@
|
|||
}
|
||||
},
|
||||
{
|
||||
"c": " 2>&1 & set\"",
|
||||
"c": " 2>&1 & set",
|
||||
"t": "source.powershell meta.scriptblock.powershell interpolated.simple.source.powershell string.quoted.double.powershell",
|
||||
"r": {
|
||||
"dark_plus": "string: #CE9178",
|
||||
|
@ -1187,6 +1209,17 @@
|
|||
"hc_black": "string: #CE9178"
|
||||
}
|
||||
},
|
||||
{
|
||||
"c": "\"",
|
||||
"t": "source.powershell meta.scriptblock.powershell interpolated.simple.source.powershell string.quoted.double.powershell punctuation.definition.string.end.powershell",
|
||||
"r": {
|
||||
"dark_plus": "string: #CE9178",
|
||||
"light_plus": "string: #A31515",
|
||||
"dark_vs": "string: #CE9178",
|
||||
"light_vs": "string: #A31515",
|
||||
"hc_black": "string: #CE9178"
|
||||
}
|
||||
},
|
||||
{
|
||||
"c": ")",
|
||||
"t": "source.powershell meta.scriptblock.powershell punctuation.section.group.end.powershell",
|
||||
|
@ -1266,13 +1299,13 @@
|
|||
},
|
||||
{
|
||||
"c": "$",
|
||||
"t": "source.powershell meta.scriptblock.powershell meta.scriptblock.powershell interpolated.simple.source.powershell keyword.other.variable.definition.powershell",
|
||||
"t": "source.powershell meta.scriptblock.powershell meta.scriptblock.powershell interpolated.simple.source.powershell support.constant.automatic.powershell punctuation.definition.variable.powershell",
|
||||
"r": {
|
||||
"dark_plus": "keyword: #569CD6",
|
||||
"light_plus": "keyword: #0000FF",
|
||||
"dark_vs": "keyword: #569CD6",
|
||||
"light_vs": "keyword: #0000FF",
|
||||
"hc_black": "keyword: #569CD6"
|
||||
"dark_plus": "default: #D4D4D4",
|
||||
"light_plus": "default: #000000",
|
||||
"dark_vs": "default: #D4D4D4",
|
||||
"light_vs": "default: #000000",
|
||||
"hc_black": "default: #FFFFFF"
|
||||
}
|
||||
},
|
||||
{
|
||||
|
@ -1320,7 +1353,18 @@
|
|||
}
|
||||
},
|
||||
{
|
||||
"c": "'^([^=]+)=(.*)'",
|
||||
"c": "'",
|
||||
"t": "source.powershell meta.scriptblock.powershell meta.scriptblock.powershell interpolated.simple.source.powershell string.quoted.single.powershell punctuation.definition.string.begin.powershell",
|
||||
"r": {
|
||||
"dark_plus": "string: #CE9178",
|
||||
"light_plus": "string: #A31515",
|
||||
"dark_vs": "string: #CE9178",
|
||||
"light_vs": "string: #A31515",
|
||||
"hc_black": "string: #CE9178"
|
||||
}
|
||||
},
|
||||
{
|
||||
"c": "^([^=]+)=(.*)",
|
||||
"t": "source.powershell meta.scriptblock.powershell meta.scriptblock.powershell interpolated.simple.source.powershell string.quoted.single.powershell",
|
||||
"r": {
|
||||
"dark_plus": "string: #CE9178",
|
||||
|
@ -1330,6 +1374,17 @@
|
|||
"hc_black": "string: #CE9178"
|
||||
}
|
||||
},
|
||||
{
|
||||
"c": "'",
|
||||
"t": "source.powershell meta.scriptblock.powershell meta.scriptblock.powershell interpolated.simple.source.powershell string.quoted.single.powershell punctuation.definition.string.end.powershell",
|
||||
"r": {
|
||||
"dark_plus": "string: #CE9178",
|
||||
"light_plus": "string: #A31515",
|
||||
"dark_vs": "string: #CE9178",
|
||||
"light_vs": "string: #A31515",
|
||||
"hc_black": "string: #CE9178"
|
||||
}
|
||||
},
|
||||
{
|
||||
"c": ")",
|
||||
"t": "source.powershell meta.scriptblock.powershell meta.scriptblock.powershell punctuation.section.group.end.powershell",
|
||||
|
@ -1431,13 +1486,13 @@
|
|||
},
|
||||
{
|
||||
"c": "$",
|
||||
"t": "source.powershell meta.scriptblock.powershell meta.scriptblock.powershell meta.scriptblock.powershell interpolated.simple.source.powershell keyword.other.variable.definition.powershell",
|
||||
"t": "source.powershell meta.scriptblock.powershell meta.scriptblock.powershell meta.scriptblock.powershell interpolated.simple.source.powershell support.constant.automatic.powershell punctuation.definition.variable.powershell",
|
||||
"r": {
|
||||
"dark_plus": "keyword: #569CD6",
|
||||
"light_plus": "keyword: #0000FF",
|
||||
"dark_vs": "keyword: #569CD6",
|
||||
"light_vs": "keyword: #0000FF",
|
||||
"hc_black": "keyword: #569CD6"
|
||||
"dark_plus": "default: #D4D4D4",
|
||||
"light_plus": "default: #000000",
|
||||
"dark_vs": "default: #D4D4D4",
|
||||
"light_vs": "default: #000000",
|
||||
"hc_black": "default: #FFFFFF"
|
||||
}
|
||||
},
|
||||
{
|
||||
|
@ -1508,13 +1563,13 @@
|
|||
},
|
||||
{
|
||||
"c": "$",
|
||||
"t": "source.powershell meta.scriptblock.powershell meta.scriptblock.powershell meta.scriptblock.powershell interpolated.simple.source.powershell keyword.other.variable.definition.powershell",
|
||||
"t": "source.powershell meta.scriptblock.powershell meta.scriptblock.powershell meta.scriptblock.powershell interpolated.simple.source.powershell support.constant.automatic.powershell punctuation.definition.variable.powershell",
|
||||
"r": {
|
||||
"dark_plus": "keyword: #569CD6",
|
||||
"light_plus": "keyword: #0000FF",
|
||||
"dark_vs": "keyword: #569CD6",
|
||||
"light_vs": "keyword: #0000FF",
|
||||
"hc_black": "keyword: #569CD6"
|
||||
"dark_plus": "default: #D4D4D4",
|
||||
"light_plus": "default: #000000",
|
||||
"dark_vs": "default: #D4D4D4",
|
||||
"light_vs": "default: #000000",
|
||||
"hc_black": "default: #FFFFFF"
|
||||
}
|
||||
},
|
||||
{
|
||||
|
@ -1672,7 +1727,18 @@
|
|||
}
|
||||
},
|
||||
{
|
||||
"c": "'Initializing Azure PowerShell environment...'",
|
||||
"c": "'",
|
||||
"t": "source.powershell string.quoted.single.powershell punctuation.definition.string.begin.powershell",
|
||||
"r": {
|
||||
"dark_plus": "string: #CE9178",
|
||||
"light_plus": "string: #A31515",
|
||||
"dark_vs": "string: #CE9178",
|
||||
"light_vs": "string: #A31515",
|
||||
"hc_black": "string: #CE9178"
|
||||
}
|
||||
},
|
||||
{
|
||||
"c": "Initializing Azure PowerShell environment...",
|
||||
"t": "source.powershell string.quoted.single.powershell",
|
||||
"r": {
|
||||
"dark_plus": "string: #CE9178",
|
||||
|
@ -1683,14 +1749,25 @@
|
|||
}
|
||||
},
|
||||
{
|
||||
"c": ";",
|
||||
"t": "source.powershell keyword.other.statement-separator.powershell",
|
||||
"c": "'",
|
||||
"t": "source.powershell string.quoted.single.powershell punctuation.definition.string.end.powershell",
|
||||
"r": {
|
||||
"dark_plus": "keyword: #569CD6",
|
||||
"light_plus": "keyword: #0000FF",
|
||||
"dark_vs": "keyword: #569CD6",
|
||||
"light_vs": "keyword: #0000FF",
|
||||
"hc_black": "keyword: #569CD6"
|
||||
"dark_plus": "string: #CE9178",
|
||||
"light_plus": "string: #A31515",
|
||||
"dark_vs": "string: #CE9178",
|
||||
"light_vs": "string: #A31515",
|
||||
"hc_black": "string: #CE9178"
|
||||
}
|
||||
},
|
||||
{
|
||||
"c": ";",
|
||||
"t": "source.powershell punctuation.terminator.statement.powershell",
|
||||
"r": {
|
||||
"dark_plus": "default: #D4D4D4",
|
||||
"light_plus": "default: #000000",
|
||||
"dark_vs": "default: #D4D4D4",
|
||||
"light_vs": "default: #000000",
|
||||
"hc_black": "default: #FFFFFF"
|
||||
}
|
||||
},
|
||||
{
|
||||
|
@ -1870,7 +1947,18 @@
|
|||
}
|
||||
},
|
||||
{
|
||||
"c": "'Please launch command under administrator account. It is needed for environment setting up and unit test.'",
|
||||
"c": "'",
|
||||
"t": "source.powershell meta.scriptblock.powershell string.quoted.single.powershell punctuation.definition.string.begin.powershell",
|
||||
"r": {
|
||||
"dark_plus": "string: #CE9178",
|
||||
"light_plus": "string: #A31515",
|
||||
"dark_vs": "string: #CE9178",
|
||||
"light_vs": "string: #A31515",
|
||||
"hc_black": "string: #CE9178"
|
||||
}
|
||||
},
|
||||
{
|
||||
"c": "Please launch command under administrator account. It is needed for environment setting up and unit test.",
|
||||
"t": "source.powershell meta.scriptblock.powershell string.quoted.single.powershell",
|
||||
"r": {
|
||||
"dark_plus": "string: #CE9178",
|
||||
|
@ -1880,6 +1968,17 @@
|
|||
"hc_black": "string: #CE9178"
|
||||
}
|
||||
},
|
||||
{
|
||||
"c": "'",
|
||||
"t": "source.powershell meta.scriptblock.powershell string.quoted.single.powershell punctuation.definition.string.end.powershell",
|
||||
"r": {
|
||||
"dark_plus": "string: #CE9178",
|
||||
"light_plus": "string: #A31515",
|
||||
"dark_vs": "string: #CE9178",
|
||||
"light_vs": "string: #A31515",
|
||||
"hc_black": "string: #CE9178"
|
||||
}
|
||||
},
|
||||
{
|
||||
"c": " ",
|
||||
"t": "source.powershell meta.scriptblock.powershell",
|
||||
|
@ -1915,13 +2014,13 @@
|
|||
},
|
||||
{
|
||||
"c": ";",
|
||||
"t": "source.powershell meta.scriptblock.powershell keyword.other.statement-separator.powershell",
|
||||
"t": "source.powershell meta.scriptblock.powershell punctuation.terminator.statement.powershell",
|
||||
"r": {
|
||||
"dark_plus": "keyword: #569CD6",
|
||||
"light_plus": "keyword: #0000FF",
|
||||
"dark_vs": "keyword: #569CD6",
|
||||
"light_vs": "keyword: #0000FF",
|
||||
"hc_black": "keyword: #569CD6"
|
||||
"dark_plus": "default: #D4D4D4",
|
||||
"light_plus": "default: #000000",
|
||||
"dark_vs": "default: #D4D4D4",
|
||||
"light_vs": "default: #000000",
|
||||
"hc_black": "default: #FFFFFF"
|
||||
}
|
||||
},
|
||||
{
|
||||
|
@ -1937,18 +2036,18 @@
|
|||
},
|
||||
{
|
||||
"c": "$",
|
||||
"t": "source.powershell keyword.other.variable.definition.powershell",
|
||||
"t": "source.powershell variable.other.readwrite.powershell punctuation.definition.variable.powershell",
|
||||
"r": {
|
||||
"dark_plus": "keyword: #569CD6",
|
||||
"light_plus": "keyword: #0000FF",
|
||||
"dark_vs": "keyword: #569CD6",
|
||||
"light_vs": "keyword: #0000FF",
|
||||
"hc_black": "keyword: #569CD6"
|
||||
"dark_plus": "variable: #9CDCFE",
|
||||
"light_plus": "variable: #001080",
|
||||
"dark_vs": "default: #D4D4D4",
|
||||
"light_vs": "default: #000000",
|
||||
"hc_black": "variable: #9CDCFE"
|
||||
}
|
||||
},
|
||||
{
|
||||
"c": "env:",
|
||||
"t": "source.powershell support.variable.drive.powershell",
|
||||
"t": "source.powershell variable.other.readwrite.powershell support.variable.drive.powershell",
|
||||
"r": {
|
||||
"dark_plus": "support.variable: #9CDCFE",
|
||||
"light_plus": "support.variable: #001080",
|
||||
|
@ -2069,18 +2168,18 @@
|
|||
},
|
||||
{
|
||||
"c": "$",
|
||||
"t": "source.powershell keyword.other.variable.definition.powershell",
|
||||
"t": "source.powershell variable.other.readwrite.powershell punctuation.definition.variable.powershell",
|
||||
"r": {
|
||||
"dark_plus": "keyword: #569CD6",
|
||||
"light_plus": "keyword: #0000FF",
|
||||
"dark_vs": "keyword: #569CD6",
|
||||
"light_vs": "keyword: #0000FF",
|
||||
"hc_black": "keyword: #569CD6"
|
||||
"dark_plus": "variable: #9CDCFE",
|
||||
"light_plus": "variable: #001080",
|
||||
"dark_vs": "default: #D4D4D4",
|
||||
"light_vs": "default: #000000",
|
||||
"hc_black": "variable: #9CDCFE"
|
||||
}
|
||||
},
|
||||
{
|
||||
"c": "env:",
|
||||
"t": "source.powershell support.variable.drive.powershell",
|
||||
"t": "source.powershell variable.other.readwrite.powershell support.variable.drive.powershell",
|
||||
"r": {
|
||||
"dark_plus": "support.variable: #9CDCFE",
|
||||
"light_plus": "support.variable: #001080",
|
||||
|
@ -2102,13 +2201,13 @@
|
|||
},
|
||||
{
|
||||
"c": ";",
|
||||
"t": "source.powershell keyword.other.statement-separator.powershell",
|
||||
"t": "source.powershell punctuation.terminator.statement.powershell",
|
||||
"r": {
|
||||
"dark_plus": "keyword: #569CD6",
|
||||
"light_plus": "keyword: #0000FF",
|
||||
"dark_vs": "keyword: #569CD6",
|
||||
"light_vs": "keyword: #0000FF",
|
||||
"hc_black": "keyword: #569CD6"
|
||||
"dark_plus": "default: #D4D4D4",
|
||||
"light_plus": "default: #000000",
|
||||
"dark_vs": "default: #D4D4D4",
|
||||
"light_vs": "default: #000000",
|
||||
"hc_black": "default: #FFFFFF"
|
||||
}
|
||||
},
|
||||
{
|
||||
|
@ -2190,7 +2289,7 @@
|
|||
},
|
||||
{
|
||||
"c": "\"",
|
||||
"t": "source.powershell interpolated.simple.source.powershell string.quoted.double.powershell",
|
||||
"t": "source.powershell interpolated.simple.source.powershell string.quoted.double.powershell punctuation.definition.string.begin.powershell",
|
||||
"r": {
|
||||
"dark_plus": "string: #CE9178",
|
||||
"light_plus": "string: #A31515",
|
||||
|
@ -2201,18 +2300,18 @@
|
|||
},
|
||||
{
|
||||
"c": "$",
|
||||
"t": "source.powershell interpolated.simple.source.powershell string.quoted.double.powershell keyword.other.variable.definition.powershell",
|
||||
"t": "source.powershell interpolated.simple.source.powershell string.quoted.double.powershell variable.other.readwrite.powershell punctuation.definition.variable.powershell",
|
||||
"r": {
|
||||
"dark_plus": "keyword: #569CD6",
|
||||
"light_plus": "keyword: #0000FF",
|
||||
"dark_vs": "keyword: #569CD6",
|
||||
"light_vs": "keyword: #0000FF",
|
||||
"hc_black": "keyword: #569CD6"
|
||||
"dark_plus": "variable: #9CDCFE",
|
||||
"light_plus": "variable: #001080",
|
||||
"dark_vs": "string: #CE9178",
|
||||
"light_vs": "string: #A31515",
|
||||
"hc_black": "variable: #9CDCFE"
|
||||
}
|
||||
},
|
||||
{
|
||||
"c": "env:",
|
||||
"t": "source.powershell interpolated.simple.source.powershell string.quoted.double.powershell support.variable.drive.powershell",
|
||||
"t": "source.powershell interpolated.simple.source.powershell string.quoted.double.powershell variable.other.readwrite.powershell support.variable.drive.powershell",
|
||||
"r": {
|
||||
"dark_plus": "support.variable: #9CDCFE",
|
||||
"light_plus": "support.variable: #001080",
|
||||
|
@ -2233,7 +2332,7 @@
|
|||
}
|
||||
},
|
||||
{
|
||||
"c": "\\Microsoft Visual Studio 12.0\"",
|
||||
"c": "\\Microsoft Visual Studio 12.0",
|
||||
"t": "source.powershell interpolated.simple.source.powershell string.quoted.double.powershell",
|
||||
"r": {
|
||||
"dark_plus": "string: #CE9178",
|
||||
|
@ -2243,6 +2342,17 @@
|
|||
"hc_black": "string: #CE9178"
|
||||
}
|
||||
},
|
||||
{
|
||||
"c": "\"",
|
||||
"t": "source.powershell interpolated.simple.source.powershell string.quoted.double.powershell punctuation.definition.string.end.powershell",
|
||||
"r": {
|
||||
"dark_plus": "string: #CE9178",
|
||||
"light_plus": "string: #A31515",
|
||||
"dark_vs": "string: #CE9178",
|
||||
"light_vs": "string: #A31515",
|
||||
"hc_black": "string: #CE9178"
|
||||
}
|
||||
},
|
||||
{
|
||||
"c": ")",
|
||||
"t": "source.powershell punctuation.section.group.end.powershell",
|
||||
|
@ -2289,13 +2399,13 @@
|
|||
},
|
||||
{
|
||||
"c": "$",
|
||||
"t": "source.powershell meta.scriptblock.powershell keyword.other.variable.definition.powershell",
|
||||
"t": "source.powershell meta.scriptblock.powershell variable.other.readwrite.powershell punctuation.definition.variable.powershell",
|
||||
"r": {
|
||||
"dark_plus": "keyword: #569CD6",
|
||||
"light_plus": "keyword: #0000FF",
|
||||
"dark_vs": "keyword: #569CD6",
|
||||
"light_vs": "keyword: #0000FF",
|
||||
"hc_black": "keyword: #569CD6"
|
||||
"dark_plus": "variable: #9CDCFE",
|
||||
"light_plus": "variable: #001080",
|
||||
"dark_vs": "default: #D4D4D4",
|
||||
"light_vs": "default: #000000",
|
||||
"hc_black": "variable: #9CDCFE"
|
||||
}
|
||||
},
|
||||
{
|
||||
|
@ -2321,7 +2431,18 @@
|
|||
}
|
||||
},
|
||||
{
|
||||
"c": "\"12.0\"",
|
||||
"c": "\"",
|
||||
"t": "source.powershell meta.scriptblock.powershell string.quoted.double.powershell punctuation.definition.string.begin.powershell",
|
||||
"r": {
|
||||
"dark_plus": "string: #CE9178",
|
||||
"light_plus": "string: #A31515",
|
||||
"dark_vs": "string: #CE9178",
|
||||
"light_vs": "string: #A31515",
|
||||
"hc_black": "string: #CE9178"
|
||||
}
|
||||
},
|
||||
{
|
||||
"c": "12.0",
|
||||
"t": "source.powershell meta.scriptblock.powershell string.quoted.double.powershell",
|
||||
"r": {
|
||||
"dark_plus": "string: #CE9178",
|
||||
|
@ -2331,6 +2452,17 @@
|
|||
"hc_black": "string: #CE9178"
|
||||
}
|
||||
},
|
||||
{
|
||||
"c": "\"",
|
||||
"t": "source.powershell meta.scriptblock.powershell string.quoted.double.powershell punctuation.definition.string.end.powershell",
|
||||
"r": {
|
||||
"dark_plus": "string: #CE9178",
|
||||
"light_plus": "string: #A31515",
|
||||
"dark_vs": "string: #CE9178",
|
||||
"light_vs": "string: #A31515",
|
||||
"hc_black": "string: #CE9178"
|
||||
}
|
||||
},
|
||||
{
|
||||
"c": "}",
|
||||
"t": "source.powershell meta.scriptblock.powershell punctuation.section.braces.end.powershell",
|
||||
|
@ -2399,13 +2531,13 @@
|
|||
},
|
||||
{
|
||||
"c": "$",
|
||||
"t": "source.powershell meta.scriptblock.powershell keyword.other.variable.definition.powershell",
|
||||
"t": "source.powershell meta.scriptblock.powershell variable.other.readwrite.powershell punctuation.definition.variable.powershell",
|
||||
"r": {
|
||||
"dark_plus": "keyword: #569CD6",
|
||||
"light_plus": "keyword: #0000FF",
|
||||
"dark_vs": "keyword: #569CD6",
|
||||
"light_vs": "keyword: #0000FF",
|
||||
"hc_black": "keyword: #569CD6"
|
||||
"dark_plus": "variable: #9CDCFE",
|
||||
"light_plus": "variable: #001080",
|
||||
"dark_vs": "default: #D4D4D4",
|
||||
"light_vs": "default: #000000",
|
||||
"hc_black": "variable: #9CDCFE"
|
||||
}
|
||||
},
|
||||
{
|
||||
|
@ -2431,7 +2563,18 @@
|
|||
}
|
||||
},
|
||||
{
|
||||
"c": "\"11.0\"",
|
||||
"c": "\"",
|
||||
"t": "source.powershell meta.scriptblock.powershell string.quoted.double.powershell punctuation.definition.string.begin.powershell",
|
||||
"r": {
|
||||
"dark_plus": "string: #CE9178",
|
||||
"light_plus": "string: #A31515",
|
||||
"dark_vs": "string: #CE9178",
|
||||
"light_vs": "string: #A31515",
|
||||
"hc_black": "string: #CE9178"
|
||||
}
|
||||
},
|
||||
{
|
||||
"c": "11.0",
|
||||
"t": "source.powershell meta.scriptblock.powershell string.quoted.double.powershell",
|
||||
"r": {
|
||||
"dark_plus": "string: #CE9178",
|
||||
|
@ -2441,6 +2584,17 @@
|
|||
"hc_black": "string: #CE9178"
|
||||
}
|
||||
},
|
||||
{
|
||||
"c": "\"",
|
||||
"t": "source.powershell meta.scriptblock.powershell string.quoted.double.powershell punctuation.definition.string.end.powershell",
|
||||
"r": {
|
||||
"dark_plus": "string: #CE9178",
|
||||
"light_plus": "string: #A31515",
|
||||
"dark_vs": "string: #CE9178",
|
||||
"light_vs": "string: #A31515",
|
||||
"hc_black": "string: #CE9178"
|
||||
}
|
||||
},
|
||||
{
|
||||
"c": "}",
|
||||
"t": "source.powershell meta.scriptblock.powershell punctuation.section.braces.end.powershell",
|
||||
|
@ -2454,13 +2608,13 @@
|
|||
},
|
||||
{
|
||||
"c": "$",
|
||||
"t": "source.powershell keyword.other.variable.definition.powershell",
|
||||
"t": "source.powershell variable.other.readwrite.powershell punctuation.definition.variable.powershell",
|
||||
"r": {
|
||||
"dark_plus": "keyword: #569CD6",
|
||||
"light_plus": "keyword: #0000FF",
|
||||
"dark_vs": "keyword: #569CD6",
|
||||
"light_vs": "keyword: #0000FF",
|
||||
"hc_black": "keyword: #569CD6"
|
||||
"dark_plus": "variable: #9CDCFE",
|
||||
"light_plus": "variable: #001080",
|
||||
"dark_vs": "default: #D4D4D4",
|
||||
"light_vs": "default: #000000",
|
||||
"hc_black": "variable: #9CDCFE"
|
||||
}
|
||||
},
|
||||
{
|
||||
|
@ -2508,7 +2662,18 @@
|
|||
}
|
||||
},
|
||||
{
|
||||
"c": "'\"{0}\\Microsoft Visual Studio {1}\\VC\\vcvarsall.bat\" x64'",
|
||||
"c": "'",
|
||||
"t": "source.powershell string.quoted.single.powershell punctuation.definition.string.begin.powershell",
|
||||
"r": {
|
||||
"dark_plus": "string: #CE9178",
|
||||
"light_plus": "string: #A31515",
|
||||
"dark_vs": "string: #CE9178",
|
||||
"light_vs": "string: #A31515",
|
||||
"hc_black": "string: #CE9178"
|
||||
}
|
||||
},
|
||||
{
|
||||
"c": "\"{0}\\Microsoft Visual Studio {1}\\VC\\vcvarsall.bat\" x64",
|
||||
"t": "source.powershell string.quoted.single.powershell",
|
||||
"r": {
|
||||
"dark_plus": "string: #CE9178",
|
||||
|
@ -2518,6 +2683,17 @@
|
|||
"hc_black": "string: #CE9178"
|
||||
}
|
||||
},
|
||||
{
|
||||
"c": "'",
|
||||
"t": "source.powershell string.quoted.single.powershell punctuation.definition.string.end.powershell",
|
||||
"r": {
|
||||
"dark_plus": "string: #CE9178",
|
||||
"light_plus": "string: #A31515",
|
||||
"dark_vs": "string: #CE9178",
|
||||
"light_vs": "string: #A31515",
|
||||
"hc_black": "string: #CE9178"
|
||||
}
|
||||
},
|
||||
{
|
||||
"c": " ",
|
||||
"t": "source.powershell",
|
||||
|
@ -2553,18 +2729,18 @@
|
|||
},
|
||||
{
|
||||
"c": "$",
|
||||
"t": "source.powershell keyword.other.variable.definition.powershell",
|
||||
"t": "source.powershell variable.other.readwrite.powershell punctuation.definition.variable.powershell",
|
||||
"r": {
|
||||
"dark_plus": "keyword: #569CD6",
|
||||
"light_plus": "keyword: #0000FF",
|
||||
"dark_vs": "keyword: #569CD6",
|
||||
"light_vs": "keyword: #0000FF",
|
||||
"hc_black": "keyword: #569CD6"
|
||||
"dark_plus": "variable: #9CDCFE",
|
||||
"light_plus": "variable: #001080",
|
||||
"dark_vs": "default: #D4D4D4",
|
||||
"light_vs": "default: #000000",
|
||||
"hc_black": "variable: #9CDCFE"
|
||||
}
|
||||
},
|
||||
{
|
||||
"c": "env:",
|
||||
"t": "source.powershell support.variable.drive.powershell",
|
||||
"t": "source.powershell variable.other.readwrite.powershell support.variable.drive.powershell",
|
||||
"r": {
|
||||
"dark_plus": "support.variable: #9CDCFE",
|
||||
"light_plus": "support.variable: #001080",
|
||||
|
@ -2608,13 +2784,13 @@
|
|||
},
|
||||
{
|
||||
"c": "$",
|
||||
"t": "source.powershell keyword.other.variable.definition.powershell",
|
||||
"t": "source.powershell variable.other.readwrite.powershell punctuation.definition.variable.powershell",
|
||||
"r": {
|
||||
"dark_plus": "keyword: #569CD6",
|
||||
"light_plus": "keyword: #0000FF",
|
||||
"dark_vs": "keyword: #569CD6",
|
||||
"light_vs": "keyword: #0000FF",
|
||||
"hc_black": "keyword: #569CD6"
|
||||
"dark_plus": "variable: #9CDCFE",
|
||||
"light_plus": "variable: #001080",
|
||||
"dark_vs": "default: #D4D4D4",
|
||||
"light_vs": "default: #000000",
|
||||
"hc_black": "variable: #9CDCFE"
|
||||
}
|
||||
},
|
||||
{
|
||||
|
@ -2630,13 +2806,13 @@
|
|||
},
|
||||
{
|
||||
"c": ";",
|
||||
"t": "source.powershell keyword.other.statement-separator.powershell",
|
||||
"t": "source.powershell punctuation.terminator.statement.powershell",
|
||||
"r": {
|
||||
"dark_plus": "keyword: #569CD6",
|
||||
"light_plus": "keyword: #0000FF",
|
||||
"dark_vs": "keyword: #569CD6",
|
||||
"light_vs": "keyword: #0000FF",
|
||||
"hc_black": "keyword: #569CD6"
|
||||
"dark_plus": "default: #D4D4D4",
|
||||
"light_plus": "default: #000000",
|
||||
"dark_vs": "default: #D4D4D4",
|
||||
"light_vs": "default: #000000",
|
||||
"hc_black": "default: #FFFFFF"
|
||||
}
|
||||
},
|
||||
{
|
||||
|
@ -2685,13 +2861,13 @@
|
|||
},
|
||||
{
|
||||
"c": "$",
|
||||
"t": "source.powershell keyword.other.variable.definition.powershell",
|
||||
"t": "source.powershell variable.other.readwrite.powershell punctuation.definition.variable.powershell",
|
||||
"r": {
|
||||
"dark_plus": "keyword: #569CD6",
|
||||
"light_plus": "keyword: #0000FF",
|
||||
"dark_vs": "keyword: #569CD6",
|
||||
"light_vs": "keyword: #0000FF",
|
||||
"hc_black": "keyword: #569CD6"
|
||||
"dark_plus": "variable: #9CDCFE",
|
||||
"light_plus": "variable: #001080",
|
||||
"dark_vs": "default: #D4D4D4",
|
||||
"light_vs": "default: #000000",
|
||||
"hc_black": "variable: #9CDCFE"
|
||||
}
|
||||
},
|
||||
{
|
||||
|
@ -2707,13 +2883,13 @@
|
|||
},
|
||||
{
|
||||
"c": ";",
|
||||
"t": "source.powershell keyword.other.statement-separator.powershell",
|
||||
"t": "source.powershell punctuation.terminator.statement.powershell",
|
||||
"r": {
|
||||
"dark_plus": "keyword: #569CD6",
|
||||
"light_plus": "keyword: #0000FF",
|
||||
"dark_vs": "keyword: #569CD6",
|
||||
"light_vs": "keyword: #0000FF",
|
||||
"hc_black": "keyword: #569CD6"
|
||||
"dark_plus": "default: #D4D4D4",
|
||||
"light_plus": "default: #000000",
|
||||
"dark_vs": "default: #D4D4D4",
|
||||
"light_vs": "default: #000000",
|
||||
"hc_black": "default: #FFFFFF"
|
||||
}
|
||||
}
|
||||
]
|
|
@ -14,7 +14,7 @@
|
|||
"categories": [],
|
||||
"dependencies": {
|
||||
"vscode-extension-telemetry": "0.0.15",
|
||||
"vscode-nls": "^3.2.1",
|
||||
"vscode-nls": "^3.2.4",
|
||||
"vscode-ripgrep": "^1.0.1"
|
||||
},
|
||||
"devDependencies": {
|
||||
|
|
229
extensions/search-rg/src/cachedSearchProvider.ts
Normal file
229
extensions/search-rg/src/cachedSearchProvider.ts
Normal file
|
@ -0,0 +1,229 @@
|
|||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import * as path from 'path';
|
||||
import * as vscode from 'vscode';
|
||||
import * as arrays from './common/arrays';
|
||||
import { compareItemsByScore, IItemAccessor, prepareQuery, ScorerCache } from './common/fileSearchScorer';
|
||||
import * as strings from './common/strings';
|
||||
import { joinPath } from './utils';
|
||||
|
||||
interface IProviderArgs {
|
||||
query: vscode.FileSearchQuery;
|
||||
options: vscode.FileSearchOptions;
|
||||
progress: vscode.Progress<vscode.Uri>;
|
||||
token: vscode.CancellationToken;
|
||||
}
|
||||
|
||||
export interface IInternalFileSearchProvider {
|
||||
provideFileSearchResults(options: vscode.FileSearchOptions, progress: vscode.Progress<string>, token: vscode.CancellationToken): Thenable<void>;
|
||||
}
|
||||
|
||||
export class CachedSearchProvider {
|
||||
|
||||
private static readonly BATCH_SIZE = 512;
|
||||
|
||||
private caches: { [cacheKey: string]: Cache; } = Object.create(null);
|
||||
|
||||
provideFileSearchResults(provider: IInternalFileSearchProvider, query: vscode.FileSearchQuery, options: vscode.FileSearchOptions, progress: vscode.Progress<vscode.Uri>, token: vscode.CancellationToken): Thenable<void> {
|
||||
const onResult = (result: IInternalFileMatch) => {
|
||||
progress.report(joinPath(options.folder, result.relativePath));
|
||||
};
|
||||
|
||||
const providerArgs: IProviderArgs = {
|
||||
query, options, progress, token
|
||||
};
|
||||
|
||||
let sortedSearch = this.trySortedSearchFromCache(providerArgs, onResult);
|
||||
if (!sortedSearch) {
|
||||
const engineOpts = options.maxResults ?
|
||||
{
|
||||
...options,
|
||||
...{ maxResults: 1e9 }
|
||||
} :
|
||||
options;
|
||||
providerArgs.options = engineOpts;
|
||||
|
||||
sortedSearch = this.doSortedSearch(providerArgs, provider);
|
||||
}
|
||||
|
||||
return sortedSearch.then(rawMatches => {
|
||||
rawMatches.forEach(onResult);
|
||||
});
|
||||
}
|
||||
|
||||
private doSortedSearch(args: IProviderArgs, provider: IInternalFileSearchProvider): Promise<IInternalFileMatch[]> {
|
||||
const allResultsPromise = new Promise<IInternalFileMatch[]>((c, e) => {
|
||||
const results: IInternalFileMatch[] = [];
|
||||
const onResult = (progress: IInternalFileMatch[]) => results.push(...progress);
|
||||
|
||||
// TODO@roblou set maxResult = null
|
||||
this.doSearch(args, provider, onResult, CachedSearchProvider.BATCH_SIZE)
|
||||
.then(() => c(results), e);
|
||||
});
|
||||
|
||||
let cache: Cache;
|
||||
if (args.query.cacheKey) {
|
||||
cache = this.getOrCreateCache(args.query.cacheKey); // TODO include folder in cache key
|
||||
cache.resultsToSearchCache[args.query.pattern] = { finished: allResultsPromise };
|
||||
allResultsPromise.then(null, err => {
|
||||
delete cache.resultsToSearchCache[args.query.pattern];
|
||||
});
|
||||
}
|
||||
|
||||
return allResultsPromise.then(results => {
|
||||
const scorerCache: ScorerCache = cache ? cache.scorerCache : Object.create(null);
|
||||
return this.sortResults(args, results, scorerCache);
|
||||
});
|
||||
}
|
||||
|
||||
private getOrCreateCache(cacheKey: string): Cache {
|
||||
const existing = this.caches[cacheKey];
|
||||
if (existing) {
|
||||
return existing;
|
||||
}
|
||||
return this.caches[cacheKey] = new Cache();
|
||||
}
|
||||
|
||||
private trySortedSearchFromCache(args: IProviderArgs, onResult: (result: IInternalFileMatch) => void): Promise<IInternalFileMatch[]> {
|
||||
const cache = args.query.cacheKey && this.caches[args.query.cacheKey];
|
||||
if (!cache) {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
const cached = this.getResultsFromCache(cache, args.query.pattern, onResult);
|
||||
if (cached) {
|
||||
return cached.then((results) => this.sortResults(args, results, cache.scorerCache));
|
||||
}
|
||||
|
||||
return undefined;
|
||||
}
|
||||
|
||||
private sortResults(args: IProviderArgs, results: IInternalFileMatch[], scorerCache: ScorerCache): Promise<IInternalFileMatch[]> {
|
||||
// we use the same compare function that is used later when showing the results using fuzzy scoring
|
||||
// this is very important because we are also limiting the number of results by config.maxResults
|
||||
// and as such we want the top items to be included in this result set if the number of items
|
||||
// exceeds config.maxResults.
|
||||
const preparedQuery = prepareQuery(args.query.pattern);
|
||||
const compare = (matchA: IInternalFileMatch, matchB: IInternalFileMatch) => compareItemsByScore(matchA, matchB, preparedQuery, true, FileMatchItemAccessor, scorerCache);
|
||||
|
||||
return arrays.topAsync(results, compare, args.options.maxResults || 0, 10000);
|
||||
}
|
||||
|
||||
private getResultsFromCache(cache: Cache, searchValue: string, onResult: (results: IInternalFileMatch) => void): Promise<IInternalFileMatch[]> {
|
||||
// Find cache entries by prefix of search value
|
||||
const hasPathSep = searchValue.indexOf(path.sep) >= 0;
|
||||
let cached: CacheEntry<IInternalFileMatch>;
|
||||
let wasResolved: boolean;
|
||||
for (let previousSearch in cache.resultsToSearchCache) {
|
||||
// If we narrow down, we might be able to reuse the cached results
|
||||
if (searchValue.startsWith(previousSearch)) {
|
||||
if (hasPathSep && previousSearch.indexOf(path.sep) < 0) {
|
||||
continue; // since a path character widens the search for potential more matches, require it in previous search too
|
||||
}
|
||||
|
||||
const c = cache.resultsToSearchCache[previousSearch];
|
||||
c.finished.then(() => { wasResolved = false; });
|
||||
cached = c;
|
||||
wasResolved = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!cached) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return new Promise((c, e) => {
|
||||
cached.finished.then(cachedEntries => {
|
||||
const cacheFilterStartTime = Date.now();
|
||||
|
||||
// Pattern match on results
|
||||
let results: IInternalFileMatch[] = [];
|
||||
const normalizedSearchValueLowercase = strings.stripWildcards(searchValue).toLowerCase();
|
||||
for (let i = 0; i < cachedEntries.length; i++) {
|
||||
let entry = cachedEntries[i];
|
||||
|
||||
// Check if this entry is a match for the search value
|
||||
if (!strings.fuzzyContains(entry.relativePath, normalizedSearchValueLowercase)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
results.push(entry);
|
||||
}
|
||||
|
||||
c(results);
|
||||
}, e);
|
||||
});
|
||||
}
|
||||
|
||||
private doSearch(args: IProviderArgs, provider: IInternalFileSearchProvider, onResult: (result: IInternalFileMatch[]) => void, batchSize: number): Promise<void> {
|
||||
return new Promise<void>((c, e) => {
|
||||
let batch: IInternalFileMatch[] = [];
|
||||
const onProviderResult = (match: string) => {
|
||||
if (match) {
|
||||
const internalMatch: IInternalFileMatch = {
|
||||
relativePath: match,
|
||||
basename: path.basename(match)
|
||||
};
|
||||
|
||||
batch.push(internalMatch);
|
||||
if (batchSize > 0 && batch.length >= batchSize) {
|
||||
onResult(batch);
|
||||
batch = [];
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
provider.provideFileSearchResults(args.options, { report: onProviderResult }, args.token).then(() => {
|
||||
if (batch.length) {
|
||||
onResult(batch);
|
||||
}
|
||||
|
||||
c();
|
||||
}, error => {
|
||||
if (batch.length) {
|
||||
onResult(batch);
|
||||
}
|
||||
|
||||
e(error);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
public clearCache(cacheKey: string): Promise<void> {
|
||||
delete this.caches[cacheKey];
|
||||
return Promise.resolve(undefined);
|
||||
}
|
||||
}
|
||||
|
||||
interface IInternalFileMatch {
|
||||
relativePath?: string; // Not present for extraFiles or absolute path matches
|
||||
basename: string;
|
||||
}
|
||||
|
||||
interface CacheEntry<T> {
|
||||
finished: Promise<T[]>;
|
||||
}
|
||||
|
||||
class Cache {
|
||||
public resultsToSearchCache: { [searchValue: string]: CacheEntry<IInternalFileMatch> } = Object.create(null);
|
||||
public scorerCache: ScorerCache = Object.create(null);
|
||||
}
|
||||
|
||||
const FileMatchItemAccessor = new class implements IItemAccessor<IInternalFileMatch> {
|
||||
|
||||
public getItemLabel(match: IInternalFileMatch): string {
|
||||
return match.basename; // e.g. myFile.txt
|
||||
}
|
||||
|
||||
public getItemDescription(match: IInternalFileMatch): string {
|
||||
return match.relativePath.substr(0, match.relativePath.length - match.basename.length - 1); // e.g. some/path/to/file
|
||||
}
|
||||
|
||||
public getItemPath(match: IInternalFileMatch): string {
|
||||
return match.relativePath; // e.g. some/path/to/file/myFile.txt
|
||||
}
|
||||
};
|
75
extensions/search-rg/src/common/arrays.ts
Normal file
75
extensions/search-rg/src/common/arrays.ts
Normal file
|
@ -0,0 +1,75 @@
|
|||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
/**
|
||||
* Asynchronous variant of `top()` allowing for splitting up work in batches between which the event loop can run.
|
||||
*
|
||||
* Returns the top N elements from the array.
|
||||
*
|
||||
* Faster than sorting the entire array when the array is a lot larger than N.
|
||||
*
|
||||
* @param array The unsorted array.
|
||||
* @param compare A sort function for the elements.
|
||||
* @param n The number of elements to return.
|
||||
* @param batch The number of elements to examine before yielding to the event loop.
|
||||
* @return The first n elemnts from array when sorted with compare.
|
||||
*/
|
||||
export function topAsync<T>(array: T[], compare: (a: T, b: T) => number, n: number, batch: number): Promise<T[]> {
|
||||
// TODO@roblou cancellation
|
||||
|
||||
if (n === 0) {
|
||||
return Promise.resolve([]);
|
||||
}
|
||||
let canceled = false;
|
||||
return new Promise((resolve, reject) => {
|
||||
(async () => {
|
||||
const o = array.length;
|
||||
const result = array.slice(0, n).sort(compare);
|
||||
for (let i = n, m = Math.min(n + batch, o); i < o; i = m, m = Math.min(m + batch, o)) {
|
||||
if (i > n) {
|
||||
await new Promise(resolve => setTimeout(resolve, 0)); // nextTick() would starve I/O.
|
||||
}
|
||||
if (canceled) {
|
||||
throw new Error('canceled');
|
||||
}
|
||||
topStep(array, compare, result, i, m);
|
||||
}
|
||||
return result;
|
||||
})()
|
||||
.then(resolve, reject);
|
||||
});
|
||||
}
|
||||
|
||||
function topStep<T>(array: T[], compare: (a: T, b: T) => number, result: T[], i: number, m: number): void {
|
||||
for (const n = result.length; i < m; i++) {
|
||||
const element = array[i];
|
||||
if (compare(element, result[n - 1]) < 0) {
|
||||
result.pop();
|
||||
const j = findFirstInSorted(result, e => compare(element, e) < 0);
|
||||
result.splice(j, 0, element);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Takes a sorted array and a function p. The array is sorted in such a way that all elements where p(x) is false
|
||||
* are located before all elements where p(x) is true.
|
||||
* @returns the least x for which p(x) is true or array.length if no element fullfills the given function.
|
||||
*/
|
||||
export function findFirstInSorted<T>(array: T[], p: (x: T) => boolean): number {
|
||||
let low = 0, high = array.length;
|
||||
if (high === 0) {
|
||||
return 0; // no children
|
||||
}
|
||||
while (low < high) {
|
||||
let mid = Math.floor((low + high) / 2);
|
||||
if (p(array[mid])) {
|
||||
high = mid;
|
||||
} else {
|
||||
low = mid + 1;
|
||||
}
|
||||
}
|
||||
return low;
|
||||
}
|
422
extensions/search-rg/src/common/charCode.ts
Normal file
422
extensions/search-rg/src/common/charCode.ts
Normal file
|
@ -0,0 +1,422 @@
|
|||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
'use strict';
|
||||
|
||||
// Names from https://blog.codinghorror.com/ascii-pronunciation-rules-for-programmers/
|
||||
|
||||
/**
|
||||
* An inlined enum containing useful character codes (to be used with String.charCodeAt).
|
||||
* Please leave the const keyword such that it gets inlined when compiled to JavaScript!
|
||||
*/
|
||||
export const enum CharCode {
|
||||
Null = 0,
|
||||
/**
|
||||
* The `\t` character.
|
||||
*/
|
||||
Tab = 9,
|
||||
/**
|
||||
* The `\n` character.
|
||||
*/
|
||||
LineFeed = 10,
|
||||
/**
|
||||
* The `\r` character.
|
||||
*/
|
||||
CarriageReturn = 13,
|
||||
Space = 32,
|
||||
/**
|
||||
* The `!` character.
|
||||
*/
|
||||
ExclamationMark = 33,
|
||||
/**
|
||||
* The `"` character.
|
||||
*/
|
||||
DoubleQuote = 34,
|
||||
/**
|
||||
* The `#` character.
|
||||
*/
|
||||
Hash = 35,
|
||||
/**
|
||||
* The `$` character.
|
||||
*/
|
||||
DollarSign = 36,
|
||||
/**
|
||||
* The `%` character.
|
||||
*/
|
||||
PercentSign = 37,
|
||||
/**
|
||||
* The `&` character.
|
||||
*/
|
||||
Ampersand = 38,
|
||||
/**
|
||||
* The `'` character.
|
||||
*/
|
||||
SingleQuote = 39,
|
||||
/**
|
||||
* The `(` character.
|
||||
*/
|
||||
OpenParen = 40,
|
||||
/**
|
||||
* The `)` character.
|
||||
*/
|
||||
CloseParen = 41,
|
||||
/**
|
||||
* The `*` character.
|
||||
*/
|
||||
Asterisk = 42,
|
||||
/**
|
||||
* The `+` character.
|
||||
*/
|
||||
Plus = 43,
|
||||
/**
|
||||
* The `,` character.
|
||||
*/
|
||||
Comma = 44,
|
||||
/**
|
||||
* The `-` character.
|
||||
*/
|
||||
Dash = 45,
|
||||
/**
|
||||
* The `.` character.
|
||||
*/
|
||||
Period = 46,
|
||||
/**
|
||||
* The `/` character.
|
||||
*/
|
||||
Slash = 47,
|
||||
|
||||
Digit0 = 48,
|
||||
Digit1 = 49,
|
||||
Digit2 = 50,
|
||||
Digit3 = 51,
|
||||
Digit4 = 52,
|
||||
Digit5 = 53,
|
||||
Digit6 = 54,
|
||||
Digit7 = 55,
|
||||
Digit8 = 56,
|
||||
Digit9 = 57,
|
||||
|
||||
/**
|
||||
* The `:` character.
|
||||
*/
|
||||
Colon = 58,
|
||||
/**
|
||||
* The `;` character.
|
||||
*/
|
||||
Semicolon = 59,
|
||||
/**
|
||||
* The `<` character.
|
||||
*/
|
||||
LessThan = 60,
|
||||
/**
|
||||
* The `=` character.
|
||||
*/
|
||||
Equals = 61,
|
||||
/**
|
||||
* The `>` character.
|
||||
*/
|
||||
GreaterThan = 62,
|
||||
/**
|
||||
* The `?` character.
|
||||
*/
|
||||
QuestionMark = 63,
|
||||
/**
|
||||
* The `@` character.
|
||||
*/
|
||||
AtSign = 64,
|
||||
|
||||
A = 65,
|
||||
B = 66,
|
||||
C = 67,
|
||||
D = 68,
|
||||
E = 69,
|
||||
F = 70,
|
||||
G = 71,
|
||||
H = 72,
|
||||
I = 73,
|
||||
J = 74,
|
||||
K = 75,
|
||||
L = 76,
|
||||
M = 77,
|
||||
N = 78,
|
||||
O = 79,
|
||||
P = 80,
|
||||
Q = 81,
|
||||
R = 82,
|
||||
S = 83,
|
||||
T = 84,
|
||||
U = 85,
|
||||
V = 86,
|
||||
W = 87,
|
||||
X = 88,
|
||||
Y = 89,
|
||||
Z = 90,
|
||||
|
||||
/**
|
||||
* The `[` character.
|
||||
*/
|
||||
OpenSquareBracket = 91,
|
||||
/**
|
||||
* The `\` character.
|
||||
*/
|
||||
Backslash = 92,
|
||||
/**
|
||||
* The `]` character.
|
||||
*/
|
||||
CloseSquareBracket = 93,
|
||||
/**
|
||||
* The `^` character.
|
||||
*/
|
||||
Caret = 94,
|
||||
/**
|
||||
* The `_` character.
|
||||
*/
|
||||
Underline = 95,
|
||||
/**
|
||||
* The ``(`)`` character.
|
||||
*/
|
||||
BackTick = 96,
|
||||
|
||||
a = 97,
|
||||
b = 98,
|
||||
c = 99,
|
||||
d = 100,
|
||||
e = 101,
|
||||
f = 102,
|
||||
g = 103,
|
||||
h = 104,
|
||||
i = 105,
|
||||
j = 106,
|
||||
k = 107,
|
||||
l = 108,
|
||||
m = 109,
|
||||
n = 110,
|
||||
o = 111,
|
||||
p = 112,
|
||||
q = 113,
|
||||
r = 114,
|
||||
s = 115,
|
||||
t = 116,
|
||||
u = 117,
|
||||
v = 118,
|
||||
w = 119,
|
||||
x = 120,
|
||||
y = 121,
|
||||
z = 122,
|
||||
|
||||
/**
|
||||
* The `{` character.
|
||||
*/
|
||||
OpenCurlyBrace = 123,
|
||||
/**
|
||||
* The `|` character.
|
||||
*/
|
||||
Pipe = 124,
|
||||
/**
|
||||
* The `}` character.
|
||||
*/
|
||||
CloseCurlyBrace = 125,
|
||||
/**
|
||||
* The `~` character.
|
||||
*/
|
||||
Tilde = 126,
|
||||
|
||||
U_Combining_Grave_Accent = 0x0300, // U+0300 Combining Grave Accent
|
||||
U_Combining_Acute_Accent = 0x0301, // U+0301 Combining Acute Accent
|
||||
U_Combining_Circumflex_Accent = 0x0302, // U+0302 Combining Circumflex Accent
|
||||
U_Combining_Tilde = 0x0303, // U+0303 Combining Tilde
|
||||
U_Combining_Macron = 0x0304, // U+0304 Combining Macron
|
||||
U_Combining_Overline = 0x0305, // U+0305 Combining Overline
|
||||
U_Combining_Breve = 0x0306, // U+0306 Combining Breve
|
||||
U_Combining_Dot_Above = 0x0307, // U+0307 Combining Dot Above
|
||||
U_Combining_Diaeresis = 0x0308, // U+0308 Combining Diaeresis
|
||||
U_Combining_Hook_Above = 0x0309, // U+0309 Combining Hook Above
|
||||
U_Combining_Ring_Above = 0x030A, // U+030A Combining Ring Above
|
||||
U_Combining_Double_Acute_Accent = 0x030B, // U+030B Combining Double Acute Accent
|
||||
U_Combining_Caron = 0x030C, // U+030C Combining Caron
|
||||
U_Combining_Vertical_Line_Above = 0x030D, // U+030D Combining Vertical Line Above
|
||||
U_Combining_Double_Vertical_Line_Above = 0x030E, // U+030E Combining Double Vertical Line Above
|
||||
U_Combining_Double_Grave_Accent = 0x030F, // U+030F Combining Double Grave Accent
|
||||
U_Combining_Candrabindu = 0x0310, // U+0310 Combining Candrabindu
|
||||
U_Combining_Inverted_Breve = 0x0311, // U+0311 Combining Inverted Breve
|
||||
U_Combining_Turned_Comma_Above = 0x0312, // U+0312 Combining Turned Comma Above
|
||||
U_Combining_Comma_Above = 0x0313, // U+0313 Combining Comma Above
|
||||
U_Combining_Reversed_Comma_Above = 0x0314, // U+0314 Combining Reversed Comma Above
|
||||
U_Combining_Comma_Above_Right = 0x0315, // U+0315 Combining Comma Above Right
|
||||
U_Combining_Grave_Accent_Below = 0x0316, // U+0316 Combining Grave Accent Below
|
||||
U_Combining_Acute_Accent_Below = 0x0317, // U+0317 Combining Acute Accent Below
|
||||
U_Combining_Left_Tack_Below = 0x0318, // U+0318 Combining Left Tack Below
|
||||
U_Combining_Right_Tack_Below = 0x0319, // U+0319 Combining Right Tack Below
|
||||
U_Combining_Left_Angle_Above = 0x031A, // U+031A Combining Left Angle Above
|
||||
U_Combining_Horn = 0x031B, // U+031B Combining Horn
|
||||
U_Combining_Left_Half_Ring_Below = 0x031C, // U+031C Combining Left Half Ring Below
|
||||
U_Combining_Up_Tack_Below = 0x031D, // U+031D Combining Up Tack Below
|
||||
U_Combining_Down_Tack_Below = 0x031E, // U+031E Combining Down Tack Below
|
||||
U_Combining_Plus_Sign_Below = 0x031F, // U+031F Combining Plus Sign Below
|
||||
U_Combining_Minus_Sign_Below = 0x0320, // U+0320 Combining Minus Sign Below
|
||||
U_Combining_Palatalized_Hook_Below = 0x0321, // U+0321 Combining Palatalized Hook Below
|
||||
U_Combining_Retroflex_Hook_Below = 0x0322, // U+0322 Combining Retroflex Hook Below
|
||||
U_Combining_Dot_Below = 0x0323, // U+0323 Combining Dot Below
|
||||
U_Combining_Diaeresis_Below = 0x0324, // U+0324 Combining Diaeresis Below
|
||||
U_Combining_Ring_Below = 0x0325, // U+0325 Combining Ring Below
|
||||
U_Combining_Comma_Below = 0x0326, // U+0326 Combining Comma Below
|
||||
U_Combining_Cedilla = 0x0327, // U+0327 Combining Cedilla
|
||||
U_Combining_Ogonek = 0x0328, // U+0328 Combining Ogonek
|
||||
U_Combining_Vertical_Line_Below = 0x0329, // U+0329 Combining Vertical Line Below
|
||||
U_Combining_Bridge_Below = 0x032A, // U+032A Combining Bridge Below
|
||||
U_Combining_Inverted_Double_Arch_Below = 0x032B, // U+032B Combining Inverted Double Arch Below
|
||||
U_Combining_Caron_Below = 0x032C, // U+032C Combining Caron Below
|
||||
U_Combining_Circumflex_Accent_Below = 0x032D, // U+032D Combining Circumflex Accent Below
|
||||
U_Combining_Breve_Below = 0x032E, // U+032E Combining Breve Below
|
||||
U_Combining_Inverted_Breve_Below = 0x032F, // U+032F Combining Inverted Breve Below
|
||||
U_Combining_Tilde_Below = 0x0330, // U+0330 Combining Tilde Below
|
||||
U_Combining_Macron_Below = 0x0331, // U+0331 Combining Macron Below
|
||||
U_Combining_Low_Line = 0x0332, // U+0332 Combining Low Line
|
||||
U_Combining_Double_Low_Line = 0x0333, // U+0333 Combining Double Low Line
|
||||
U_Combining_Tilde_Overlay = 0x0334, // U+0334 Combining Tilde Overlay
|
||||
U_Combining_Short_Stroke_Overlay = 0x0335, // U+0335 Combining Short Stroke Overlay
|
||||
U_Combining_Long_Stroke_Overlay = 0x0336, // U+0336 Combining Long Stroke Overlay
|
||||
U_Combining_Short_Solidus_Overlay = 0x0337, // U+0337 Combining Short Solidus Overlay
|
||||
U_Combining_Long_Solidus_Overlay = 0x0338, // U+0338 Combining Long Solidus Overlay
|
||||
U_Combining_Right_Half_Ring_Below = 0x0339, // U+0339 Combining Right Half Ring Below
|
||||
U_Combining_Inverted_Bridge_Below = 0x033A, // U+033A Combining Inverted Bridge Below
|
||||
U_Combining_Square_Below = 0x033B, // U+033B Combining Square Below
|
||||
U_Combining_Seagull_Below = 0x033C, // U+033C Combining Seagull Below
|
||||
U_Combining_X_Above = 0x033D, // U+033D Combining X Above
|
||||
U_Combining_Vertical_Tilde = 0x033E, // U+033E Combining Vertical Tilde
|
||||
U_Combining_Double_Overline = 0x033F, // U+033F Combining Double Overline
|
||||
U_Combining_Grave_Tone_Mark = 0x0340, // U+0340 Combining Grave Tone Mark
|
||||
U_Combining_Acute_Tone_Mark = 0x0341, // U+0341 Combining Acute Tone Mark
|
||||
U_Combining_Greek_Perispomeni = 0x0342, // U+0342 Combining Greek Perispomeni
|
||||
U_Combining_Greek_Koronis = 0x0343, // U+0343 Combining Greek Koronis
|
||||
U_Combining_Greek_Dialytika_Tonos = 0x0344, // U+0344 Combining Greek Dialytika Tonos
|
||||
U_Combining_Greek_Ypogegrammeni = 0x0345, // U+0345 Combining Greek Ypogegrammeni
|
||||
U_Combining_Bridge_Above = 0x0346, // U+0346 Combining Bridge Above
|
||||
U_Combining_Equals_Sign_Below = 0x0347, // U+0347 Combining Equals Sign Below
|
||||
U_Combining_Double_Vertical_Line_Below = 0x0348, // U+0348 Combining Double Vertical Line Below
|
||||
U_Combining_Left_Angle_Below = 0x0349, // U+0349 Combining Left Angle Below
|
||||
U_Combining_Not_Tilde_Above = 0x034A, // U+034A Combining Not Tilde Above
|
||||
U_Combining_Homothetic_Above = 0x034B, // U+034B Combining Homothetic Above
|
||||
U_Combining_Almost_Equal_To_Above = 0x034C, // U+034C Combining Almost Equal To Above
|
||||
U_Combining_Left_Right_Arrow_Below = 0x034D, // U+034D Combining Left Right Arrow Below
|
||||
U_Combining_Upwards_Arrow_Below = 0x034E, // U+034E Combining Upwards Arrow Below
|
||||
U_Combining_Grapheme_Joiner = 0x034F, // U+034F Combining Grapheme Joiner
|
||||
U_Combining_Right_Arrowhead_Above = 0x0350, // U+0350 Combining Right Arrowhead Above
|
||||
U_Combining_Left_Half_Ring_Above = 0x0351, // U+0351 Combining Left Half Ring Above
|
||||
U_Combining_Fermata = 0x0352, // U+0352 Combining Fermata
|
||||
U_Combining_X_Below = 0x0353, // U+0353 Combining X Below
|
||||
U_Combining_Left_Arrowhead_Below = 0x0354, // U+0354 Combining Left Arrowhead Below
|
||||
U_Combining_Right_Arrowhead_Below = 0x0355, // U+0355 Combining Right Arrowhead Below
|
||||
U_Combining_Right_Arrowhead_And_Up_Arrowhead_Below = 0x0356, // U+0356 Combining Right Arrowhead And Up Arrowhead Below
|
||||
U_Combining_Right_Half_Ring_Above = 0x0357, // U+0357 Combining Right Half Ring Above
|
||||
U_Combining_Dot_Above_Right = 0x0358, // U+0358 Combining Dot Above Right
|
||||
U_Combining_Asterisk_Below = 0x0359, // U+0359 Combining Asterisk Below
|
||||
U_Combining_Double_Ring_Below = 0x035A, // U+035A Combining Double Ring Below
|
||||
U_Combining_Zigzag_Above = 0x035B, // U+035B Combining Zigzag Above
|
||||
U_Combining_Double_Breve_Below = 0x035C, // U+035C Combining Double Breve Below
|
||||
U_Combining_Double_Breve = 0x035D, // U+035D Combining Double Breve
|
||||
U_Combining_Double_Macron = 0x035E, // U+035E Combining Double Macron
|
||||
U_Combining_Double_Macron_Below = 0x035F, // U+035F Combining Double Macron Below
|
||||
U_Combining_Double_Tilde = 0x0360, // U+0360 Combining Double Tilde
|
||||
U_Combining_Double_Inverted_Breve = 0x0361, // U+0361 Combining Double Inverted Breve
|
||||
U_Combining_Double_Rightwards_Arrow_Below = 0x0362, // U+0362 Combining Double Rightwards Arrow Below
|
||||
U_Combining_Latin_Small_Letter_A = 0x0363, // U+0363 Combining Latin Small Letter A
|
||||
U_Combining_Latin_Small_Letter_E = 0x0364, // U+0364 Combining Latin Small Letter E
|
||||
U_Combining_Latin_Small_Letter_I = 0x0365, // U+0365 Combining Latin Small Letter I
|
||||
U_Combining_Latin_Small_Letter_O = 0x0366, // U+0366 Combining Latin Small Letter O
|
||||
U_Combining_Latin_Small_Letter_U = 0x0367, // U+0367 Combining Latin Small Letter U
|
||||
U_Combining_Latin_Small_Letter_C = 0x0368, // U+0368 Combining Latin Small Letter C
|
||||
U_Combining_Latin_Small_Letter_D = 0x0369, // U+0369 Combining Latin Small Letter D
|
||||
U_Combining_Latin_Small_Letter_H = 0x036A, // U+036A Combining Latin Small Letter H
|
||||
U_Combining_Latin_Small_Letter_M = 0x036B, // U+036B Combining Latin Small Letter M
|
||||
U_Combining_Latin_Small_Letter_R = 0x036C, // U+036C Combining Latin Small Letter R
|
||||
U_Combining_Latin_Small_Letter_T = 0x036D, // U+036D Combining Latin Small Letter T
|
||||
U_Combining_Latin_Small_Letter_V = 0x036E, // U+036E Combining Latin Small Letter V
|
||||
U_Combining_Latin_Small_Letter_X = 0x036F, // U+036F Combining Latin Small Letter X
|
||||
|
||||
/**
|
||||
* Unicode Character 'LINE SEPARATOR' (U+2028)
|
||||
* http://www.fileformat.info/info/unicode/char/2028/index.htm
|
||||
*/
|
||||
LINE_SEPARATOR_2028 = 8232,
|
||||
|
||||
// http://www.fileformat.info/info/unicode/category/Sk/list.htm
|
||||
U_CIRCUMFLEX = 0x005E, // U+005E CIRCUMFLEX
|
||||
U_GRAVE_ACCENT = 0x0060, // U+0060 GRAVE ACCENT
|
||||
U_DIAERESIS = 0x00A8, // U+00A8 DIAERESIS
|
||||
U_MACRON = 0x00AF, // U+00AF MACRON
|
||||
U_ACUTE_ACCENT = 0x00B4, // U+00B4 ACUTE ACCENT
|
||||
U_CEDILLA = 0x00B8, // U+00B8 CEDILLA
|
||||
U_MODIFIER_LETTER_LEFT_ARROWHEAD = 0x02C2, // U+02C2 MODIFIER LETTER LEFT ARROWHEAD
|
||||
U_MODIFIER_LETTER_RIGHT_ARROWHEAD = 0x02C3, // U+02C3 MODIFIER LETTER RIGHT ARROWHEAD
|
||||
U_MODIFIER_LETTER_UP_ARROWHEAD = 0x02C4, // U+02C4 MODIFIER LETTER UP ARROWHEAD
|
||||
U_MODIFIER_LETTER_DOWN_ARROWHEAD = 0x02C5, // U+02C5 MODIFIER LETTER DOWN ARROWHEAD
|
||||
U_MODIFIER_LETTER_CENTRED_RIGHT_HALF_RING = 0x02D2, // U+02D2 MODIFIER LETTER CENTRED RIGHT HALF RING
|
||||
U_MODIFIER_LETTER_CENTRED_LEFT_HALF_RING = 0x02D3, // U+02D3 MODIFIER LETTER CENTRED LEFT HALF RING
|
||||
U_MODIFIER_LETTER_UP_TACK = 0x02D4, // U+02D4 MODIFIER LETTER UP TACK
|
||||
U_MODIFIER_LETTER_DOWN_TACK = 0x02D5, // U+02D5 MODIFIER LETTER DOWN TACK
|
||||
U_MODIFIER_LETTER_PLUS_SIGN = 0x02D6, // U+02D6 MODIFIER LETTER PLUS SIGN
|
||||
U_MODIFIER_LETTER_MINUS_SIGN = 0x02D7, // U+02D7 MODIFIER LETTER MINUS SIGN
|
||||
U_BREVE = 0x02D8, // U+02D8 BREVE
|
||||
U_DOT_ABOVE = 0x02D9, // U+02D9 DOT ABOVE
|
||||
U_RING_ABOVE = 0x02DA, // U+02DA RING ABOVE
|
||||
U_OGONEK = 0x02DB, // U+02DB OGONEK
|
||||
U_SMALL_TILDE = 0x02DC, // U+02DC SMALL TILDE
|
||||
U_DOUBLE_ACUTE_ACCENT = 0x02DD, // U+02DD DOUBLE ACUTE ACCENT
|
||||
U_MODIFIER_LETTER_RHOTIC_HOOK = 0x02DE, // U+02DE MODIFIER LETTER RHOTIC HOOK
|
||||
U_MODIFIER_LETTER_CROSS_ACCENT = 0x02DF, // U+02DF MODIFIER LETTER CROSS ACCENT
|
||||
U_MODIFIER_LETTER_EXTRA_HIGH_TONE_BAR = 0x02E5, // U+02E5 MODIFIER LETTER EXTRA-HIGH TONE BAR
|
||||
U_MODIFIER_LETTER_HIGH_TONE_BAR = 0x02E6, // U+02E6 MODIFIER LETTER HIGH TONE BAR
|
||||
U_MODIFIER_LETTER_MID_TONE_BAR = 0x02E7, // U+02E7 MODIFIER LETTER MID TONE BAR
|
||||
U_MODIFIER_LETTER_LOW_TONE_BAR = 0x02E8, // U+02E8 MODIFIER LETTER LOW TONE BAR
|
||||
U_MODIFIER_LETTER_EXTRA_LOW_TONE_BAR = 0x02E9, // U+02E9 MODIFIER LETTER EXTRA-LOW TONE BAR
|
||||
U_MODIFIER_LETTER_YIN_DEPARTING_TONE_MARK = 0x02EA, // U+02EA MODIFIER LETTER YIN DEPARTING TONE MARK
|
||||
U_MODIFIER_LETTER_YANG_DEPARTING_TONE_MARK = 0x02EB, // U+02EB MODIFIER LETTER YANG DEPARTING TONE MARK
|
||||
U_MODIFIER_LETTER_UNASPIRATED = 0x02ED, // U+02ED MODIFIER LETTER UNASPIRATED
|
||||
U_MODIFIER_LETTER_LOW_DOWN_ARROWHEAD = 0x02EF, // U+02EF MODIFIER LETTER LOW DOWN ARROWHEAD
|
||||
U_MODIFIER_LETTER_LOW_UP_ARROWHEAD = 0x02F0, // U+02F0 MODIFIER LETTER LOW UP ARROWHEAD
|
||||
U_MODIFIER_LETTER_LOW_LEFT_ARROWHEAD = 0x02F1, // U+02F1 MODIFIER LETTER LOW LEFT ARROWHEAD
|
||||
U_MODIFIER_LETTER_LOW_RIGHT_ARROWHEAD = 0x02F2, // U+02F2 MODIFIER LETTER LOW RIGHT ARROWHEAD
|
||||
U_MODIFIER_LETTER_LOW_RING = 0x02F3, // U+02F3 MODIFIER LETTER LOW RING
|
||||
U_MODIFIER_LETTER_MIDDLE_GRAVE_ACCENT = 0x02F4, // U+02F4 MODIFIER LETTER MIDDLE GRAVE ACCENT
|
||||
U_MODIFIER_LETTER_MIDDLE_DOUBLE_GRAVE_ACCENT = 0x02F5, // U+02F5 MODIFIER LETTER MIDDLE DOUBLE GRAVE ACCENT
|
||||
U_MODIFIER_LETTER_MIDDLE_DOUBLE_ACUTE_ACCENT = 0x02F6, // U+02F6 MODIFIER LETTER MIDDLE DOUBLE ACUTE ACCENT
|
||||
U_MODIFIER_LETTER_LOW_TILDE = 0x02F7, // U+02F7 MODIFIER LETTER LOW TILDE
|
||||
U_MODIFIER_LETTER_RAISED_COLON = 0x02F8, // U+02F8 MODIFIER LETTER RAISED COLON
|
||||
U_MODIFIER_LETTER_BEGIN_HIGH_TONE = 0x02F9, // U+02F9 MODIFIER LETTER BEGIN HIGH TONE
|
||||
U_MODIFIER_LETTER_END_HIGH_TONE = 0x02FA, // U+02FA MODIFIER LETTER END HIGH TONE
|
||||
U_MODIFIER_LETTER_BEGIN_LOW_TONE = 0x02FB, // U+02FB MODIFIER LETTER BEGIN LOW TONE
|
||||
U_MODIFIER_LETTER_END_LOW_TONE = 0x02FC, // U+02FC MODIFIER LETTER END LOW TONE
|
||||
U_MODIFIER_LETTER_SHELF = 0x02FD, // U+02FD MODIFIER LETTER SHELF
|
||||
U_MODIFIER_LETTER_OPEN_SHELF = 0x02FE, // U+02FE MODIFIER LETTER OPEN SHELF
|
||||
U_MODIFIER_LETTER_LOW_LEFT_ARROW = 0x02FF, // U+02FF MODIFIER LETTER LOW LEFT ARROW
|
||||
U_GREEK_LOWER_NUMERAL_SIGN = 0x0375, // U+0375 GREEK LOWER NUMERAL SIGN
|
||||
U_GREEK_TONOS = 0x0384, // U+0384 GREEK TONOS
|
||||
U_GREEK_DIALYTIKA_TONOS = 0x0385, // U+0385 GREEK DIALYTIKA TONOS
|
||||
U_GREEK_KORONIS = 0x1FBD, // U+1FBD GREEK KORONIS
|
||||
U_GREEK_PSILI = 0x1FBF, // U+1FBF GREEK PSILI
|
||||
U_GREEK_PERISPOMENI = 0x1FC0, // U+1FC0 GREEK PERISPOMENI
|
||||
U_GREEK_DIALYTIKA_AND_PERISPOMENI = 0x1FC1, // U+1FC1 GREEK DIALYTIKA AND PERISPOMENI
|
||||
U_GREEK_PSILI_AND_VARIA = 0x1FCD, // U+1FCD GREEK PSILI AND VARIA
|
||||
U_GREEK_PSILI_AND_OXIA = 0x1FCE, // U+1FCE GREEK PSILI AND OXIA
|
||||
U_GREEK_PSILI_AND_PERISPOMENI = 0x1FCF, // U+1FCF GREEK PSILI AND PERISPOMENI
|
||||
U_GREEK_DASIA_AND_VARIA = 0x1FDD, // U+1FDD GREEK DASIA AND VARIA
|
||||
U_GREEK_DASIA_AND_OXIA = 0x1FDE, // U+1FDE GREEK DASIA AND OXIA
|
||||
U_GREEK_DASIA_AND_PERISPOMENI = 0x1FDF, // U+1FDF GREEK DASIA AND PERISPOMENI
|
||||
U_GREEK_DIALYTIKA_AND_VARIA = 0x1FED, // U+1FED GREEK DIALYTIKA AND VARIA
|
||||
U_GREEK_DIALYTIKA_AND_OXIA = 0x1FEE, // U+1FEE GREEK DIALYTIKA AND OXIA
|
||||
U_GREEK_VARIA = 0x1FEF, // U+1FEF GREEK VARIA
|
||||
U_GREEK_OXIA = 0x1FFD, // U+1FFD GREEK OXIA
|
||||
U_GREEK_DASIA = 0x1FFE, // U+1FFE GREEK DASIA
|
||||
|
||||
|
||||
U_OVERLINE = 0x203E, // Unicode Character 'OVERLINE'
|
||||
|
||||
/**
|
||||
* UTF-8 BOM
|
||||
* Unicode Character 'ZERO WIDTH NO-BREAK SPACE' (U+FEFF)
|
||||
* http://www.fileformat.info/info/unicode/char/feff/index.htm
|
||||
*/
|
||||
UTF8_BOM = 65279
|
||||
}
|
115
extensions/search-rg/src/common/comparers.ts
Normal file
115
extensions/search-rg/src/common/comparers.ts
Normal file
|
@ -0,0 +1,115 @@
|
|||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
'use strict';
|
||||
|
||||
import * as strings from './strings';
|
||||
|
||||
let intlFileNameCollator: Intl.Collator;
|
||||
let intlFileNameCollatorIsNumeric: boolean;
|
||||
|
||||
setFileNameComparer(new Intl.Collator(undefined, { numeric: true, sensitivity: 'base' }));
|
||||
|
||||
export function setFileNameComparer(collator: Intl.Collator): void {
|
||||
intlFileNameCollator = collator;
|
||||
intlFileNameCollatorIsNumeric = collator.resolvedOptions().numeric;
|
||||
}
|
||||
|
||||
export function compareFileNames(one: string, other: string, caseSensitive = false): number {
|
||||
if (intlFileNameCollator) {
|
||||
const a = one || '';
|
||||
const b = other || '';
|
||||
const result = intlFileNameCollator.compare(a, b);
|
||||
|
||||
// Using the numeric option in the collator will
|
||||
// make compare(`foo1`, `foo01`) === 0. We must disambiguate.
|
||||
if (intlFileNameCollatorIsNumeric && result === 0 && a !== b) {
|
||||
return a < b ? -1 : 1;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
return noIntlCompareFileNames(one, other, caseSensitive);
|
||||
}
|
||||
|
||||
const FileNameMatch = /^(.*?)(\.([^.]*))?$/;
|
||||
|
||||
export function noIntlCompareFileNames(one: string, other: string, caseSensitive = false): number {
|
||||
if (!caseSensitive) {
|
||||
one = one && one.toLowerCase();
|
||||
other = other && other.toLowerCase();
|
||||
}
|
||||
|
||||
const [oneName, oneExtension] = extractNameAndExtension(one);
|
||||
const [otherName, otherExtension] = extractNameAndExtension(other);
|
||||
|
||||
if (oneName !== otherName) {
|
||||
return oneName < otherName ? -1 : 1;
|
||||
}
|
||||
|
||||
if (oneExtension === otherExtension) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
return oneExtension < otherExtension ? -1 : 1;
|
||||
}
|
||||
|
||||
function extractNameAndExtension(str?: string): [string, string] {
|
||||
const match = str ? FileNameMatch.exec(str) : [] as RegExpExecArray;
|
||||
|
||||
return [(match && match[1]) || '', (match && match[3]) || ''];
|
||||
}
|
||||
|
||||
export function compareAnything(one: string, other: string, lookFor: string): number {
|
||||
let elementAName = one.toLowerCase();
|
||||
let elementBName = other.toLowerCase();
|
||||
|
||||
// Sort prefix matches over non prefix matches
|
||||
const prefixCompare = compareByPrefix(one, other, lookFor);
|
||||
if (prefixCompare) {
|
||||
return prefixCompare;
|
||||
}
|
||||
|
||||
// Sort suffix matches over non suffix matches
|
||||
let elementASuffixMatch = strings.endsWith(elementAName, lookFor);
|
||||
let elementBSuffixMatch = strings.endsWith(elementBName, lookFor);
|
||||
if (elementASuffixMatch !== elementBSuffixMatch) {
|
||||
return elementASuffixMatch ? -1 : 1;
|
||||
}
|
||||
|
||||
// Understand file names
|
||||
let r = compareFileNames(elementAName, elementBName);
|
||||
if (r !== 0) {
|
||||
return r;
|
||||
}
|
||||
|
||||
// Compare by name
|
||||
return elementAName.localeCompare(elementBName);
|
||||
}
|
||||
|
||||
export function compareByPrefix(one: string, other: string, lookFor: string): number {
|
||||
let elementAName = one.toLowerCase();
|
||||
let elementBName = other.toLowerCase();
|
||||
|
||||
// Sort prefix matches over non prefix matches
|
||||
let elementAPrefixMatch = strings.startsWith(elementAName, lookFor);
|
||||
let elementBPrefixMatch = strings.startsWith(elementBName, lookFor);
|
||||
if (elementAPrefixMatch !== elementBPrefixMatch) {
|
||||
return elementAPrefixMatch ? -1 : 1;
|
||||
}
|
||||
|
||||
// Same prefix: Sort shorter matches to the top to have those on top that match more precisely
|
||||
else if (elementAPrefixMatch && elementBPrefixMatch) {
|
||||
if (elementAName.length < elementBName.length) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (elementAName.length > elementBName.length) {
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
619
extensions/search-rg/src/common/fileSearchScorer.ts
Normal file
619
extensions/search-rg/src/common/fileSearchScorer.ts
Normal file
|
@ -0,0 +1,619 @@
|
|||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
'use strict';
|
||||
|
||||
import { stripWildcards, equalsIgnoreCase } from './strings';
|
||||
import { matchesPrefix, matchesCamelCase, createMatches, IMatch, isUpper } from './filters';
|
||||
import { compareAnything } from './comparers';
|
||||
import { CharCode } from './charCode';
|
||||
|
||||
const isWindows = process.platform === 'win32';
|
||||
const isMacintosh = (process.platform === 'darwin');
|
||||
const isLinux = (process.platform === 'linux');
|
||||
|
||||
const nativeSep = isWindows ? '\\' : '/';
|
||||
|
||||
export type Score = [number /* score */, number[] /* match positions */];
|
||||
export type ScorerCache = { [key: string]: IItemScore };
|
||||
|
||||
const NO_MATCH = 0;
|
||||
const NO_SCORE: Score = [NO_MATCH, []];
|
||||
|
||||
// const DEBUG = false;
|
||||
// const DEBUG_MATRIX = false;
|
||||
|
||||
export function score(target: string, query: string, queryLower: string, fuzzy: boolean): Score {
|
||||
if (!target || !query) {
|
||||
return NO_SCORE; // return early if target or query are undefined
|
||||
}
|
||||
|
||||
const targetLength = target.length;
|
||||
const queryLength = query.length;
|
||||
|
||||
if (targetLength < queryLength) {
|
||||
return NO_SCORE; // impossible for query to be contained in target
|
||||
}
|
||||
|
||||
// if (DEBUG) {
|
||||
// console.group(`Target: ${target}, Query: ${query}`);
|
||||
// }
|
||||
|
||||
const targetLower = target.toLowerCase();
|
||||
|
||||
// When not searching fuzzy, we require the query to be contained fully
|
||||
// in the target string contiguously.
|
||||
if (!fuzzy) {
|
||||
const indexOfQueryInTarget = targetLower.indexOf(queryLower);
|
||||
if (indexOfQueryInTarget === -1) {
|
||||
// if (DEBUG) {
|
||||
// console.log(`Characters not matching consecutively ${queryLower} within ${targetLower}`);
|
||||
// }
|
||||
|
||||
return NO_SCORE;
|
||||
}
|
||||
}
|
||||
|
||||
const res = doScore(query, queryLower, queryLength, target, targetLower, targetLength);
|
||||
|
||||
// if (DEBUG) {
|
||||
// console.log(`%cFinal Score: ${res[0]}`, 'font-weight: bold');
|
||||
// console.groupEnd();
|
||||
// }
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
function doScore(query: string, queryLower: string, queryLength: number, target: string, targetLower: string, targetLength: number): [number, number[]] {
|
||||
const scores = [];
|
||||
const matches = [];
|
||||
|
||||
//
|
||||
// Build Scorer Matrix:
|
||||
//
|
||||
// The matrix is composed of query q and target t. For each index we score
|
||||
// q[i] with t[i] and compare that with the previous score. If the score is
|
||||
// equal or larger, we keep the match. In addition to the score, we also keep
|
||||
// the length of the consecutive matches to use as boost for the score.
|
||||
//
|
||||
// t a r g e t
|
||||
// q
|
||||
// u
|
||||
// e
|
||||
// r
|
||||
// y
|
||||
//
|
||||
for (let queryIndex = 0; queryIndex < queryLength; queryIndex++) {
|
||||
for (let targetIndex = 0; targetIndex < targetLength; targetIndex++) {
|
||||
const currentIndex = queryIndex * targetLength + targetIndex;
|
||||
const leftIndex = currentIndex - 1;
|
||||
const diagIndex = (queryIndex - 1) * targetLength + targetIndex - 1;
|
||||
|
||||
const leftScore: number = targetIndex > 0 ? scores[leftIndex] : 0;
|
||||
const diagScore: number = queryIndex > 0 && targetIndex > 0 ? scores[diagIndex] : 0;
|
||||
|
||||
const matchesSequenceLength: number = queryIndex > 0 && targetIndex > 0 ? matches[diagIndex] : 0;
|
||||
|
||||
// If we are not matching on the first query character any more, we only produce a
|
||||
// score if we had a score previously for the last query index (by looking at the diagScore).
|
||||
// This makes sure that the query always matches in sequence on the target. For example
|
||||
// given a target of "ede" and a query of "de", we would otherwise produce a wrong high score
|
||||
// for query[1] ("e") matching on target[0] ("e") because of the "beginning of word" boost.
|
||||
let score: number;
|
||||
if (!diagScore && queryIndex > 0) {
|
||||
score = 0;
|
||||
} else {
|
||||
score = computeCharScore(query, queryLower, queryIndex, target, targetLower, targetIndex, matchesSequenceLength);
|
||||
}
|
||||
|
||||
// We have a score and its equal or larger than the left score
|
||||
// Match: sequence continues growing from previous diag value
|
||||
// Score: increases by diag score value
|
||||
if (score && diagScore + score >= leftScore) {
|
||||
matches[currentIndex] = matchesSequenceLength + 1;
|
||||
scores[currentIndex] = diagScore + score;
|
||||
}
|
||||
|
||||
// We either have no score or the score is lower than the left score
|
||||
// Match: reset to 0
|
||||
// Score: pick up from left hand side
|
||||
else {
|
||||
matches[currentIndex] = NO_MATCH;
|
||||
scores[currentIndex] = leftScore;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Restore Positions (starting from bottom right of matrix)
|
||||
const positions = [];
|
||||
let queryIndex = queryLength - 1;
|
||||
let targetIndex = targetLength - 1;
|
||||
while (queryIndex >= 0 && targetIndex >= 0) {
|
||||
const currentIndex = queryIndex * targetLength + targetIndex;
|
||||
const match = matches[currentIndex];
|
||||
if (match === NO_MATCH) {
|
||||
targetIndex--; // go left
|
||||
} else {
|
||||
positions.push(targetIndex);
|
||||
|
||||
// go up and left
|
||||
queryIndex--;
|
||||
targetIndex--;
|
||||
}
|
||||
}
|
||||
|
||||
// Print matrix
|
||||
// if (DEBUG_MATRIX) {
|
||||
// printMatrix(query, target, matches, scores);
|
||||
// }
|
||||
|
||||
return [scores[queryLength * targetLength - 1], positions.reverse()];
|
||||
}
|
||||
|
||||
function computeCharScore(query: string, queryLower: string, queryIndex: number, target: string, targetLower: string, targetIndex: number, matchesSequenceLength: number): number {
|
||||
let score = 0;
|
||||
|
||||
if (queryLower[queryIndex] !== targetLower[targetIndex]) {
|
||||
return score; // no match of characters
|
||||
}
|
||||
|
||||
// Character match bonus
|
||||
score += 1;
|
||||
|
||||
// if (DEBUG) {
|
||||
// console.groupCollapsed(`%cCharacter match bonus: +1 (char: ${queryLower[queryIndex]} at index ${targetIndex}, total score: ${score})`, 'font-weight: normal');
|
||||
// }
|
||||
|
||||
// Consecutive match bonus
|
||||
if (matchesSequenceLength > 0) {
|
||||
score += (matchesSequenceLength * 5);
|
||||
|
||||
// if (DEBUG) {
|
||||
// console.log('Consecutive match bonus: ' + (matchesSequenceLength * 5));
|
||||
// }
|
||||
}
|
||||
|
||||
// Same case bonus
|
||||
if (query[queryIndex] === target[targetIndex]) {
|
||||
score += 1;
|
||||
|
||||
// if (DEBUG) {
|
||||
// console.log('Same case bonus: +1');
|
||||
// }
|
||||
}
|
||||
|
||||
// Start of word bonus
|
||||
if (targetIndex === 0) {
|
||||
score += 8;
|
||||
|
||||
// if (DEBUG) {
|
||||
// console.log('Start of word bonus: +8');
|
||||
// }
|
||||
}
|
||||
|
||||
else {
|
||||
|
||||
// After separator bonus
|
||||
const separatorBonus = scoreSeparatorAtPos(target.charCodeAt(targetIndex - 1));
|
||||
if (separatorBonus) {
|
||||
score += separatorBonus;
|
||||
|
||||
// if (DEBUG) {
|
||||
// console.log('After separtor bonus: +4');
|
||||
// }
|
||||
}
|
||||
|
||||
// Inside word upper case bonus (camel case)
|
||||
else if (isUpper(target.charCodeAt(targetIndex))) {
|
||||
score += 1;
|
||||
|
||||
// if (DEBUG) {
|
||||
// console.log('Inside word upper case bonus: +1');
|
||||
// }
|
||||
}
|
||||
}
|
||||
|
||||
// if (DEBUG) {
|
||||
// console.groupEnd();
|
||||
// }
|
||||
|
||||
return score;
|
||||
}
|
||||
|
||||
function scoreSeparatorAtPos(charCode: number): number {
|
||||
switch (charCode) {
|
||||
case CharCode.Slash:
|
||||
case CharCode.Backslash:
|
||||
return 5; // prefer path separators...
|
||||
case CharCode.Underline:
|
||||
case CharCode.Dash:
|
||||
case CharCode.Period:
|
||||
case CharCode.Space:
|
||||
case CharCode.SingleQuote:
|
||||
case CharCode.DoubleQuote:
|
||||
case CharCode.Colon:
|
||||
return 4; // ...over other separators
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
// function printMatrix(query: string, target: string, matches: number[], scores: number[]): void {
|
||||
// console.log('\t' + target.split('').join('\t'));
|
||||
// for (let queryIndex = 0; queryIndex < query.length; queryIndex++) {
|
||||
// let line = query[queryIndex] + '\t';
|
||||
// for (let targetIndex = 0; targetIndex < target.length; targetIndex++) {
|
||||
// const currentIndex = queryIndex * target.length + targetIndex;
|
||||
// line = line + 'M' + matches[currentIndex] + '/' + 'S' + scores[currentIndex] + '\t';
|
||||
// }
|
||||
|
||||
// console.log(line);
|
||||
// }
|
||||
// }
|
||||
|
||||
/**
|
||||
* Scoring on structural items that have a label and optional description.
|
||||
*/
|
||||
export interface IItemScore {
|
||||
|
||||
/**
|
||||
* Overall score.
|
||||
*/
|
||||
score: number;
|
||||
|
||||
/**
|
||||
* Matches within the label.
|
||||
*/
|
||||
labelMatch?: IMatch[];
|
||||
|
||||
/**
|
||||
* Matches within the description.
|
||||
*/
|
||||
descriptionMatch?: IMatch[];
|
||||
}
|
||||
|
||||
const NO_ITEM_SCORE: IItemScore = Object.freeze({ score: 0 });
|
||||
|
||||
export interface IItemAccessor<T> {
|
||||
|
||||
/**
|
||||
* Just the label of the item to score on.
|
||||
*/
|
||||
getItemLabel(item: T): string;
|
||||
|
||||
/**
|
||||
* The optional description of the item to score on. Can be null.
|
||||
*/
|
||||
getItemDescription(item: T): string;
|
||||
|
||||
/**
|
||||
* If the item is a file, the path of the file to score on. Can be null.
|
||||
*/
|
||||
getItemPath(file: T): string;
|
||||
}
|
||||
|
||||
const PATH_IDENTITY_SCORE = 1 << 18;
|
||||
const LABEL_PREFIX_SCORE = 1 << 17;
|
||||
const LABEL_CAMELCASE_SCORE = 1 << 16;
|
||||
const LABEL_SCORE_THRESHOLD = 1 << 15;
|
||||
|
||||
export interface IPreparedQuery {
|
||||
original: string;
|
||||
value: string;
|
||||
lowercase: string;
|
||||
containsPathSeparator: boolean;
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper function to prepare a search value for scoring in quick open by removing unwanted characters.
|
||||
*/
|
||||
export function prepareQuery(original: string): IPreparedQuery {
|
||||
let lowercase: string;
|
||||
let containsPathSeparator: boolean;
|
||||
let value: string;
|
||||
|
||||
if (original) {
|
||||
value = stripWildcards(original).replace(/\s/g, ''); // get rid of all wildcards and whitespace
|
||||
if (isWindows) {
|
||||
value = value.replace(/\//g, nativeSep); // Help Windows users to search for paths when using slash
|
||||
}
|
||||
|
||||
lowercase = value.toLowerCase();
|
||||
containsPathSeparator = value.indexOf(nativeSep) >= 0;
|
||||
}
|
||||
|
||||
return { original, value, lowercase, containsPathSeparator };
|
||||
}
|
||||
|
||||
export function scoreItem<T>(item: T, query: IPreparedQuery, fuzzy: boolean, accessor: IItemAccessor<T>, cache: ScorerCache): IItemScore {
|
||||
if (!item || !query.value) {
|
||||
return NO_ITEM_SCORE; // we need an item and query to score on at least
|
||||
}
|
||||
|
||||
const label = accessor.getItemLabel(item);
|
||||
if (!label) {
|
||||
return NO_ITEM_SCORE; // we need a label at least
|
||||
}
|
||||
|
||||
const description = accessor.getItemDescription(item);
|
||||
|
||||
let cacheHash: string;
|
||||
if (description) {
|
||||
cacheHash = `${label}${description}${query.value}${fuzzy}`;
|
||||
} else {
|
||||
cacheHash = `${label}${query.value}${fuzzy}`;
|
||||
}
|
||||
|
||||
const cached = cache[cacheHash];
|
||||
if (cached) {
|
||||
return cached;
|
||||
}
|
||||
|
||||
const itemScore = doScoreItem(label, description, accessor.getItemPath(item), query, fuzzy);
|
||||
cache[cacheHash] = itemScore;
|
||||
|
||||
return itemScore;
|
||||
}
|
||||
|
||||
function doScoreItem(label: string, description: string, path: string, query: IPreparedQuery, fuzzy: boolean): IItemScore {
|
||||
|
||||
// 1.) treat identity matches on full path highest
|
||||
if (path && isLinux ? query.original === path : equalsIgnoreCase(query.original, path)) {
|
||||
return { score: PATH_IDENTITY_SCORE, labelMatch: [{ start: 0, end: label.length }], descriptionMatch: description ? [{ start: 0, end: description.length }] : void 0 };
|
||||
}
|
||||
|
||||
// We only consider label matches if the query is not including file path separators
|
||||
const preferLabelMatches = !path || !query.containsPathSeparator;
|
||||
if (preferLabelMatches) {
|
||||
|
||||
// 2.) treat prefix matches on the label second highest
|
||||
const prefixLabelMatch = matchesPrefix(query.value, label);
|
||||
if (prefixLabelMatch) {
|
||||
return { score: LABEL_PREFIX_SCORE, labelMatch: prefixLabelMatch };
|
||||
}
|
||||
|
||||
// 3.) treat camelcase matches on the label third highest
|
||||
const camelcaseLabelMatch = matchesCamelCase(query.value, label);
|
||||
if (camelcaseLabelMatch) {
|
||||
return { score: LABEL_CAMELCASE_SCORE, labelMatch: camelcaseLabelMatch };
|
||||
}
|
||||
|
||||
// 4.) prefer scores on the label if any
|
||||
const [labelScore, labelPositions] = score(label, query.value, query.lowercase, fuzzy);
|
||||
if (labelScore) {
|
||||
return { score: labelScore + LABEL_SCORE_THRESHOLD, labelMatch: createMatches(labelPositions) };
|
||||
}
|
||||
}
|
||||
|
||||
// 5.) finally compute description + label scores if we have a description
|
||||
if (description) {
|
||||
let descriptionPrefix = description;
|
||||
if (!!path) {
|
||||
descriptionPrefix = `${description}${nativeSep}`; // assume this is a file path
|
||||
}
|
||||
|
||||
const descriptionPrefixLength = descriptionPrefix.length;
|
||||
const descriptionAndLabel = `${descriptionPrefix}${label}`;
|
||||
|
||||
const [labelDescriptionScore, labelDescriptionPositions] = score(descriptionAndLabel, query.value, query.lowercase, fuzzy);
|
||||
if (labelDescriptionScore) {
|
||||
const labelDescriptionMatches = createMatches(labelDescriptionPositions);
|
||||
const labelMatch: IMatch[] = [];
|
||||
const descriptionMatch: IMatch[] = [];
|
||||
|
||||
// We have to split the matches back onto the label and description portions
|
||||
labelDescriptionMatches.forEach(h => {
|
||||
|
||||
// Match overlaps label and description part, we need to split it up
|
||||
if (h.start < descriptionPrefixLength && h.end > descriptionPrefixLength) {
|
||||
labelMatch.push({ start: 0, end: h.end - descriptionPrefixLength });
|
||||
descriptionMatch.push({ start: h.start, end: descriptionPrefixLength });
|
||||
}
|
||||
|
||||
// Match on label part
|
||||
else if (h.start >= descriptionPrefixLength) {
|
||||
labelMatch.push({ start: h.start - descriptionPrefixLength, end: h.end - descriptionPrefixLength });
|
||||
}
|
||||
|
||||
// Match on description part
|
||||
else {
|
||||
descriptionMatch.push(h);
|
||||
}
|
||||
});
|
||||
|
||||
return { score: labelDescriptionScore, labelMatch, descriptionMatch };
|
||||
}
|
||||
}
|
||||
|
||||
return NO_ITEM_SCORE;
|
||||
}
|
||||
|
||||
export function compareItemsByScore<T>(itemA: T, itemB: T, query: IPreparedQuery, fuzzy: boolean, accessor: IItemAccessor<T>, cache: ScorerCache, fallbackComparer = fallbackCompare): number {
|
||||
const itemScoreA = scoreItem(itemA, query, fuzzy, accessor, cache);
|
||||
const itemScoreB = scoreItem(itemB, query, fuzzy, accessor, cache);
|
||||
|
||||
const scoreA = itemScoreA.score;
|
||||
const scoreB = itemScoreB.score;
|
||||
|
||||
// 1.) prefer identity matches
|
||||
if (scoreA === PATH_IDENTITY_SCORE || scoreB === PATH_IDENTITY_SCORE) {
|
||||
if (scoreA !== scoreB) {
|
||||
return scoreA === PATH_IDENTITY_SCORE ? -1 : 1;
|
||||
}
|
||||
}
|
||||
|
||||
// 2.) prefer label prefix matches
|
||||
if (scoreA === LABEL_PREFIX_SCORE || scoreB === LABEL_PREFIX_SCORE) {
|
||||
if (scoreA !== scoreB) {
|
||||
return scoreA === LABEL_PREFIX_SCORE ? -1 : 1;
|
||||
}
|
||||
|
||||
const labelA = accessor.getItemLabel(itemA);
|
||||
const labelB = accessor.getItemLabel(itemB);
|
||||
|
||||
// prefer shorter names when both match on label prefix
|
||||
if (labelA.length !== labelB.length) {
|
||||
return labelA.length - labelB.length;
|
||||
}
|
||||
}
|
||||
|
||||
// 3.) prefer camelcase matches
|
||||
if (scoreA === LABEL_CAMELCASE_SCORE || scoreB === LABEL_CAMELCASE_SCORE) {
|
||||
if (scoreA !== scoreB) {
|
||||
return scoreA === LABEL_CAMELCASE_SCORE ? -1 : 1;
|
||||
}
|
||||
|
||||
const labelA = accessor.getItemLabel(itemA);
|
||||
const labelB = accessor.getItemLabel(itemB);
|
||||
|
||||
// prefer more compact camel case matches over longer
|
||||
const comparedByMatchLength = compareByMatchLength(itemScoreA.labelMatch, itemScoreB.labelMatch);
|
||||
if (comparedByMatchLength !== 0) {
|
||||
return comparedByMatchLength;
|
||||
}
|
||||
|
||||
// prefer shorter names when both match on label camelcase
|
||||
if (labelA.length !== labelB.length) {
|
||||
return labelA.length - labelB.length;
|
||||
}
|
||||
}
|
||||
|
||||
// 4.) prefer label scores
|
||||
if (scoreA > LABEL_SCORE_THRESHOLD || scoreB > LABEL_SCORE_THRESHOLD) {
|
||||
if (scoreB < LABEL_SCORE_THRESHOLD) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (scoreA < LABEL_SCORE_THRESHOLD) {
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
// 5.) compare by score
|
||||
if (scoreA !== scoreB) {
|
||||
return scoreA > scoreB ? -1 : 1;
|
||||
}
|
||||
|
||||
// 6.) scores are identical, prefer more compact matches (label and description)
|
||||
const itemAMatchDistance = computeLabelAndDescriptionMatchDistance(itemA, itemScoreA, accessor);
|
||||
const itemBMatchDistance = computeLabelAndDescriptionMatchDistance(itemB, itemScoreB, accessor);
|
||||
if (itemAMatchDistance && itemBMatchDistance && itemAMatchDistance !== itemBMatchDistance) {
|
||||
return itemBMatchDistance > itemAMatchDistance ? -1 : 1;
|
||||
}
|
||||
|
||||
// 7.) at this point, scores are identical and match compactness as well
|
||||
// for both items so we start to use the fallback compare
|
||||
return fallbackComparer(itemA, itemB, query, accessor);
|
||||
}
|
||||
|
||||
function computeLabelAndDescriptionMatchDistance<T>(item: T, score: IItemScore, accessor: IItemAccessor<T>): number {
|
||||
const hasLabelMatches = (score.labelMatch && score.labelMatch.length);
|
||||
const hasDescriptionMatches = (score.descriptionMatch && score.descriptionMatch.length);
|
||||
|
||||
let matchStart: number = -1;
|
||||
let matchEnd: number = -1;
|
||||
|
||||
// If we have description matches, the start is first of description match
|
||||
if (hasDescriptionMatches) {
|
||||
matchStart = score.descriptionMatch[0].start;
|
||||
}
|
||||
|
||||
// Otherwise, the start is the first label match
|
||||
else if (hasLabelMatches) {
|
||||
matchStart = score.labelMatch[0].start;
|
||||
}
|
||||
|
||||
// If we have label match, the end is the last label match
|
||||
// If we had a description match, we add the length of the description
|
||||
// as offset to the end to indicate this.
|
||||
if (hasLabelMatches) {
|
||||
matchEnd = score.labelMatch[score.labelMatch.length - 1].end;
|
||||
if (hasDescriptionMatches) {
|
||||
const itemDescription = accessor.getItemDescription(item);
|
||||
if (itemDescription) {
|
||||
matchEnd += itemDescription.length;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// If we have just a description match, the end is the last description match
|
||||
else if (hasDescriptionMatches) {
|
||||
matchEnd = score.descriptionMatch[score.descriptionMatch.length - 1].end;
|
||||
}
|
||||
|
||||
return matchEnd - matchStart;
|
||||
}
|
||||
|
||||
function compareByMatchLength(matchesA?: IMatch[], matchesB?: IMatch[]): number {
|
||||
if ((!matchesA && !matchesB) || (!matchesA.length && !matchesB.length)) {
|
||||
return 0; // make sure to not cause bad comparing when matches are not provided
|
||||
}
|
||||
|
||||
if (!matchesB || !matchesB.length) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (!matchesA || !matchesA.length) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
// Compute match length of A (first to last match)
|
||||
const matchStartA = matchesA[0].start;
|
||||
const matchEndA = matchesA[matchesA.length - 1].end;
|
||||
const matchLengthA = matchEndA - matchStartA;
|
||||
|
||||
// Compute match length of B (first to last match)
|
||||
const matchStartB = matchesB[0].start;
|
||||
const matchEndB = matchesB[matchesB.length - 1].end;
|
||||
const matchLengthB = matchEndB - matchStartB;
|
||||
|
||||
// Prefer shorter match length
|
||||
return matchLengthA === matchLengthB ? 0 : matchLengthB < matchLengthA ? 1 : -1;
|
||||
}
|
||||
|
||||
export function fallbackCompare<T>(itemA: T, itemB: T, query: IPreparedQuery, accessor: IItemAccessor<T>): number {
|
||||
|
||||
// check for label + description length and prefer shorter
|
||||
const labelA = accessor.getItemLabel(itemA);
|
||||
const labelB = accessor.getItemLabel(itemB);
|
||||
|
||||
const descriptionA = accessor.getItemDescription(itemA);
|
||||
const descriptionB = accessor.getItemDescription(itemB);
|
||||
|
||||
const labelDescriptionALength = labelA.length + (descriptionA ? descriptionA.length : 0);
|
||||
const labelDescriptionBLength = labelB.length + (descriptionB ? descriptionB.length : 0);
|
||||
|
||||
if (labelDescriptionALength !== labelDescriptionBLength) {
|
||||
return labelDescriptionALength - labelDescriptionBLength;
|
||||
}
|
||||
|
||||
// check for path length and prefer shorter
|
||||
const pathA = accessor.getItemPath(itemA);
|
||||
const pathB = accessor.getItemPath(itemB);
|
||||
|
||||
if (pathA && pathB && pathA.length !== pathB.length) {
|
||||
return pathA.length - pathB.length;
|
||||
}
|
||||
|
||||
// 7.) finally we have equal scores and equal length, we fallback to comparer
|
||||
|
||||
// compare by label
|
||||
if (labelA !== labelB) {
|
||||
return compareAnything(labelA, labelB, query.value);
|
||||
}
|
||||
|
||||
// compare by description
|
||||
if (descriptionA && descriptionB && descriptionA !== descriptionB) {
|
||||
return compareAnything(descriptionA, descriptionB, query.value);
|
||||
}
|
||||
|
||||
// compare by path
|
||||
if (pathA && pathB && pathA !== pathB) {
|
||||
return compareAnything(pathA, pathB, query.value);
|
||||
}
|
||||
|
||||
// equal
|
||||
return 0;
|
||||
}
|
224
extensions/search-rg/src/common/filters.ts
Normal file
224
extensions/search-rg/src/common/filters.ts
Normal file
|
@ -0,0 +1,224 @@
|
|||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
'use strict';
|
||||
|
||||
import * as strings from './strings';
|
||||
import { CharCode } from './charCode';
|
||||
|
||||
export interface IFilter {
|
||||
// Returns null if word doesn't match.
|
||||
(word: string, wordToMatchAgainst: string): IMatch[];
|
||||
}
|
||||
|
||||
export interface IMatch {
|
||||
start: number;
|
||||
end: number;
|
||||
}
|
||||
|
||||
// Prefix
|
||||
|
||||
export const matchesPrefix: IFilter = _matchesPrefix.bind(undefined, true);
|
||||
|
||||
function _matchesPrefix(ignoreCase: boolean, word: string, wordToMatchAgainst: string): IMatch[] {
|
||||
if (!wordToMatchAgainst || wordToMatchAgainst.length < word.length) {
|
||||
return null;
|
||||
}
|
||||
|
||||
let matches: boolean;
|
||||
if (ignoreCase) {
|
||||
matches = strings.startsWithIgnoreCase(wordToMatchAgainst, word);
|
||||
} else {
|
||||
matches = wordToMatchAgainst.indexOf(word) === 0;
|
||||
}
|
||||
|
||||
if (!matches) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return word.length > 0 ? [{ start: 0, end: word.length }] : [];
|
||||
}
|
||||
|
||||
// CamelCase
|
||||
|
||||
function isLower(code: number): boolean {
|
||||
return CharCode.a <= code && code <= CharCode.z;
|
||||
}
|
||||
|
||||
export function isUpper(code: number): boolean {
|
||||
return CharCode.A <= code && code <= CharCode.Z;
|
||||
}
|
||||
|
||||
function isNumber(code: number): boolean {
|
||||
return CharCode.Digit0 <= code && code <= CharCode.Digit9;
|
||||
}
|
||||
|
||||
function isWhitespace(code: number): boolean {
|
||||
return (
|
||||
code === CharCode.Space
|
||||
|| code === CharCode.Tab
|
||||
|| code === CharCode.LineFeed
|
||||
|| code === CharCode.CarriageReturn
|
||||
);
|
||||
}
|
||||
|
||||
function isAlphanumeric(code: number): boolean {
|
||||
return isLower(code) || isUpper(code) || isNumber(code);
|
||||
}
|
||||
|
||||
function join(head: IMatch, tail: IMatch[]): IMatch[] {
|
||||
if (tail.length === 0) {
|
||||
tail = [head];
|
||||
} else if (head.end === tail[0].start) {
|
||||
tail[0].start = head.start;
|
||||
} else {
|
||||
tail.unshift(head);
|
||||
}
|
||||
return tail;
|
||||
}
|
||||
|
||||
function nextAnchor(camelCaseWord: string, start: number): number {
|
||||
for (let i = start; i < camelCaseWord.length; i++) {
|
||||
let c = camelCaseWord.charCodeAt(i);
|
||||
if (isUpper(c) || isNumber(c) || (i > 0 && !isAlphanumeric(camelCaseWord.charCodeAt(i - 1)))) {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
return camelCaseWord.length;
|
||||
}
|
||||
|
||||
function _matchesCamelCase(word: string, camelCaseWord: string, i: number, j: number): IMatch[] {
|
||||
if (i === word.length) {
|
||||
return [];
|
||||
} else if (j === camelCaseWord.length) {
|
||||
return null;
|
||||
} else if (word[i] !== camelCaseWord[j].toLowerCase()) {
|
||||
return null;
|
||||
} else {
|
||||
let result: IMatch[] = null;
|
||||
let nextUpperIndex = j + 1;
|
||||
result = _matchesCamelCase(word, camelCaseWord, i + 1, j + 1);
|
||||
while (!result && (nextUpperIndex = nextAnchor(camelCaseWord, nextUpperIndex)) < camelCaseWord.length) {
|
||||
result = _matchesCamelCase(word, camelCaseWord, i + 1, nextUpperIndex);
|
||||
nextUpperIndex++;
|
||||
}
|
||||
return result === null ? null : join({ start: j, end: j + 1 }, result);
|
||||
}
|
||||
}
|
||||
|
||||
interface ICamelCaseAnalysis {
|
||||
upperPercent: number;
|
||||
lowerPercent: number;
|
||||
alphaPercent: number;
|
||||
numericPercent: number;
|
||||
}
|
||||
|
||||
// Heuristic to avoid computing camel case matcher for words that don't
|
||||
// look like camelCaseWords.
|
||||
function analyzeCamelCaseWord(word: string): ICamelCaseAnalysis {
|
||||
let upper = 0, lower = 0, alpha = 0, numeric = 0, code = 0;
|
||||
|
||||
for (let i = 0; i < word.length; i++) {
|
||||
code = word.charCodeAt(i);
|
||||
|
||||
if (isUpper(code)) { upper++; }
|
||||
if (isLower(code)) { lower++; }
|
||||
if (isAlphanumeric(code)) { alpha++; }
|
||||
if (isNumber(code)) { numeric++; }
|
||||
}
|
||||
|
||||
let upperPercent = upper / word.length;
|
||||
let lowerPercent = lower / word.length;
|
||||
let alphaPercent = alpha / word.length;
|
||||
let numericPercent = numeric / word.length;
|
||||
|
||||
return { upperPercent, lowerPercent, alphaPercent, numericPercent };
|
||||
}
|
||||
|
||||
function isUpperCaseWord(analysis: ICamelCaseAnalysis): boolean {
|
||||
const { upperPercent, lowerPercent } = analysis;
|
||||
return lowerPercent === 0 && upperPercent > 0.6;
|
||||
}
|
||||
|
||||
function isCamelCaseWord(analysis: ICamelCaseAnalysis): boolean {
|
||||
const { upperPercent, lowerPercent, alphaPercent, numericPercent } = analysis;
|
||||
return lowerPercent > 0.2 && upperPercent < 0.8 && alphaPercent > 0.6 && numericPercent < 0.2;
|
||||
}
|
||||
|
||||
// Heuristic to avoid computing camel case matcher for words that don't
|
||||
// look like camel case patterns.
|
||||
function isCamelCasePattern(word: string): boolean {
|
||||
let upper = 0, lower = 0, code = 0, whitespace = 0;
|
||||
|
||||
for (let i = 0; i < word.length; i++) {
|
||||
code = word.charCodeAt(i);
|
||||
|
||||
if (isUpper(code)) { upper++; }
|
||||
if (isLower(code)) { lower++; }
|
||||
if (isWhitespace(code)) { whitespace++; }
|
||||
}
|
||||
|
||||
if ((upper === 0 || lower === 0) && whitespace === 0) {
|
||||
return word.length <= 30;
|
||||
} else {
|
||||
return upper <= 5;
|
||||
}
|
||||
}
|
||||
|
||||
export function matchesCamelCase(word: string, camelCaseWord: string): IMatch[] {
|
||||
if (!camelCaseWord) {
|
||||
return null;
|
||||
}
|
||||
|
||||
camelCaseWord = camelCaseWord.trim();
|
||||
|
||||
if (camelCaseWord.length === 0) {
|
||||
return null;
|
||||
}
|
||||
|
||||
if (!isCamelCasePattern(word)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
if (camelCaseWord.length > 60) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const analysis = analyzeCamelCaseWord(camelCaseWord);
|
||||
|
||||
if (!isCamelCaseWord(analysis)) {
|
||||
if (!isUpperCaseWord(analysis)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
camelCaseWord = camelCaseWord.toLowerCase();
|
||||
}
|
||||
|
||||
let result: IMatch[] = null;
|
||||
let i = 0;
|
||||
|
||||
word = word.toLowerCase();
|
||||
while (i < camelCaseWord.length && (result = _matchesCamelCase(word, camelCaseWord, 0, i)) === null) {
|
||||
i = nextAnchor(camelCaseWord, i + 1);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
export function createMatches(position: number[]): IMatch[] {
|
||||
let ret: IMatch[] = [];
|
||||
if (!position) {
|
||||
return ret;
|
||||
}
|
||||
let last: IMatch;
|
||||
for (const pos of position) {
|
||||
if (last && last.end === pos) {
|
||||
last.end += 1;
|
||||
} else {
|
||||
last = { start: pos, end: pos + 1 };
|
||||
ret.push(last);
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
}
|
143
extensions/search-rg/src/common/strings.ts
Normal file
143
extensions/search-rg/src/common/strings.ts
Normal file
|
@ -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.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
'use strict';
|
||||
|
||||
import { CharCode } from './charCode';
|
||||
|
||||
export function stripWildcards(pattern: string): string {
|
||||
return pattern.replace(/\*/g, '');
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines if haystack starts with needle.
|
||||
*/
|
||||
export function startsWith(haystack: string, needle: string): boolean {
|
||||
if (haystack.length < needle.length) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (haystack === needle) {
|
||||
return true;
|
||||
}
|
||||
|
||||
for (let i = 0; i < needle.length; i++) {
|
||||
if (haystack[i] !== needle[i]) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
export function startsWithIgnoreCase(str: string, candidate: string): boolean {
|
||||
const candidateLength = candidate.length;
|
||||
if (candidate.length > str.length) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return doEqualsIgnoreCase(str, candidate, candidateLength);
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines if haystack ends with needle.
|
||||
*/
|
||||
export function endsWith(haystack: string, needle: string): boolean {
|
||||
let diff = haystack.length - needle.length;
|
||||
if (diff > 0) {
|
||||
return haystack.indexOf(needle, diff) === diff;
|
||||
} else if (diff === 0) {
|
||||
return haystack === needle;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
function isLowerAsciiLetter(code: number): boolean {
|
||||
return code >= CharCode.a && code <= CharCode.z;
|
||||
}
|
||||
|
||||
function isUpperAsciiLetter(code: number): boolean {
|
||||
return code >= CharCode.A && code <= CharCode.Z;
|
||||
}
|
||||
|
||||
function isAsciiLetter(code: number): boolean {
|
||||
return isLowerAsciiLetter(code) || isUpperAsciiLetter(code);
|
||||
}
|
||||
|
||||
export function equalsIgnoreCase(a: string, b: string): boolean {
|
||||
const len1 = a ? a.length : 0;
|
||||
const len2 = b ? b.length : 0;
|
||||
|
||||
if (len1 !== len2) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return doEqualsIgnoreCase(a, b);
|
||||
}
|
||||
|
||||
function doEqualsIgnoreCase(a: string, b: string, stopAt = a.length): boolean {
|
||||
if (typeof a !== 'string' || typeof b !== 'string') {
|
||||
return false;
|
||||
}
|
||||
|
||||
for (let i = 0; i < stopAt; i++) {
|
||||
const codeA = a.charCodeAt(i);
|
||||
const codeB = b.charCodeAt(i);
|
||||
|
||||
if (codeA === codeB) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// a-z A-Z
|
||||
if (isAsciiLetter(codeA) && isAsciiLetter(codeB)) {
|
||||
let diff = Math.abs(codeA - codeB);
|
||||
if (diff !== 0 && diff !== 32) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// Any other charcode
|
||||
else {
|
||||
if (String.fromCharCode(codeA).toLowerCase() !== String.fromCharCode(codeB).toLowerCase()) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if the characters of the provided query string are included in the
|
||||
* target string. The characters do not have to be contiguous within the string.
|
||||
*/
|
||||
export function fuzzyContains(target: string, query: string): boolean {
|
||||
if (!target || !query) {
|
||||
return false; // return early if target or query are undefined
|
||||
}
|
||||
|
||||
if (target.length < query.length) {
|
||||
return false; // impossible for query to be contained in target
|
||||
}
|
||||
|
||||
const queryLen = query.length;
|
||||
const targetLower = target.toLowerCase();
|
||||
|
||||
let index = 0;
|
||||
let lastIndexOf = -1;
|
||||
while (index < queryLen) {
|
||||
let indexOf = targetLower.indexOf(query[index], lastIndexOf + 1);
|
||||
if (indexOf < 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
lastIndexOf = indexOf;
|
||||
|
||||
index++;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
|
@ -6,6 +6,7 @@
|
|||
import * as vscode from 'vscode';
|
||||
import { RipgrepTextSearchEngine } from './ripgrepTextSearch';
|
||||
import { RipgrepFileSearchEngine } from './ripgrepFileSearch';
|
||||
import { CachedSearchProvider } from './cachedSearchProvider';
|
||||
|
||||
export function activate(): void {
|
||||
if (vscode.workspace.getConfiguration('searchRipgrep').get('enable')) {
|
||||
|
@ -15,17 +16,39 @@ export function activate(): void {
|
|||
}
|
||||
}
|
||||
|
||||
type SearchEngine = RipgrepFileSearchEngine | RipgrepTextSearchEngine;
|
||||
|
||||
class RipgrepSearchProvider implements vscode.SearchProvider {
|
||||
private cachedProvider: CachedSearchProvider;
|
||||
private inProgress: Set<SearchEngine> = new Set();
|
||||
|
||||
constructor(private outputChannel: vscode.OutputChannel) {
|
||||
this.cachedProvider = new CachedSearchProvider();
|
||||
process.once('exit', () => this.dispose());
|
||||
}
|
||||
|
||||
provideTextSearchResults(query: vscode.TextSearchQuery, options: vscode.TextSearchOptions, progress: vscode.Progress<vscode.TextSearchResult>, token: vscode.CancellationToken): Thenable<void> {
|
||||
const engine = new RipgrepTextSearchEngine(this.outputChannel);
|
||||
return engine.provideTextSearchResults(query, options, progress, token);
|
||||
return this.withEngine(engine, () => engine.provideTextSearchResults(query, options, progress, token));
|
||||
}
|
||||
|
||||
provideFileSearchResults(options: vscode.SearchOptions, progress: vscode.Progress<string>, token: vscode.CancellationToken): Thenable<void> {
|
||||
provideFileSearchResults(query: vscode.FileSearchQuery, options: vscode.SearchOptions, progress: vscode.Progress<vscode.Uri>, token: vscode.CancellationToken): Thenable<void> {
|
||||
const engine = new RipgrepFileSearchEngine(this.outputChannel);
|
||||
return engine.provideFileSearchResults(options, progress, token);
|
||||
return this.withEngine(engine, () => this.cachedProvider.provideFileSearchResults(engine, query, options, progress, token));
|
||||
}
|
||||
|
||||
clearCache(cacheKey: string): void {
|
||||
this.cachedProvider.clearCache(cacheKey);
|
||||
}
|
||||
|
||||
private withEngine(engine: SearchEngine, fn: () => Thenable<void>): Thenable<void> {
|
||||
this.inProgress.add(engine);
|
||||
return fn().then(() => {
|
||||
this.inProgress.delete(engine);
|
||||
});
|
||||
}
|
||||
|
||||
private dispose() {
|
||||
this.inProgress.forEach(engine => engine.cancel());
|
||||
}
|
||||
}
|
|
@ -7,30 +7,31 @@ import * as cp from 'child_process';
|
|||
import { Readable } from 'stream';
|
||||
import { NodeStringDecoder, StringDecoder } from 'string_decoder';
|
||||
import * as vscode from 'vscode';
|
||||
import { normalizeNFC, normalizeNFD } from './normalization';
|
||||
import { normalizeNFC, normalizeNFD } from './common/normalization';
|
||||
import { rgPath } from './ripgrep';
|
||||
import { anchorGlob } from './ripgrepHelpers';
|
||||
import { anchorGlob } from './utils';
|
||||
import { rgErrorMsgForDisplay } from './ripgrepTextSearch';
|
||||
import { IInternalFileSearchProvider } from './cachedSearchProvider';
|
||||
|
||||
const isMac = process.platform === 'darwin';
|
||||
|
||||
// If vscode-ripgrep is in an .asar file, then the binary is unpacked.
|
||||
const rgDiskPath = rgPath.replace(/\bnode_modules\.asar\b/, 'node_modules.asar.unpacked');
|
||||
|
||||
export class RipgrepFileSearchEngine {
|
||||
export class RipgrepFileSearchEngine implements IInternalFileSearchProvider {
|
||||
private rgProc: cp.ChildProcess;
|
||||
private killRgProcFn: (code?: number) => void;
|
||||
private isDone: boolean;
|
||||
|
||||
constructor(private outputChannel: vscode.OutputChannel) {
|
||||
this.killRgProcFn = () => this.rgProc && this.rgProc.kill();
|
||||
process.once('exit', this.killRgProcFn);
|
||||
constructor(private outputChannel: vscode.OutputChannel) { }
|
||||
|
||||
cancel() {
|
||||
this.isDone = true;
|
||||
if (this.rgProc) {
|
||||
this.rgProc.kill();
|
||||
}
|
||||
}
|
||||
|
||||
private dispose() {
|
||||
process.removeListener('exit', this.killRgProcFn);
|
||||
}
|
||||
|
||||
provideFileSearchResults(options: vscode.SearchOptions, progress: vscode.Progress<string>, token: vscode.CancellationToken): Thenable<void> {
|
||||
provideFileSearchResults(options: vscode.FileSearchOptions, progress: vscode.Progress<string>, token: vscode.CancellationToken): Thenable<void> {
|
||||
this.outputChannel.appendLine(`provideFileSearchResults ${JSON.stringify({
|
||||
...options,
|
||||
...{
|
||||
|
@ -39,12 +40,7 @@ export class RipgrepFileSearchEngine {
|
|||
})}`);
|
||||
|
||||
return new Promise((resolve, reject) => {
|
||||
let isDone = false;
|
||||
const cancel = () => {
|
||||
isDone = true;
|
||||
this.rgProc.kill();
|
||||
};
|
||||
token.onCancellationRequested(cancel);
|
||||
token.onCancellationRequested(() => this.cancel());
|
||||
|
||||
const rgArgs = getRgArgs(options);
|
||||
|
||||
|
@ -93,7 +89,7 @@ export class RipgrepFileSearchEngine {
|
|||
});
|
||||
|
||||
if (last) {
|
||||
if (isDone) {
|
||||
if (this.isDone) {
|
||||
resolve();
|
||||
} else {
|
||||
// Trigger last result
|
||||
|
@ -106,12 +102,7 @@ export class RipgrepFileSearchEngine {
|
|||
}
|
||||
}
|
||||
});
|
||||
}).then(
|
||||
() => this.dispose(),
|
||||
err => {
|
||||
this.dispose();
|
||||
return Promise.reject(err);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
private collectStdout(cmd: cp.ChildProcess, cb: (err: Error, stdout?: string, last?: boolean) => void): void {
|
||||
|
|
|
@ -7,10 +7,11 @@
|
|||
|
||||
import * as cp from 'child_process';
|
||||
import { EventEmitter } from 'events';
|
||||
import * as path from 'path';
|
||||
import { NodeStringDecoder, StringDecoder } from 'string_decoder';
|
||||
import * as vscode from 'vscode';
|
||||
import { rgPath } from './ripgrep';
|
||||
import { anchorGlob } from './ripgrepHelpers';
|
||||
import { anchorGlob } from './utils';
|
||||
|
||||
// If vscode-ripgrep is in an .asar file, then the binary is unpacked.
|
||||
const rgDiskPath = rgPath.replace(/\bnode_modules\.asar\b/, 'node_modules.asar.unpacked');
|
||||
|
@ -21,12 +22,21 @@ const MAX_TEXT_RESULTS = 10000;
|
|||
export class RipgrepTextSearchEngine {
|
||||
private isDone = false;
|
||||
private rgProc: cp.ChildProcess;
|
||||
private killRgProcFn: (code?: number) => void;
|
||||
|
||||
private ripgrepParser: RipgrepParser;
|
||||
|
||||
constructor(private outputChannel: vscode.OutputChannel) {
|
||||
this.killRgProcFn = () => this.rgProc && this.rgProc.kill();
|
||||
constructor(private outputChannel: vscode.OutputChannel) { }
|
||||
|
||||
cancel() {
|
||||
this.isDone = true;
|
||||
|
||||
if (this.rgProc) {
|
||||
this.rgProc.kill();
|
||||
}
|
||||
|
||||
if (this.ripgrepParser) {
|
||||
this.ripgrepParser.cancel();
|
||||
}
|
||||
}
|
||||
|
||||
provideTextSearchResults(query: vscode.TextSearchQuery, options: vscode.TextSearchOptions, progress: vscode.Progress<vscode.TextSearchResult>, token: vscode.CancellationToken): Thenable<void> {
|
||||
|
@ -38,12 +48,7 @@ export class RipgrepTextSearchEngine {
|
|||
})}`);
|
||||
|
||||
return new Promise((resolve, reject) => {
|
||||
const cancel = () => {
|
||||
this.isDone = true;
|
||||
this.ripgrepParser.cancel();
|
||||
this.rgProc.kill();
|
||||
};
|
||||
token.onCancellationRequested(cancel);
|
||||
token.onCancellationRequested(() => this.cancel());
|
||||
|
||||
const rgArgs = getRgArgs(query, options);
|
||||
|
||||
|
@ -55,7 +60,6 @@ export class RipgrepTextSearchEngine {
|
|||
this.outputChannel.appendLine(`rg ${escapedArgs}\n - cwd: ${cwd}`);
|
||||
|
||||
this.rgProc = cp.spawn(rgDiskPath, rgArgs, { cwd });
|
||||
process.once('exit', this.killRgProcFn);
|
||||
this.rgProc.on('error', e => {
|
||||
console.error(e);
|
||||
this.outputChannel.append('Error: ' + (e && e.message));
|
||||
|
@ -70,7 +74,7 @@ export class RipgrepTextSearchEngine {
|
|||
});
|
||||
|
||||
this.ripgrepParser.on('hitLimit', () => {
|
||||
cancel();
|
||||
this.cancel();
|
||||
});
|
||||
|
||||
this.rgProc.stdout.on('data', data => {
|
||||
|
@ -91,7 +95,6 @@ export class RipgrepTextSearchEngine {
|
|||
this.outputChannel.appendLine(gotData ? 'Got data from stdout' : 'No data from stdout');
|
||||
this.outputChannel.appendLine(gotResult ? 'Got result from parser' : 'No result from parser');
|
||||
this.outputChannel.appendLine('');
|
||||
process.removeListener('exit', this.killRgProcFn);
|
||||
if (this.isDone) {
|
||||
resolve();
|
||||
} else {
|
||||
|
@ -291,7 +294,7 @@ export class RipgrepParser extends EventEmitter {
|
|||
lineMatches
|
||||
.map(range => {
|
||||
return <vscode.TextSearchResult>{
|
||||
path: this.currentFile,
|
||||
uri: vscode.Uri.file(path.join(this.rootFolder, this.currentFile)),
|
||||
range,
|
||||
preview: {
|
||||
text: preview,
|
||||
|
|
|
@ -5,9 +5,8 @@
|
|||
|
||||
'use strict';
|
||||
|
||||
import * as vscode from 'vscode';
|
||||
|
||||
import * as path from 'path';
|
||||
import * as vscode from 'vscode';
|
||||
|
||||
export function fixDriveC(_path: string): string {
|
||||
const root = path.parse(_path).root;
|
||||
|
@ -19,3 +18,10 @@ export function fixDriveC(_path: string): string {
|
|||
export function anchorGlob(glob: string): string {
|
||||
return glob.startsWith('**') || glob.startsWith('/') ? glob : `/${glob}`;
|
||||
}
|
||||
|
||||
export function joinPath(resource: vscode.Uri, pathFragment: string): vscode.Uri {
|
||||
const joinedPath = path.join(resource.path || '/', pathFragment);
|
||||
return resource.with({
|
||||
path: joinedPath
|
||||
});
|
||||
}
|
|
@ -1545,9 +1545,9 @@ vscode-extension-telemetry@0.0.15:
|
|||
dependencies:
|
||||
applicationinsights "1.0.1"
|
||||
|
||||
vscode-nls@^3.2.1:
|
||||
version "3.2.2"
|
||||
resolved "https://registry.yarnpkg.com/vscode-nls/-/vscode-nls-3.2.2.tgz#3817eca5b985c2393de325197cf4e15eb2aa5350"
|
||||
vscode-nls@^3.2.4:
|
||||
version "3.2.4"
|
||||
resolved "https://registry.yarnpkg.com/vscode-nls/-/vscode-nls-3.2.4.tgz#2166b4183c8aea884d20727f5449e62be69fd398"
|
||||
|
||||
vscode-ripgrep@^1.0.1:
|
||||
version "1.0.1"
|
||||
|
|
|
@ -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/7bf8960f7042474b10b519f39339fc527907ce16",
|
||||
"version": "https://github.com/Microsoft/TypeScript-TmLanguage/commit/40288b872220e5c0b844b1de507f1749ed14589b",
|
||||
"name": "TypeScript",
|
||||
"scopeName": "source.ts",
|
||||
"patterns": [
|
||||
|
@ -4149,7 +4149,7 @@
|
|||
},
|
||||
"directives": {
|
||||
"name": "comment.line.triple-slash.directive.ts",
|
||||
"begin": "^(///)\\s*(?=<(reference|amd-dependency|amd-module)(\\s+(path|types|no-default-lib|name)\\s*=\\s*((\\'([^\\'\\\\]|\\\\\\'|\\\\)*\\')|(\\\"([^\\\"\\\\]|\\\\\\\"|\\\\)*\\\")))+\\s*/>\\s*$)",
|
||||
"begin": "^(///)\\s*(?=<(reference|amd-dependency|amd-module)(\\s+(path|types|no-default-lib|lib|name)\\s*=\\s*((\\'([^\\'\\\\]|\\\\\\'|\\\\)*\\')|(\\\"([^\\\"\\\\]|\\\\\\\"|\\\\)*\\\")))+\\s*/>\\s*$)",
|
||||
"beginCaptures": {
|
||||
"1": {
|
||||
"name": "punctuation.definition.comment.ts"
|
||||
|
@ -4177,7 +4177,7 @@
|
|||
"patterns": [
|
||||
{
|
||||
"name": "entity.other.attribute-name.directive.ts",
|
||||
"match": "path|types|no-default-lib|name"
|
||||
"match": "path|types|no-default-lib|lib|name"
|
||||
},
|
||||
{
|
||||
"name": "keyword.operator.assignment.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/7bf8960f7042474b10b519f39339fc527907ce16",
|
||||
"version": "https://github.com/Microsoft/TypeScript-TmLanguage/commit/88217b1c7d36ed5d35adc3099ba7978aabe2531b",
|
||||
"name": "TypeScriptReact",
|
||||
"scopeName": "source.tsx",
|
||||
"patterns": [
|
||||
|
@ -4115,7 +4115,7 @@
|
|||
},
|
||||
"directives": {
|
||||
"name": "comment.line.triple-slash.directive.tsx",
|
||||
"begin": "^(///)\\s*(?=<(reference|amd-dependency|amd-module)(\\s+(path|types|no-default-lib|name)\\s*=\\s*((\\'([^\\'\\\\]|\\\\\\'|\\\\)*\\')|(\\\"([^\\\"\\\\]|\\\\\\\"|\\\\)*\\\")))+\\s*/>\\s*$)",
|
||||
"begin": "^(///)\\s*(?=<(reference|amd-dependency|amd-module)(\\s+(path|types|no-default-lib|lib|name)\\s*=\\s*((\\'([^\\'\\\\]|\\\\\\'|\\\\)*\\')|(\\\"([^\\\"\\\\]|\\\\\\\"|\\\\)*\\\")))+\\s*/>\\s*$)",
|
||||
"beginCaptures": {
|
||||
"1": {
|
||||
"name": "punctuation.definition.comment.tsx"
|
||||
|
@ -4143,7 +4143,7 @@
|
|||
"patterns": [
|
||||
{
|
||||
"name": "entity.other.attribute-name.directive.tsx",
|
||||
"match": "path|types|no-default-lib|name"
|
||||
"match": "path|types|no-default-lib|lib|name"
|
||||
},
|
||||
{
|
||||
"name": "keyword.operator.assignment.tsx",
|
||||
|
@ -4664,8 +4664,8 @@
|
|||
]
|
||||
},
|
||||
"jsx-tag-in-expression": {
|
||||
"begin": "(?x)\n (?<!\\+\\+|--)(?<=[({\\[,?=>:*]|&&|\\|\\||\\?|^return|[^\\._$[:alnum:]]return|^default|[^\\._$[:alnum:]]default|^)\\s*\n (?!<\\s*[_$[:alpha:]][_$[:alnum:]]*((\\s+extends\\s+[^=>])|,)) # look ahead is not type parameter of arrow\n (?=(<)\\s*(?:([_$a-zA-Z][-$\\w.]*)(?<!\\.|-)(:))?((?:[a-z][a-z0-9]*|([_$a-zA-Z][-$\\w.]*))(?<!\\.|-))(?=((<\\s*(((keyof|infer)\\s+)|(([_$[:alpha:]][_$[:alnum:]]*|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\])|(\\'[^\\']*\\')|(\\\"[^\\\"]*\\\")|(\\`[^\\`]*\\`))(?=\\s*([\\<\\>\\,\\.\\[=]|&(?!&)|\\|(?!\\|)))))([^<>\\(]|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(?<==)\\>|\\<\\s*(((keyof|infer)\\s+)|(([_$[:alpha:]][_$[:alnum:]]*|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\])|(\\'[^\\']*\\')|(\\\"[^\\\"]*\\\")|(\\`[^\\`]*\\`))(?=\\s*([\\<\\>\\,\\.\\[=]|&(?!&)|\\|(?!\\|)))))([^<>\\(]|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(?<==)\\>)*(?!=)\\>)*(?!=)>\\s*)|(\\s+))(?!\\?)|\\/?>))",
|
||||
"end": "(?!(<)\\s*(?:([_$a-zA-Z][-$\\w.]*)(?<!\\.|-)(:))?((?:[a-z][a-z0-9]*|([_$a-zA-Z][-$\\w.]*))(?<!\\.|-))(?=((<\\s*(((keyof|infer)\\s+)|(([_$[:alpha:]][_$[:alnum:]]*|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\])|(\\'[^\\']*\\')|(\\\"[^\\\"]*\\\")|(\\`[^\\`]*\\`))(?=\\s*([\\<\\>\\,\\.\\[=]|&(?!&)|\\|(?!\\|)))))([^<>\\(]|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(?<==)\\>|\\<\\s*(((keyof|infer)\\s+)|(([_$[:alpha:]][_$[:alnum:]]*|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\])|(\\'[^\\']*\\')|(\\\"[^\\\"]*\\\")|(\\`[^\\`]*\\`))(?=\\s*([\\<\\>\\,\\.\\[=]|&(?!&)|\\|(?!\\|)))))([^<>\\(]|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(?<==)\\>)*(?!=)\\>)*(?!=)>\\s*)|(\\s+))(?!\\?)|\\/?>))",
|
||||
"begin": "(?x)\n (?<!\\+\\+|--)(?<=[({\\[,?=>:*]|&&|\\|\\||\\?|^return|[^\\._$[:alnum:]]return|^default|[^\\._$[:alnum:]]default|^)\\s*\n (?!<\\s*[_$[:alpha:]][_$[:alnum:]]*((\\s+extends\\s+[^=>])|,)) # look ahead is not type parameter of arrow\n (?=(<)\\s*(?:([_$a-zA-Z][-$\\w.]*)(?<!\\.|-)(:))?((?:[a-z][a-z0-9]*|([_$a-zA-Z][-$\\w.]*))(?<!\\.|-))(?=((<\\s*)|(\\s+))(?!\\?)|\\/?>))",
|
||||
"end": "(?!(<)\\s*(?:([_$a-zA-Z][-$\\w.]*)(?<!\\.|-)(:))?((?:[a-z][a-z0-9]*|([_$a-zA-Z][-$\\w.]*))(?<!\\.|-))(?=((<\\s*)|(\\s+))(?!\\?)|\\/?>))",
|
||||
"patterns": [
|
||||
{
|
||||
"include": "#jsx-tag"
|
||||
|
@ -4674,7 +4674,7 @@
|
|||
},
|
||||
"jsx-tag": {
|
||||
"name": "meta.tag.tsx",
|
||||
"begin": "(?=(<)\\s*(?:([_$a-zA-Z][-$\\w.]*)(?<!\\.|-)(:))?((?:[a-z][a-z0-9]*|([_$a-zA-Z][-$\\w.]*))(?<!\\.|-))(?=((<\\s*(((keyof|infer)\\s+)|(([_$[:alpha:]][_$[:alnum:]]*|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\])|(\\'[^\\']*\\')|(\\\"[^\\\"]*\\\")|(\\`[^\\`]*\\`))(?=\\s*([\\<\\>\\,\\.\\[=]|&(?!&)|\\|(?!\\|)))))([^<>\\(]|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(?<==)\\>|\\<\\s*(((keyof|infer)\\s+)|(([_$[:alpha:]][_$[:alnum:]]*|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\])|(\\'[^\\']*\\')|(\\\"[^\\\"]*\\\")|(\\`[^\\`]*\\`))(?=\\s*([\\<\\>\\,\\.\\[=]|&(?!&)|\\|(?!\\|)))))([^<>\\(]|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(?<==)\\>)*(?!=)\\>)*(?!=)>\\s*)|(\\s+))(?!\\?)|\\/?>))",
|
||||
"begin": "(?=(<)\\s*(?:([_$a-zA-Z][-$\\w.]*)(?<!\\.|-)(:))?((?:[a-z][a-z0-9]*|([_$a-zA-Z][-$\\w.]*))(?<!\\.|-))(?=((<\\s*)|(\\s+))(?!\\?)|\\/?>))",
|
||||
"end": "(/>)|(?:(</)\\s*(?:([_$a-zA-Z][-$\\w.]*)(?<!\\.|-)(:))?((?:[a-z][a-z0-9]*|([_$a-zA-Z][-$\\w.]*))(?<!\\.|-))?\\s*(>))",
|
||||
"endCaptures": {
|
||||
"1": {
|
||||
|
@ -4701,7 +4701,7 @@
|
|||
},
|
||||
"patterns": [
|
||||
{
|
||||
"begin": "(<)\\s*(?:([_$a-zA-Z][-$\\w.]*)(?<!\\.|-)(:))?((?:[a-z][a-z0-9]*|([_$a-zA-Z][-$\\w.]*))(?<!\\.|-))(?=((<\\s*(((keyof|infer)\\s+)|(([_$[:alpha:]][_$[:alnum:]]*|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\])|(\\'[^\\']*\\')|(\\\"[^\\\"]*\\\")|(\\`[^\\`]*\\`))(?=\\s*([\\<\\>\\,\\.\\[=]|&(?!&)|\\|(?!\\|)))))([^<>\\(]|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(?<==)\\>|\\<\\s*(((keyof|infer)\\s+)|(([_$[:alpha:]][_$[:alnum:]]*|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\])|(\\'[^\\']*\\')|(\\\"[^\\\"]*\\\")|(\\`[^\\`]*\\`))(?=\\s*([\\<\\>\\,\\.\\[=]|&(?!&)|\\|(?!\\|)))))([^<>\\(]|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(?<==)\\>)*(?!=)\\>)*(?!=)>\\s*)|(\\s+))(?!\\?)|\\/?>)",
|
||||
"begin": "(<)\\s*(?:([_$a-zA-Z][-$\\w.]*)(?<!\\.|-)(:))?((?:[a-z][a-z0-9]*|([_$a-zA-Z][-$\\w.]*))(?<!\\.|-))(?=((<\\s*)|(\\s+))(?!\\?)|\\/?>)",
|
||||
"beginCaptures": {
|
||||
"1": {
|
||||
"name": "punctuation.definition.tag.begin.tsx"
|
||||
|
|
|
@ -18,7 +18,7 @@
|
|||
"dependencies": {
|
||||
"semver": "4.3.6",
|
||||
"vscode-extension-telemetry": "0.0.17",
|
||||
"vscode-nls": "^3.2.1"
|
||||
"vscode-nls": "^3.2.4"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/node": "8.0.33",
|
||||
|
|
|
@ -318,20 +318,9 @@ class TypeScriptCompletionItemProvider implements vscode.CompletionItemProvider
|
|||
}
|
||||
|
||||
const enableDotCompletions = this.shouldEnableDotCompletions(document, position);
|
||||
|
||||
const completionItems: vscode.CompletionItem[] = [];
|
||||
for (const element of msg) {
|
||||
if (element.kind === PConst.Kind.warning && !completionConfiguration.nameSuggestions) {
|
||||
continue;
|
||||
}
|
||||
if (!completionConfiguration.autoImportSuggestions && element.hasAction) {
|
||||
continue;
|
||||
}
|
||||
const item = new MyCompletionItem(position, document, line.text, element, enableDotCompletions, completionConfiguration.useCodeSnippetsOnMethodSuggest);
|
||||
completionItems.push(item);
|
||||
}
|
||||
|
||||
return completionItems;
|
||||
return msg
|
||||
.filter(entry => !shouldExcludeCompletionEntry(entry, completionConfiguration))
|
||||
.map(entry => new MyCompletionItem(position, document, line.text, entry, enableDotCompletions, completionConfiguration.useCodeSnippetsOnMethodSuggest));
|
||||
}
|
||||
|
||||
public async resolveCompletionItem(
|
||||
|
@ -595,6 +584,17 @@ class TypeScriptCompletionItemProvider implements vscode.CompletionItemProvider
|
|||
}
|
||||
}
|
||||
|
||||
function shouldExcludeCompletionEntry(
|
||||
element: Proto.CompletionEntry,
|
||||
completionConfiguration: CompletionConfiguration
|
||||
) {
|
||||
return (
|
||||
(!completionConfiguration.nameSuggestions && element.kind === PConst.Kind.warning)
|
||||
|| (!completionConfiguration.quickSuggestionsForPaths &&
|
||||
(element.kind === PConst.Kind.directory || element.kind === PConst.Kind.script))
|
||||
|| (!completionConfiguration.autoImportSuggestions && element.hasAction)
|
||||
);
|
||||
}
|
||||
|
||||
export function register(
|
||||
selector: vscode.DocumentSelector,
|
||||
|
|
|
@ -0,0 +1,22 @@
|
|||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import * as assert from 'assert';
|
||||
import 'mocha';
|
||||
import { tagsMarkdownPreview } from '../utils/previewer';
|
||||
|
||||
suite('typescript.previewer', () => {
|
||||
test('Should ignore hyphens after a param tag', async () => {
|
||||
assert.strictEqual(
|
||||
tagsMarkdownPreview([
|
||||
{
|
||||
name: 'param',
|
||||
text: 'a - b'
|
||||
}
|
||||
]),
|
||||
'*@param* `a` — b');
|
||||
});
|
||||
});
|
||||
|
|
@ -27,7 +27,7 @@ function getTagBodyText(tag: Proto.JSDocTagInfo): string | undefined {
|
|||
function getTagDocumentation(tag: Proto.JSDocTagInfo): string | undefined {
|
||||
switch (tag.name) {
|
||||
case 'param':
|
||||
const body = (tag.text || '').split(/^([\w\.]+)\s*/);
|
||||
const body = (tag.text || '').split(/^([\w\.]+)\s*-?\s*/);
|
||||
if (body && body.length === 3) {
|
||||
const param = body[1];
|
||||
const doc = body[2];
|
||||
|
@ -81,4 +81,4 @@ export function addMarkdownDocumentation(
|
|||
out.appendMarkdown('\n\n' + tagsPreview);
|
||||
}
|
||||
return out;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1548,9 +1548,9 @@ vscode-extension-telemetry@0.0.17:
|
|||
dependencies:
|
||||
applicationinsights "1.0.1"
|
||||
|
||||
vscode-nls@^3.2.1:
|
||||
version "3.2.1"
|
||||
resolved "https://registry.yarnpkg.com/vscode-nls/-/vscode-nls-3.2.1.tgz#b1f3e04e8a94a715d5a7bcbc8339c51e6d74ca51"
|
||||
vscode-nls@^3.2.4:
|
||||
version "3.2.4"
|
||||
resolved "https://registry.yarnpkg.com/vscode-nls/-/vscode-nls-3.2.4.tgz#2166b4183c8aea884d20727f5449e62be69fd398"
|
||||
|
||||
vscode@^1.1.10:
|
||||
version "1.1.17"
|
||||
|
|
|
@ -511,6 +511,16 @@ suite('workspace-namespace', () => {
|
|||
// });
|
||||
// });
|
||||
|
||||
test('findTextInFiles', async () => {
|
||||
const results: vscode.TextSearchResult[] = [];
|
||||
await vscode.workspace.findTextInFiles({ pattern: 'foo' }, { include: '*.ts' }, result => {
|
||||
results.push(result);
|
||||
});
|
||||
|
||||
assert.equal(results.length, 1);
|
||||
assert.equal(vscode.workspace.asRelativePath(results[0].uri), '10linefile.ts');
|
||||
});
|
||||
|
||||
test('applyEdit', () => {
|
||||
|
||||
return vscode.workspace.openTextDocument(vscode.Uri.parse('untitled:' + join(vscode.workspace.rootPath || '', './new2.txt'))).then(doc => {
|
||||
|
@ -603,8 +613,8 @@ suite('workspace-namespace', () => {
|
|||
|
||||
let newDoc = await vscode.workspace.openTextDocument(newUri);
|
||||
assert.equal(newDoc.getText(), 'HelloFoo');
|
||||
// let doc = await vscode.workspace.openTextDocument(docUri);
|
||||
// assert.equal(doc.getText(), 'Bar');
|
||||
let doc = await vscode.workspace.openTextDocument(docUri);
|
||||
assert.equal(doc.getText(), 'Bar');
|
||||
});
|
||||
|
||||
test('WorkspaceEdit api - after saving a deleted file, it still shows up as deleted. #42667', async function () {
|
||||
|
@ -679,8 +689,7 @@ suite('workspace-namespace', () => {
|
|||
we = new vscode.WorkspaceEdit();
|
||||
we.createFile(docUri, { overwrite: true });
|
||||
assert.ok(await vscode.workspace.applyEdit(we));
|
||||
// todo@ben
|
||||
// assert.equal((await vscode.workspace.openTextDocument(docUri)).getText(), '');
|
||||
assert.equal((await vscode.workspace.openTextDocument(docUri)).getText(), '');
|
||||
});
|
||||
|
||||
test('WorkspaceEdit: create & ignoreIfExists', async function () {
|
||||
|
|
|
@ -49,7 +49,7 @@
|
|||
"vscode-nsfw": "1.0.17",
|
||||
"vscode-ripgrep": "^1.0.1",
|
||||
"vscode-textmate": "^4.0.1",
|
||||
"vscode-xterm": "3.5.0-beta17",
|
||||
"vscode-xterm": "3.6.0-beta2",
|
||||
"yauzl": "^2.9.1"
|
||||
},
|
||||
"devDependencies": {
|
||||
|
|
13
src/bootstrap-amd.js
vendored
13
src/bootstrap-amd.js
vendored
|
@ -29,6 +29,8 @@ function readFile(file) {
|
|||
});
|
||||
}
|
||||
|
||||
const writeFile = (file, content) => new Promise((c, e) => fs.writeFile(file, content, 'utf8', err => err ? e(err) : c()));
|
||||
|
||||
var rawNlsConfig = process.env['VSCODE_NLS_CONFIG'];
|
||||
var nlsConfig = rawNlsConfig ? JSON.parse(rawNlsConfig) : { availableLanguages: {} };
|
||||
|
||||
|
@ -46,8 +48,15 @@ if (nlsConfig._resolvedLanguagePackCoreLocation) {
|
|||
let json = JSON.parse(content);
|
||||
bundles[bundle] = json;
|
||||
cb(undefined, json);
|
||||
})
|
||||
.catch(cb);
|
||||
}).catch((error) => {
|
||||
try {
|
||||
if (nlsConfig._corruptedFile) {
|
||||
writeFile(nlsConfig._corruptedFile, 'corrupted').catch(function (error) { console.error(error); });
|
||||
}
|
||||
} finally {
|
||||
cb(error, undefined);
|
||||
}
|
||||
});
|
||||
};
|
||||
}
|
||||
|
||||
|
|
164
src/main.js
164
src/main.js
|
@ -100,6 +100,19 @@ const args = minimist(process.argv, {
|
|||
]
|
||||
});
|
||||
|
||||
function getUserDataPath() {
|
||||
if (isPortable) {
|
||||
return path.join(portableDataPath, 'user-data');
|
||||
}
|
||||
|
||||
return path.resolve(args['user-data-dir'] || paths.getDefaultUserDataPath(process.platform));
|
||||
}
|
||||
|
||||
const userDataPath = getUserDataPath();
|
||||
|
||||
// Set userData path before app 'ready' event and call to process.chdir
|
||||
app.setPath('userData', userDataPath);
|
||||
|
||||
//#region NLS
|
||||
function stripComments(content) {
|
||||
let regexp = /("(?:[^\\\"]*(?:\\.)?)*")|('(?:[^\\\']*(?:\\.)?)*')|(\/\*(?:\r?\n|.)*?\*\/)|(\/{2,}.*?(?:(?:\r?\n)|$))/g;
|
||||
|
@ -130,6 +143,10 @@ const exists = file => new Promise(c => fs.exists(file, c));
|
|||
const readFile = file => new Promise((c, e) => fs.readFile(file, 'utf8', (err, data) => err ? e(err) : c(data)));
|
||||
const writeFile = (file, content) => new Promise((c, e) => fs.writeFile(file, content, 'utf8', err => err ? e(err) : c()));
|
||||
const touch = file => new Promise((c, e) => { const d = new Date(); fs.utimes(file, d, d, err => err ? e(err) : c()); });
|
||||
const lstat = file => new Promise((c, e) => fs.lstat(file, (err, stats) => err ? e(err) : c(stats)));
|
||||
const readdir = dir => new Promise((c, e) => fs.readdir(dir, (err, files) => err ? e(err) : c(files)));
|
||||
const rmdir = dir => new Promise((c, e) => fs.rmdir(dir, err => err ? e(err) : c(undefined)));
|
||||
const unlink = file => new Promise((c, e) => fs.unlink(file, err => err ? e(err) : c(undefined)));
|
||||
|
||||
function mkdirp(dir) {
|
||||
return mkdir(dir).then(null, err => {
|
||||
|
@ -145,6 +162,23 @@ function mkdirp(dir) {
|
|||
});
|
||||
}
|
||||
|
||||
function rimraf(location) {
|
||||
return lstat(location).then(stat => {
|
||||
if (stat.isDirectory() && !stat.isSymbolicLink()) {
|
||||
return readdir(location)
|
||||
.then(children => Promise.all(children.map(child => rimraf(path.join(location, child)))))
|
||||
.then(() => rmdir(location));
|
||||
} else {
|
||||
return unlink(location);
|
||||
}
|
||||
}, (err) => {
|
||||
if (err.code === 'ENOENT') {
|
||||
return void 0;
|
||||
}
|
||||
throw err;
|
||||
});
|
||||
}
|
||||
|
||||
function resolveJSFlags(...jsFlags) {
|
||||
|
||||
if (args['js-flags']) {
|
||||
|
@ -169,8 +203,7 @@ function getUserDefinedLocale() {
|
|||
return Promise.resolve(locale.toLowerCase());
|
||||
}
|
||||
|
||||
let userData = app.getPath('userData');
|
||||
let localeConfig = path.join(userData, 'User', 'locale.json');
|
||||
let localeConfig = path.join(userDataPath, 'User', 'locale.json');
|
||||
return exists(localeConfig).then((result) => {
|
||||
if (result) {
|
||||
return readFile(localeConfig).then((content) => {
|
||||
|
@ -189,8 +222,7 @@ function getUserDefinedLocale() {
|
|||
}
|
||||
|
||||
function getLanguagePackConfigurations() {
|
||||
let userData = app.getPath('userData');
|
||||
let configFile = path.join(userData, 'languagepacks.json');
|
||||
let configFile = path.join(userDataPath, 'languagepacks.json');
|
||||
try {
|
||||
return require(configFile);
|
||||
} catch (err) {
|
||||
|
@ -229,8 +261,6 @@ function getNLSConfiguration(locale) {
|
|||
return Promise.resolve({ locale: locale, availableLanguages: {} });
|
||||
}
|
||||
|
||||
let userData = app.getPath('userData');
|
||||
|
||||
// We have a built version so we have extracted nls file. Try to find
|
||||
// the right file to use.
|
||||
|
||||
|
@ -271,65 +301,78 @@ function getNLSConfiguration(locale) {
|
|||
return defaultResult(initialLocale);
|
||||
}
|
||||
let packId = packConfig.hash + '.' + locale;
|
||||
let cacheRoot = path.join(userData, 'clp', packId);
|
||||
let cacheRoot = path.join(userDataPath, 'clp', packId);
|
||||
let coreLocation = path.join(cacheRoot, commit);
|
||||
let translationsConfigFile = path.join(cacheRoot, 'tcf.json');
|
||||
let corruptedFile = path.join(cacheRoot, 'corrupted.info');
|
||||
let result = {
|
||||
locale: initialLocale,
|
||||
availableLanguages: { '*': locale },
|
||||
_languagePackId: packId,
|
||||
_translationsConfigFile: translationsConfigFile,
|
||||
_cacheRoot: cacheRoot,
|
||||
_resolvedLanguagePackCoreLocation: coreLocation
|
||||
_resolvedLanguagePackCoreLocation: coreLocation,
|
||||
_corruptedFile: corruptedFile
|
||||
};
|
||||
return exists(coreLocation).then((fileExists) => {
|
||||
if (fileExists) {
|
||||
// We don't wait for this. No big harm if we can't touch
|
||||
touch(coreLocation).catch(() => { });
|
||||
perf.mark('nlsGeneration:end');
|
||||
return result;
|
||||
return exists(corruptedFile).then((corrupted) => {
|
||||
// The nls cache directory is corrupted.
|
||||
let toDelete;
|
||||
if (corrupted) {
|
||||
toDelete = rimraf(cacheRoot);
|
||||
} else {
|
||||
toDelete = Promise.resolve(undefined);
|
||||
}
|
||||
return mkdirp(coreLocation).then(() => {
|
||||
return Promise.all([readFile(path.join(__dirname, 'nls.metadata.json')), readFile(mainPack)]);
|
||||
}).then((values) => {
|
||||
let metadata = JSON.parse(values[0]);
|
||||
let packData = JSON.parse(values[1]).contents;
|
||||
let bundles = Object.keys(metadata.bundles);
|
||||
let writes = [];
|
||||
for (let bundle of bundles) {
|
||||
let modules = metadata.bundles[bundle];
|
||||
let target = Object.create(null);
|
||||
for (let module of modules) {
|
||||
let keys = metadata.keys[module];
|
||||
let defaultMessages = metadata.messages[module];
|
||||
let translations = packData[module];
|
||||
let targetStrings;
|
||||
if (translations) {
|
||||
targetStrings = [];
|
||||
for (let i = 0; i < keys.length; i++) {
|
||||
let elem = keys[i];
|
||||
let key = typeof elem === 'string' ? elem : elem.key;
|
||||
let translatedMessage = translations[key];
|
||||
if (translatedMessage === undefined) {
|
||||
translatedMessage = defaultMessages[i];
|
||||
}
|
||||
targetStrings.push(translatedMessage);
|
||||
}
|
||||
} else {
|
||||
targetStrings = defaultMessages;
|
||||
}
|
||||
target[module] = targetStrings;
|
||||
return toDelete.then(() => {
|
||||
return exists(coreLocation).then((fileExists) => {
|
||||
if (fileExists) {
|
||||
// We don't wait for this. No big harm if we can't touch
|
||||
touch(coreLocation).catch(() => { });
|
||||
perf.mark('nlsGeneration:end');
|
||||
return result;
|
||||
}
|
||||
writes.push(writeFile(path.join(coreLocation, bundle.replace(/\//g, '!') + '.nls.json'), JSON.stringify(target)));
|
||||
}
|
||||
writes.push(writeFile(translationsConfigFile, JSON.stringify(packConfig.translations)));
|
||||
return Promise.all(writes);
|
||||
}).then(() => {
|
||||
perf.mark('nlsGeneration:end');
|
||||
return result;
|
||||
}).catch((err) => {
|
||||
console.error('Generating translation files failed.', err);
|
||||
return defaultResult(locale);
|
||||
return mkdirp(coreLocation).then(() => {
|
||||
return Promise.all([readFile(path.join(__dirname, 'nls.metadata.json')), readFile(mainPack)]);
|
||||
}).then((values) => {
|
||||
let metadata = JSON.parse(values[0]);
|
||||
let packData = JSON.parse(values[1]).contents;
|
||||
let bundles = Object.keys(metadata.bundles);
|
||||
let writes = [];
|
||||
for (let bundle of bundles) {
|
||||
let modules = metadata.bundles[bundle];
|
||||
let target = Object.create(null);
|
||||
for (let module of modules) {
|
||||
let keys = metadata.keys[module];
|
||||
let defaultMessages = metadata.messages[module];
|
||||
let translations = packData[module];
|
||||
let targetStrings;
|
||||
if (translations) {
|
||||
targetStrings = [];
|
||||
for (let i = 0; i < keys.length; i++) {
|
||||
let elem = keys[i];
|
||||
let key = typeof elem === 'string' ? elem : elem.key;
|
||||
let translatedMessage = translations[key];
|
||||
if (translatedMessage === undefined) {
|
||||
translatedMessage = defaultMessages[i];
|
||||
}
|
||||
targetStrings.push(translatedMessage);
|
||||
}
|
||||
} else {
|
||||
targetStrings = defaultMessages;
|
||||
}
|
||||
target[module] = targetStrings;
|
||||
}
|
||||
writes.push(writeFile(path.join(coreLocation, bundle.replace(/\//g, '!') + '.nls.json'), JSON.stringify(target)));
|
||||
}
|
||||
writes.push(writeFile(translationsConfigFile, JSON.stringify(packConfig.translations)));
|
||||
return Promise.all(writes);
|
||||
}).then(() => {
|
||||
perf.mark('nlsGeneration:end');
|
||||
return result;
|
||||
}).catch((err) => {
|
||||
console.error('Generating translation files failed.', err);
|
||||
return defaultResult(locale);
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
@ -368,23 +411,12 @@ const nodeCachedDataDir = new class {
|
|||
if (!commit) {
|
||||
return undefined;
|
||||
}
|
||||
return path.join(app.getPath('userData'), 'CachedData', commit);
|
||||
return path.join(userDataPath, 'CachedData', commit);
|
||||
}
|
||||
};
|
||||
|
||||
//#endregion
|
||||
|
||||
function getUserDataPath() {
|
||||
if (isPortable) {
|
||||
return path.join(portableDataPath, 'user-data');
|
||||
}
|
||||
|
||||
return path.resolve(args['user-data-dir'] || paths.getDefaultUserDataPath(process.platform));
|
||||
}
|
||||
|
||||
// Set userData path before app 'ready' event and call to process.chdir
|
||||
app.setPath('userData', getUserDataPath());
|
||||
|
||||
// Update cwd based on environment and platform
|
||||
try {
|
||||
if (process.platform === 'win32') {
|
||||
|
|
|
@ -18,5 +18,10 @@
|
|||
"typeRoots": [
|
||||
"typings"
|
||||
]
|
||||
}
|
||||
},
|
||||
"exclude": [
|
||||
"../out",
|
||||
"../out-build",
|
||||
"../out-vscode"
|
||||
]
|
||||
}
|
||||
|
|
9
src/typings/vscode-xterm.d.ts
vendored
9
src/typings/vscode-xterm.d.ts
vendored
|
@ -124,6 +124,15 @@ declare module 'vscode-xterm' {
|
|||
*/
|
||||
macOptionIsMeta?: boolean;
|
||||
|
||||
/**
|
||||
* Whether holding a modifier key will force normal selection behavior,
|
||||
* regardless of whether the terminal is in mouse events mode. This will
|
||||
* also prevent mouse events from being emitted by the terminal. For example,
|
||||
* this allows you to use xterm.js' regular selection inside tmux with
|
||||
* mouse mode enabled.
|
||||
*/
|
||||
macOptionClickForcesSelection?: boolean;
|
||||
|
||||
/**
|
||||
* (EXPERIMENTAL) The type of renderer to use, this allows using the
|
||||
* fallback DOM renderer when canvas is too slow for the environment. The
|
||||
|
|
|
@ -5,9 +5,8 @@
|
|||
'use strict';
|
||||
|
||||
import 'vs/css!./builder';
|
||||
import { TPromise } from 'vs/base/common/winjs.base';
|
||||
import * as types from 'vs/base/common/types';
|
||||
import { IDisposable, dispose } from 'vs/base/common/lifecycle';
|
||||
import { IDisposable, dispose, toDisposable } from 'vs/base/common/lifecycle';
|
||||
import * as strings from 'vs/base/common/strings';
|
||||
import * as assert from 'vs/base/common/assert';
|
||||
import * as DOM from 'vs/base/browser/dom';
|
||||
|
@ -907,7 +906,7 @@ export class Builder implements IDisposable {
|
|||
this.attr('aria-hidden', 'false');
|
||||
|
||||
// Cancel any pending showDelayed() invocation
|
||||
this.cancelVisibilityPromise();
|
||||
this.cancelVisibilityTimeout();
|
||||
|
||||
return this;
|
||||
}
|
||||
|
@ -922,15 +921,15 @@ export class Builder implements IDisposable {
|
|||
showDelayed(delay: number): Builder {
|
||||
|
||||
// Cancel any pending showDelayed() invocation
|
||||
this.cancelVisibilityPromise();
|
||||
this.cancelVisibilityTimeout();
|
||||
|
||||
let promise = TPromise.timeout(delay);
|
||||
this.setProperty(VISIBILITY_BINDING_ID, promise);
|
||||
|
||||
promise.done(() => {
|
||||
// Install new delay for showing
|
||||
const handle = setTimeout(() => {
|
||||
this.removeProperty(VISIBILITY_BINDING_ID);
|
||||
this.show();
|
||||
});
|
||||
}, delay);
|
||||
|
||||
this.setProperty(VISIBILITY_BINDING_ID, toDisposable(() => clearTimeout(handle)));
|
||||
|
||||
return this;
|
||||
}
|
||||
|
@ -945,7 +944,7 @@ export class Builder implements IDisposable {
|
|||
this.attr('aria-hidden', 'true');
|
||||
|
||||
// Cancel any pending showDelayed() invocation
|
||||
this.cancelVisibilityPromise();
|
||||
this.cancelVisibilityTimeout();
|
||||
|
||||
return this;
|
||||
}
|
||||
|
@ -957,10 +956,10 @@ export class Builder implements IDisposable {
|
|||
return this.hasClass('monaco-builder-hidden') || this.currentElement.style.display === 'none';
|
||||
}
|
||||
|
||||
private cancelVisibilityPromise(): void {
|
||||
let promise: TPromise<void> = this.getProperty(VISIBILITY_BINDING_ID);
|
||||
if (promise) {
|
||||
promise.cancel();
|
||||
private cancelVisibilityTimeout(): void {
|
||||
const visibilityDisposable = this.getProperty(VISIBILITY_BINDING_ID) as IDisposable;
|
||||
if (visibilityDisposable) {
|
||||
visibilityDisposable.dispose();
|
||||
this.removeProperty(VISIBILITY_BINDING_ID);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -819,6 +819,7 @@ export const EventType = {
|
|||
MOUSE_OVER: 'mouseover',
|
||||
MOUSE_MOVE: 'mousemove',
|
||||
MOUSE_OUT: 'mouseout',
|
||||
MOUSE_ENTER: 'mouseenter',
|
||||
MOUSE_LEAVE: 'mouseleave',
|
||||
CONTEXT_MENU: 'contextmenu',
|
||||
WHEEL: 'wheel',
|
||||
|
|
40
src/vs/base/browser/ui/breadcrumbs/breadcrumbsWidget.css
Normal file
40
src/vs/base/browser/ui/breadcrumbs/breadcrumbsWidget.css
Normal file
|
@ -0,0 +1,40 @@
|
|||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
.monaco-breadcrumbs {
|
||||
user-select: none;
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
flex-wrap: nowrap;
|
||||
justify-content: flex-start;
|
||||
}
|
||||
|
||||
.monaco-breadcrumbs .monaco-breadcrumb-item {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
flex: 0 1 auto;
|
||||
white-space: nowrap;
|
||||
cursor: default;
|
||||
align-self: center;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
.monaco-breadcrumbs .monaco-breadcrumb-item:not(:last-child)::after {
|
||||
background-image: url(./collapsed.svg);
|
||||
width: 16px;
|
||||
height: 16px;
|
||||
display: inline-block;
|
||||
background-size: 16px;
|
||||
background-position: 50% 50%;
|
||||
content: ' ';
|
||||
}
|
||||
|
||||
.vs-dark .monaco-breadcrumbs .monaco-breadcrumb-item:not(:last-child)::after {
|
||||
background-image: url(./collpased-dark.svg);
|
||||
}
|
||||
|
||||
.monaco-breadcrumbs .monaco-breadcrumb-item.focused {
|
||||
font-weight: bold;
|
||||
}
|
248
src/vs/base/browser/ui/breadcrumbs/breadcrumbsWidget.ts
Normal file
248
src/vs/base/browser/ui/breadcrumbs/breadcrumbsWidget.ts
Normal file
|
@ -0,0 +1,248 @@
|
|||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
'use strict';
|
||||
|
||||
import 'vs/css!./breadcrumbsWidget';
|
||||
import * as dom from 'vs/base/browser/dom';
|
||||
import { DomScrollableElement } from 'vs/base/browser/ui/scrollbar/scrollableElement';
|
||||
import { ScrollbarVisibility } from 'vs/base/common/scrollable';
|
||||
import { IDisposable, dispose } from 'vs/base/common/lifecycle';
|
||||
import { IMouseEvent } from 'vs/base/browser/mouseEvent';
|
||||
import { Event, Emitter } from 'vs/base/common/event';
|
||||
import { Color } from 'vs/base/common/color';
|
||||
import { commonPrefixLength, tail } from 'vs/base/common/arrays';
|
||||
|
||||
export abstract class BreadcrumbsItem {
|
||||
dispose(): void { }
|
||||
abstract equals(other: BreadcrumbsItem): boolean;
|
||||
abstract render(container: HTMLElement): void;
|
||||
}
|
||||
|
||||
export class SimpleBreadcrumbsItem extends BreadcrumbsItem {
|
||||
|
||||
constructor(
|
||||
readonly text: string,
|
||||
readonly title: string = text
|
||||
) {
|
||||
super();
|
||||
}
|
||||
|
||||
equals(other: this) {
|
||||
return other === this || other instanceof SimpleBreadcrumbsItem && other.text === this.text && other.title === this.title;
|
||||
}
|
||||
|
||||
render(container: HTMLElement): void {
|
||||
let node = document.createElement('div');
|
||||
node.title = this.title;
|
||||
node.innerText = this.text;
|
||||
container.appendChild(node);
|
||||
}
|
||||
}
|
||||
|
||||
export interface IBreadcrumbsWidgetStyles {
|
||||
breadcrumbsBackground?: Color;
|
||||
breadcrumbsActiveForeground?: Color;
|
||||
breadcrumbsInactiveForeground?: Color;
|
||||
}
|
||||
|
||||
export interface IBreadcrumbsItemEvent {
|
||||
item: BreadcrumbsItem;
|
||||
node: HTMLElement;
|
||||
}
|
||||
|
||||
export class BreadcrumbsWidget {
|
||||
|
||||
private readonly _disposables = new Array<IDisposable>();
|
||||
private readonly _domNode: HTMLDivElement;
|
||||
private readonly _styleElement: HTMLStyleElement;
|
||||
private readonly _scrollable: DomScrollableElement;
|
||||
|
||||
private readonly _onDidSelectItem = new Emitter<IBreadcrumbsItemEvent>();
|
||||
private readonly _onDidFocusItem = new Emitter<IBreadcrumbsItemEvent>();
|
||||
private readonly _onDidChangeFocus = new Emitter<boolean>();
|
||||
|
||||
readonly onDidSelectItem: Event<IBreadcrumbsItemEvent> = this._onDidSelectItem.event;
|
||||
readonly onDidFocusItem: Event<IBreadcrumbsItemEvent> = this._onDidFocusItem.event;
|
||||
readonly onDidChangeFocus: Event<boolean> = this._onDidChangeFocus.event;
|
||||
|
||||
private readonly _items = new Array<BreadcrumbsItem>();
|
||||
private readonly _nodes = new Array<HTMLDivElement>();
|
||||
private readonly _freeNodes = new Array<HTMLDivElement>();
|
||||
|
||||
private _focusedItemIdx: number = -1;
|
||||
private _selectedItemIdx: number = -1;
|
||||
|
||||
constructor(
|
||||
container: HTMLElement
|
||||
) {
|
||||
this._domNode = document.createElement('div');
|
||||
this._domNode.className = 'monaco-breadcrumbs';
|
||||
this._domNode.tabIndex = -1;
|
||||
this._scrollable = new DomScrollableElement(this._domNode, {
|
||||
vertical: ScrollbarVisibility.Hidden,
|
||||
horizontal: ScrollbarVisibility.Auto,
|
||||
horizontalScrollbarSize: 3,
|
||||
useShadows: false
|
||||
});
|
||||
this._disposables.push(this._scrollable);
|
||||
this._disposables.push(dom.addStandardDisposableListener(this._domNode, 'click', e => this._onClick(e)));
|
||||
container.appendChild(this._scrollable.getDomNode());
|
||||
|
||||
this._styleElement = dom.createStyleSheet(this._domNode);
|
||||
|
||||
let focusTracker = dom.trackFocus(this._domNode);
|
||||
this._disposables.push(focusTracker);
|
||||
this._disposables.push(focusTracker.onDidBlur(_ => this._onDidChangeFocus.fire(false)));
|
||||
this._disposables.push(focusTracker.onDidFocus(_ => this._onDidChangeFocus.fire(true)));
|
||||
}
|
||||
|
||||
dispose(): void {
|
||||
dispose(this._disposables);
|
||||
this._domNode.remove();
|
||||
this._disposables.length = 0;
|
||||
this._nodes.length = 0;
|
||||
this._freeNodes.length = 0;
|
||||
}
|
||||
|
||||
layout(dim: dom.Dimension): void {
|
||||
if (!dim) {
|
||||
this._scrollable.scanDomNode();
|
||||
} else {
|
||||
this._domNode.style.width = `${dim.width}px`;
|
||||
this._domNode.style.height = `${dim.height}px`;
|
||||
this._scrollable.scanDomNode();
|
||||
}
|
||||
}
|
||||
|
||||
style(style: IBreadcrumbsWidgetStyles): void {
|
||||
let content = '';
|
||||
if (style.breadcrumbsBackground) {
|
||||
content += `.monaco-breadcrumbs { background-color: ${style.breadcrumbsBackground}}`;
|
||||
}
|
||||
if (style.breadcrumbsActiveForeground) {
|
||||
content += `.monaco-breadcrumbs:focus .monaco-breadcrumb-item { color: ${style.breadcrumbsActiveForeground}}\n`;
|
||||
}
|
||||
if (style.breadcrumbsInactiveForeground) {
|
||||
content += `.monaco-breadcrumbs .monaco-breadcrumb-item { color: ${style.breadcrumbsInactiveForeground}}\n`;
|
||||
}
|
||||
if (this._styleElement.innerHTML !== content) {
|
||||
this._styleElement.innerHTML = content;
|
||||
}
|
||||
}
|
||||
|
||||
domFocus(): void {
|
||||
const focused = this.getFocused() || tail(this._items);
|
||||
this.setFocused(focused);
|
||||
this._domNode.focus();
|
||||
}
|
||||
|
||||
getFocused(): BreadcrumbsItem {
|
||||
return this._items[this._focusedItemIdx];
|
||||
}
|
||||
|
||||
setFocused(item: BreadcrumbsItem): void {
|
||||
this._focus(this._items.indexOf(item));
|
||||
}
|
||||
|
||||
focusPrev(): any {
|
||||
this._focus((this._focusedItemIdx - 1 + this._nodes.length) % this._nodes.length);
|
||||
this._domNode.focus();
|
||||
}
|
||||
|
||||
focusNext(): any {
|
||||
this._focus((this._focusedItemIdx + 1) % this._nodes.length);
|
||||
this._domNode.focus();
|
||||
}
|
||||
|
||||
private _focus(nth: number): void {
|
||||
this._focusedItemIdx = -1;
|
||||
for (let i = 0; i < this._nodes.length; i++) {
|
||||
const node = this._nodes[i];
|
||||
if (i !== nth) {
|
||||
dom.removeClass(node, 'focused');
|
||||
} else {
|
||||
this._focusedItemIdx = i;
|
||||
dom.addClass(node, 'focused');
|
||||
}
|
||||
}
|
||||
this._onDidFocusItem.fire({ item: this._items[this._focusedItemIdx], node: this._nodes[this._focusedItemIdx] });
|
||||
}
|
||||
|
||||
getSelected(): BreadcrumbsItem {
|
||||
return this._items[this._selectedItemIdx];
|
||||
}
|
||||
|
||||
setSelected(item: BreadcrumbsItem): void {
|
||||
this._select(this._items.indexOf(item));
|
||||
}
|
||||
|
||||
private _select(nth: number): void {
|
||||
this._selectedItemIdx = -1;
|
||||
for (let i = 0; i < this._nodes.length; i++) {
|
||||
const node = this._nodes[i];
|
||||
if (i !== nth) {
|
||||
dom.removeClass(node, 'selected');
|
||||
} else {
|
||||
this._selectedItemIdx = i;
|
||||
dom.addClass(node, 'selected');
|
||||
}
|
||||
}
|
||||
this._onDidSelectItem.fire({ item: this._items[this._selectedItemIdx], node: this._nodes[this._selectedItemIdx] });
|
||||
}
|
||||
|
||||
setItems(items: BreadcrumbsItem[]): void {
|
||||
let prefix = commonPrefixLength(this._items, items, (a, b) => a.equals(b));
|
||||
let removed = this._items.splice(prefix, this._items.length - prefix, ...items.slice(prefix));
|
||||
this._render(prefix);
|
||||
dispose(removed);
|
||||
if (prefix >= this._focusedItemIdx) {
|
||||
this._focus(-1);
|
||||
}
|
||||
}
|
||||
|
||||
private _render(start: number): void {
|
||||
for (; start < this._items.length && start < this._nodes.length; start++) {
|
||||
let item = this._items[start];
|
||||
let node = this._nodes[start];
|
||||
this._renderItem(item, node);
|
||||
}
|
||||
// case a: more nodes -> remove them
|
||||
for (; start < this._nodes.length; start++) {
|
||||
this._nodes[start].remove();
|
||||
this._freeNodes.push(this._nodes[start]);
|
||||
}
|
||||
this._nodes.length = this._items.length;
|
||||
|
||||
// case b: more items -> render them
|
||||
for (; start < this._items.length; start++) {
|
||||
let item = this._items[start];
|
||||
let node = this._freeNodes.length > 0 ? this._freeNodes.pop() : document.createElement('div');
|
||||
this._renderItem(item, node);
|
||||
this._domNode.appendChild(node);
|
||||
this._nodes[start] = node;
|
||||
}
|
||||
this.layout(undefined);
|
||||
}
|
||||
|
||||
private _renderItem(item: BreadcrumbsItem, container: HTMLDivElement): void {
|
||||
dom.clearNode(container);
|
||||
container.className = '';
|
||||
item.render(container);
|
||||
dom.append(container);
|
||||
dom.addClass(container, 'monaco-breadcrumb-item');
|
||||
}
|
||||
|
||||
private _onClick(event: IMouseEvent): void {
|
||||
for (let el = event.target; el; el = el.parentElement) {
|
||||
let idx = this._nodes.indexOf(el as any);
|
||||
if (idx >= 0) {
|
||||
this._focus(idx);
|
||||
this._select(idx);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
1
src/vs/base/browser/ui/breadcrumbs/collapsed.svg
Executable file
1
src/vs/base/browser/ui/breadcrumbs/collapsed.svg
Executable file
|
@ -0,0 +1 @@
|
|||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16"><path fill="#646465" d="M6 4v8l4-4-4-4zm1 2.414L8.586 8 7 9.586V6.414z"/></svg>
|
After Width: | Height: | Size: 139 B |
1
src/vs/base/browser/ui/breadcrumbs/collpased-dark.svg
Executable file
1
src/vs/base/browser/ui/breadcrumbs/collpased-dark.svg
Executable file
|
@ -0,0 +1 @@
|
|||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16"><path fill="#E8E8E8" d="M6 4v8l4-4-4-4zm1 2.414L8.586 8 7 9.586V6.414z"/></svg>
|
After Width: | Height: | Size: 139 B |
|
@ -4,10 +4,13 @@
|
|||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
.monaco-count-badge {
|
||||
padding: 0.2em 0.5em;
|
||||
padding: 0.3em 0.5em;
|
||||
border-radius: 1em;
|
||||
font-size: 85%;
|
||||
min-width: 1.6em;
|
||||
line-height: 1em;
|
||||
font-weight: normal;
|
||||
text-align: center;
|
||||
display: inline;
|
||||
display: inline-block;
|
||||
box-sizing: border-box;
|
||||
}
|
|
@ -279,10 +279,15 @@ export class Grid<T extends IView> implements IDisposable {
|
|||
getViewSize(view: T): number {
|
||||
const location = this.getViewLocation(view);
|
||||
const viewSize = this.gridview.getViewSize(location);
|
||||
|
||||
return getLocationOrientation(this.orientation, location) === Orientation.HORIZONTAL ? viewSize.width : viewSize.height;
|
||||
}
|
||||
|
||||
// TODO@joao cleanup
|
||||
getViewSize2(view: T): { width: number; height: number; } {
|
||||
const location = this.getViewLocation(view);
|
||||
return this.gridview.getViewSize(location);
|
||||
}
|
||||
|
||||
maximizeViewSize(view: T): void {
|
||||
const location = this.getViewLocation(view);
|
||||
this.gridview.maximizeViewSize(location);
|
||||
|
|
|
@ -9,7 +9,7 @@ import 'vs/css!./gridview';
|
|||
import { Event, anyEvent, Emitter, mapEvent, Relay } from 'vs/base/common/event';
|
||||
import { Orientation, Sash } from 'vs/base/browser/ui/sash/sash';
|
||||
import { SplitView, IView as ISplitView, Sizing, ISplitViewStyles } from 'vs/base/browser/ui/splitview/splitview';
|
||||
import { empty as EmptyDisposable, IDisposable, toDisposable } from 'vs/base/common/lifecycle';
|
||||
import { Disposable, IDisposable, toDisposable } from 'vs/base/common/lifecycle';
|
||||
import { $ } from 'vs/base/browser/dom';
|
||||
import { tail2 as tail } from 'vs/base/common/arrays';
|
||||
import { Color } from 'vs/base/common/color';
|
||||
|
@ -122,12 +122,12 @@ class BranchNode implements ISplitView, IDisposable {
|
|||
private _onDidChange = new Emitter<number | undefined>();
|
||||
readonly onDidChange: Event<number | undefined> = this._onDidChange.event;
|
||||
|
||||
private childrenChangeDisposable: IDisposable = EmptyDisposable;
|
||||
private childrenChangeDisposable: IDisposable = Disposable.None;
|
||||
|
||||
private _onDidSashReset = new Emitter<number[]>();
|
||||
readonly onDidSashReset: Event<number[]> = this._onDidSashReset.event;
|
||||
private splitviewSashResetDisposable: IDisposable = EmptyDisposable;
|
||||
private childrenSashResetDisposable: IDisposable = EmptyDisposable;
|
||||
private splitviewSashResetDisposable: IDisposable = Disposable.None;
|
||||
private childrenSashResetDisposable: IDisposable = Disposable.None;
|
||||
|
||||
get orthogonalStartSash(): Sash | undefined { return this.splitview.orthogonalStartSash; }
|
||||
set orthogonalStartSash(sash: Sash | undefined) { this.splitview.orthogonalStartSash = sash; }
|
||||
|
@ -280,22 +280,22 @@ class BranchNode implements ISplitView, IDisposable {
|
|||
|
||||
trySet2x2(other: BranchNode): IDisposable {
|
||||
if (this.children.length !== 2 || other.children.length !== 2) {
|
||||
return EmptyDisposable;
|
||||
return Disposable.None;
|
||||
}
|
||||
|
||||
if (this.getChildSize(0) !== other.getChildSize(0)) {
|
||||
return EmptyDisposable;
|
||||
return Disposable.None;
|
||||
}
|
||||
|
||||
const [firstChild, secondChild] = this.children;
|
||||
const [otherFirstChild, otherSecondChild] = other.children;
|
||||
|
||||
if (!(firstChild instanceof LeafNode) || !(secondChild instanceof LeafNode)) {
|
||||
return EmptyDisposable;
|
||||
return Disposable.None;
|
||||
}
|
||||
|
||||
if (!(otherFirstChild instanceof LeafNode) || !(otherSecondChild instanceof LeafNode)) {
|
||||
return EmptyDisposable;
|
||||
return Disposable.None;
|
||||
}
|
||||
|
||||
if (this.orientation === Orientation.VERTICAL) {
|
||||
|
@ -485,7 +485,7 @@ export class GridView implements IDisposable {
|
|||
private onDidSashResetRelay = new Relay<number[]>();
|
||||
readonly onDidSashReset: Event<number[]> = this.onDidSashResetRelay.event;
|
||||
|
||||
private disposable2x2: IDisposable = EmptyDisposable;
|
||||
private disposable2x2: IDisposable = Disposable.None;
|
||||
|
||||
private get root(): BranchNode {
|
||||
return this._root;
|
||||
|
@ -550,7 +550,7 @@ export class GridView implements IDisposable {
|
|||
|
||||
addView(view: IView, size: number | Sizing, location: number[]): void {
|
||||
this.disposable2x2.dispose();
|
||||
this.disposable2x2 = EmptyDisposable;
|
||||
this.disposable2x2 = Disposable.None;
|
||||
|
||||
const [rest, index] = tail(location);
|
||||
const [pathToParent, parent] = this.getNode(rest);
|
||||
|
@ -582,7 +582,7 @@ export class GridView implements IDisposable {
|
|||
|
||||
removeView(location: number[], sizing?: Sizing): IView {
|
||||
this.disposable2x2.dispose();
|
||||
this.disposable2x2 = EmptyDisposable;
|
||||
this.disposable2x2 = Disposable.None;
|
||||
|
||||
const [rest, index] = tail(location);
|
||||
const [pathToParent, parent] = this.getNode(rest);
|
||||
|
@ -783,7 +783,7 @@ export class GridView implements IDisposable {
|
|||
|
||||
trySet2x2(): void {
|
||||
this.disposable2x2.dispose();
|
||||
this.disposable2x2 = EmptyDisposable;
|
||||
this.disposable2x2 = Disposable.None;
|
||||
|
||||
if (this.root.children.length !== 2) {
|
||||
return;
|
||||
|
|
|
@ -282,6 +282,11 @@ export class ListView<T> implements ISpliceable<T>, IDisposable {
|
|||
private insertItemInDOM(index: number, beforeElement: HTMLElement | null): void {
|
||||
const item = this.items[index];
|
||||
|
||||
if (!item) {
|
||||
console.log(this.items);
|
||||
throw new Error(`Got index ${index} and there are ${this.items.length} items. File issue to joao!`);
|
||||
}
|
||||
|
||||
if (!item.row) {
|
||||
item.row = this.cache.alloc(item.templateId);
|
||||
}
|
||||
|
@ -311,6 +316,12 @@ export class ListView<T> implements ISpliceable<T>, IDisposable {
|
|||
|
||||
private removeItemFromDOM(index: number): void {
|
||||
const item = this.items[index];
|
||||
|
||||
if (!item) {
|
||||
console.log(this.items);
|
||||
throw new Error(`Got index ${index} and there are ${this.items.length} items. File issue to joao!`);
|
||||
}
|
||||
|
||||
this.cache.release(item.row);
|
||||
item.row = null;
|
||||
}
|
||||
|
@ -371,7 +382,12 @@ export class ListView<T> implements ISpliceable<T>, IDisposable {
|
|||
}
|
||||
|
||||
private onScroll(e: ScrollEvent): void {
|
||||
this.render(e.scrollTop, e.height);
|
||||
try {
|
||||
this.render(e.scrollTop, e.height);
|
||||
} catch (err) {
|
||||
console.log('Got bad scroll event:', e);
|
||||
throw err;
|
||||
}
|
||||
}
|
||||
|
||||
private onTouchChange(event: GestureEvent): void {
|
||||
|
|
|
@ -13,7 +13,7 @@ import { ResolvedKeybinding, KeyCode } from 'vs/base/common/keyCodes';
|
|||
import { Event } from 'vs/base/common/event';
|
||||
import { addClass, EventType, EventHelper, EventLike } from 'vs/base/browser/dom';
|
||||
import { StandardKeyboardEvent } from 'vs/base/browser/keyboardEvent';
|
||||
import { $ } from 'vs/base/browser/builder';
|
||||
import { $, Builder } from 'vs/base/browser/builder';
|
||||
|
||||
export interface IMenuOptions {
|
||||
context?: any;
|
||||
|
@ -152,6 +152,7 @@ class MenuActionItem extends ActionItem {
|
|||
|
||||
class SubmenuActionItem extends MenuActionItem {
|
||||
private mysubmenu: Menu;
|
||||
private submenuContainer: Builder;
|
||||
private mouseOver: boolean;
|
||||
|
||||
constructor(
|
||||
|
@ -224,18 +225,23 @@ class SubmenuActionItem extends MenuActionItem {
|
|||
if (this.parentData.submenu && (force || (this.parentData.submenu !== this.mysubmenu))) {
|
||||
this.parentData.submenu.dispose();
|
||||
this.parentData.submenu = null;
|
||||
|
||||
if (this.submenuContainer) {
|
||||
this.submenuContainer.dispose();
|
||||
this.submenuContainer = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private createSubmenu() {
|
||||
if (!this.parentData.submenu) {
|
||||
const submenuContainer = $(this.builder).div({ class: 'monaco-submenu menubar-menu-items-holder context-view' });
|
||||
this.submenuContainer = $(this.builder).div({ class: 'monaco-submenu menubar-menu-items-holder context-view' });
|
||||
|
||||
$(submenuContainer).style({
|
||||
$(this.submenuContainer).style({
|
||||
'left': `${$(this.builder).getClientArea().width}px`
|
||||
});
|
||||
|
||||
$(submenuContainer).on(EventType.KEY_UP, (e) => {
|
||||
$(this.submenuContainer).on(EventType.KEY_UP, (e) => {
|
||||
let event = new StandardKeyboardEvent(e as KeyboardEvent);
|
||||
if (event.equals(KeyCode.LeftArrow)) {
|
||||
EventHelper.stop(e, true);
|
||||
|
@ -243,10 +249,13 @@ class SubmenuActionItem extends MenuActionItem {
|
|||
this.parentData.parent.focus();
|
||||
this.parentData.submenu.dispose();
|
||||
this.parentData.submenu = null;
|
||||
|
||||
this.submenuContainer.dispose();
|
||||
this.submenuContainer = null;
|
||||
}
|
||||
});
|
||||
|
||||
$(submenuContainer).on(EventType.KEY_DOWN, (e) => {
|
||||
$(this.submenuContainer).on(EventType.KEY_DOWN, (e) => {
|
||||
let event = new StandardKeyboardEvent(e as KeyboardEvent);
|
||||
if (event.equals(KeyCode.LeftArrow)) {
|
||||
EventHelper.stop(e, true);
|
||||
|
@ -254,10 +263,24 @@ class SubmenuActionItem extends MenuActionItem {
|
|||
});
|
||||
|
||||
|
||||
this.parentData.submenu = new Menu(submenuContainer.getHTMLElement(), this.submenuActions, this.submenuOptions);
|
||||
this.parentData.submenu = new Menu(this.submenuContainer.getHTMLElement(), this.submenuActions, this.submenuOptions);
|
||||
this.parentData.submenu.focus();
|
||||
|
||||
this.mysubmenu = this.parentData.submenu;
|
||||
}
|
||||
}
|
||||
|
||||
public dispose() {
|
||||
super.dispose();
|
||||
|
||||
if (this.mysubmenu) {
|
||||
this.mysubmenu.dispose();
|
||||
this.mysubmenu = null;
|
||||
}
|
||||
|
||||
if (this.submenuContainer) {
|
||||
this.submenuContainer.dispose();
|
||||
this.submenuContainer = null;
|
||||
}
|
||||
}
|
||||
}
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue