Merge remote-tracking branch 'origin/master' into joao/uri-handler

This commit is contained in:
Joao Moreno
2018-07-06 12:49:16 +02:00
625 changed files with 15064 additions and 7992 deletions
+2 -2
View File
@@ -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.
+74 -12
View File
@@ -1,43 +1,69 @@
{
perform: true,
alwaysRequireAssignee: false,
labelsRequiringAssignee: [ feature-request ],
labelsRequiringAssignee: [],
autoAssignees: {
L10N: [],
VIM: [],
api: {
assignees: [ jrieken ],
assignLabel: false
},
color-picker: [],
css-less-sass: [ aeschli ],
cli: [],
color-palette: [],
config: [],
css-less-scss: [ aeschli ],
debug-console: [],
debug: {
assignees: [ weinand ],
assignLabel: false
},
diff-editor: [],
dropdown: [],
editor: [],
editor-1000-limit: [],
editor-autoclosing: [],
editor-autoindent: [],
editor-brackets: [],
editor-clipboard: [],
editor-code-actions: [],
editor-code-lens: [],
editor-color-picker: [],
editor-colors: [],
editor-columnselect: [],
editor-commands: [],
editor-contrib: [],
editor-core: [],
editor-find-widget: [],
editor-drag-and-drop: [],
editor-find: [],
editor-folding: [],
editor-hover: [],
editor-ime: [],
editor-input: [],
editor-ligatures: [],
editor-links: [],
editor-minimap: [],
editor-multicursor: [],
editor-parameter-hints: [],
editor-rendering: [],
editor-smooth: [],
editor-symbols: [],
editor-textbuffer: [],
editor-wrapping: [],
emmet: [ ramya-rao-a ],
error-list: [],
explorer-custom: [],
extension-host: [],
extensions: [],
file-decorations: [],
file-encoding: {
assignees: [],
assignLabel: false
},
file-explorer: {
assignees: [ isidorn ],
assignLabel: false
},
file-glob: [],
file-io: {
assignees: [],
assignLabel: false
@@ -46,45 +72,73 @@
assignees: [],
assignLabel: false
},
file-explorer: {
assignees: [ isidorn ],
assignLabel: false
},
format: [],
formatting: [],
git: [ joaomoreno ],
grammar: [],
hot-exit: [ Tyriar ],
html: [ aeschli ],
i18n: [],
install-update: [],
integrated-terminal: [ Tyriar ],
integration-test: [],
intellisense-config: [],
issue-reporter: [ RMacfarlane ],
javascript: [ mjbvz ],
json: [],
keybindings: [],
keyboard-layout: [],
keybindings: [],
keybindings-editor: [],
lang-diagnostics: [],
languages basic: [],
list: [],
log: [],
markdown: [ mjbvz ],
marketplace: [],
menus: [],
merge-conflict: [ chrmarti ],
multi-root: {
assignees: [],
assignLabel: false
},
os-integration: [],
outline: [],
output: [],
perf-profile: [],
perf-bloat: [],
perf-startup: [],
php: [ roblourens ],
proxy: [],
quick-pick: [ chrmarti ],
release-notes: [],
remote: {
assignees: [ jrieken ],
assignLabel: false
},
rename: [],
run-as-admin: [],
samples: [],
scm: [],
search: [ roblourens ],
search-replace: [],
settings-editor: [],
shared-process: [],
smart-select: [],
smoke-test: [],
snippets: {
assignees: [ jrieken ],
assignLabel: false
},
suggest: [],
tasks: [ dbaeumer ],
telemetry: [],
themes: [],
tokenization: [],
tree: [],
typescript: [ mjbvz ],
unit-test: [],
uri: [],
ux: [],
vscode-build: [],
webview: [],
workbench: {
assignees: [],
assignLabel: false
@@ -109,6 +163,10 @@
assignees: [],
assignLabel: false
},
workbench-grid: {
assignees: [],
assignLabel: false
},
workbench-history: {
assignees: [],
assignLabel: false
@@ -145,6 +203,10 @@
assignees: [],
assignLabel: false
},
workbench-views: {
assignees: [],
assignLabel: false
},
workbench-welcome: [ chrmarti ]
}
}
+2 -2
View File
@@ -1,12 +1,12 @@
[
{
"name": "ms-vscode.node-debug",
"version": "1.25.3",
"version": "1.26.0",
"repo": "https://github.com/Microsoft/vscode-node-debug"
},
{
"name": "ms-vscode.node-debug2",
"version": "1.25.4",
"version": "1.26.0",
"repo": "https://github.com/Microsoft/vscode-node-debug2"
}
]
+2
View File
@@ -82,6 +82,7 @@ const indentationFilter = [
'!build/{lib,tslintRules}/**/*.js',
'!build/**/*.sh',
'!build/tfs/**/*.js',
'!build/tfs/**/*.config',
'!**/Dockerfile',
'!extensions/markdown-language-features/media/*.js'
];
@@ -104,6 +105,7 @@ const copyrightFilter = [
'!**/*.code-workspace',
'!build/**/*.init',
'!resources/linux/snap/snapcraft.yaml',
'!resources/linux/snap/electron-launch',
'!resources/win32/bin/code.js',
'!extensions/markdown-language-features/media/highlight.css',
'!extensions/html-language-features/server/src/modes/typescript/*',
+14 -3
View File
@@ -71,7 +71,7 @@ const vscodeResources = [
'out-build/paths.js',
'out-build/vs/**/*.{svg,png,cur,html}',
'out-build/vs/base/common/performance.js',
'out-build/vs/base/node/{stdForkStart.js,terminateProcess.sh, cpuUsage.sh}',
'out-build/vs/base/node/{stdForkStart.js,terminateProcess.sh,cpuUsage.sh}',
'out-build/vs/base/browser/ui/octiconLabel/octicons/**',
'out-build/vs/workbench/browser/media/*-theme.css',
'out-build/vs/workbench/electron-browser/bootstrap/**',
@@ -265,10 +265,17 @@ function packageTask(platform, arch, opts) {
const packageJsonStream = gulp.src(['package.json'], { base: '.' })
.pipe(json({ name, version }));
const settingsSearchBuildId = getSettingsSearchBuildId(packageJson);
const date = new Date().toISOString();
const productJsonUpdate = { commit, date, checksums };
try {
productJsonUpdate.settingsSearchBuildId = getSettingsSearchBuildId(packageJson);
} catch (err) {
console.warn(err);
}
const productJsonStream = gulp.src(['product.json'], { base: '.' })
.pipe(json({ commit, date, checksums, settingsSearchBuildId }));
.pipe(json(productJsonUpdate));
const license = gulp.src(['LICENSES.chromium.html', 'LICENSE.txt', 'ThirdPartyNotices.txt', 'licenses/**'], { base: '.' });
@@ -508,6 +515,10 @@ gulp.task('generate-vscode-configuration', () => {
return reject(new Error('$AGENT_BUILDDIRECTORY not set'));
}
if (process.env.VSCODE_QUALITY !== 'insider' && process.env.VSCODE_QUALITY !== 'stable') {
return resolve();
}
const userDataDir = path.join(os.tmpdir(), 'tmpuserdata');
const extensionsDir = path.join(os.tmpdir(), 'tmpextdir');
const appName = process.env.VSCODE_QUALITY === 'insider' ? 'Visual\\ Studio\\ Code\\ -\\ Insiders.app' : 'Visual\\ Studio\\ Code.app';
+10 -4
View File
@@ -26,6 +26,7 @@ const zipPath = arch => path.join(zipDir(arch), `VSCode-win32-${arch}.zip`);
const setupDir = (arch, target) => path.join(repoPath, '.build', `win32-${arch}`, `${target}-setup`);
const issPath = path.join(__dirname, 'win32', 'code.iss');
const innoSetupPath = path.join(path.dirname(path.dirname(require.resolve('innosetup-compiler'))), 'bin', 'ISCC.exe');
const signPS1 = path.join(repoPath, 'build', 'tfs', 'win32', 'sign.ps1');
function packageInnoSetup(iss, options, cb) {
options = options || {};
@@ -42,7 +43,11 @@ function packageInnoSetup(iss, options, cb) {
keys.forEach(key => assert(typeof definitions[key] === 'string', `Missing value for '${key}' in Inno Setup package step`));
const defs = keys.map(key => `/d${key}=${definitions[key]}`);
const args = [iss].concat(defs);
const args = [
iss,
...defs,
`/sesrp=powershell.exe -ExecutionPolicy bypass ${signPS1} $f`
];
cp.spawn(innoSetupPath, args, { stdio: ['ignore', 'inherit', 'inherit'] })
.on('error', cb)
@@ -74,14 +79,15 @@ function buildWin32Setup(arch, target) {
DirName: product.win32DirName,
Version: pkg.version,
RawVersion: pkg.version.replace(/-\w+$/, ''),
NameVersion: product.win32NameVersion,
NameVersion: product.win32NameVersion + (target === 'user' ? ' (User)' : ''),
ExeBasename: product.nameShort,
RegValueName: product.win32RegValueName,
ShellNameShort: product.win32ShellNameShort,
AppMutex: product.win32MutexName,
Arch: arch,
AppId: arch === 'ia32' ? ia32AppId : x64AppId,
IncompatibleAppId: arch === 'ia32' ? x64AppId : ia32AppId,
IncompatibleTargetAppId: arch === 'ia32' ? product.win32AppId : product.win32x64AppId,
IncompatibleArchAppId: arch === 'ia32' ? x64AppId : ia32AppId,
AppUserId: product.win32AppUserModelId,
ArchitecturesAllowed: arch === 'ia32' ? '' : 'x64',
ArchitecturesInstallIn64BitMode: arch === 'ia32' ? '' : 'x64',
@@ -108,7 +114,7 @@ defineWin32SetupTasks('x64', 'user');
function archiveWin32Setup(arch) {
return cb => {
const args = ['a', '-tzip', zipPath(arch), '.', '-r'];
const args = ['a', '-tzip', zipPath(arch), '-x!CodeSignSummary*.md', '.', '-r'];
cp.spawn(_7z, args, { stdio: 'inherit', cwd: buildPath(arch) })
.on('error', cb)
+4
View File
@@ -78,6 +78,10 @@
"name": "vs/workbench/parts/logs",
"project": "vscode-workbench"
},
{
"name": "vs/workbench/parts/navigation",
"project": "vscode-workbench"
},
{
"name": "vs/workbench/parts/output",
"project": "vscode-workbench"
+19 -81
View File
@@ -125,91 +125,29 @@ phases:
]
SessionTimeout: 120
- task: NuGetCommand@2
displayName: Install ESRPClient.exe
inputs:
restoreSolution: 'build\tfs\win32\ESRPClient\packages.config'
feedsToUse: config
nugetConfigPath: 'build\tfs\win32\ESRPClient\NuGet.config'
externalFeedCredentials: 3fc0b7f7-da09-4ae7-a9c8-d69824b1819b
restoreDirectory: packages
- task: ESRPImportCertTask@1
displayName: Import ESRP Request Signing Certificate
inputs:
ESRP: 'ESRP CodeSign'
- powershell: |
$ErrorActionPreference = "Stop"
.\build\tfs\win32\import-esrp-auth-cert.ps1 -AuthCertificateBase64 $(ESRP_AUTH_CERTIFICATE) -AuthCertificateKey $(ESRP_AUTH_CERTIFICATE_KEY)
displayName: Import ESRP Auth Certificate
- powershell: |
$ErrorActionPreference = "Stop"
npm run gulp -- "vscode-win32-$(VSCODE_ARCH)-archive" "vscode-win32-$(VSCODE_ARCH)-system-setup" "vscode-win32-$(VSCODE_ARCH)-user-setup"
- task: SFP.build-tasks.custom-build-task-1.EsrpCodeSigning@1
inputs:
ConnectedServiceName: 'ESRP CodeSign'
FolderPath: '$(agent.builddirectory)'
Pattern: VSCodeSetup.exe
signConfigType: inlineSignParams
inlineOperation: |
[
{
"keyCode": "CP-229803",
"operationSetCode": "SigntoolSign",
"parameters": [
{
"parameterName": "OpusName",
"parameterValue": "VS Code"
},
{
"parameterName": "OpusInfo",
"parameterValue": "https://code.visualstudio.com/"
},
{
"parameterName": "PageHash",
"parameterValue": "/NPH"
},
{
"parameterName": "TimeStamp",
"parameterValue": "/t \"http://ts4096.gtm.microsoft.com/TSS/AuthenticodeTS\""
}
],
"toolName": "sign",
"toolVersion": "1.0"
},
{
"keyCode": "CP-230012",
"operationSetCode": "SigntoolSign",
"parameters": [
{
"parameterName": "OpusName",
"parameterValue": "VS Code"
},
{
"parameterName": "OpusInfo",
"parameterValue": "https://code.visualstudio.com/"
},
{
"parameterName": "Append",
"parameterValue": "/as"
},
{
"parameterName": "FileDigest",
"parameterValue": "/fd \"SHA256\""
},
{
"parameterName": "PageHash",
"parameterValue": "/NPH"
},
{
"parameterName": "TimeStamp",
"parameterValue": "/tr \"http://rfc3161.gtm.corp.microsoft.com/TSS/HttpTspServer\" /td sha256"
}
],
"toolName": "sign",
"toolVersion": "1.0"
},
{
"keyCode": "CP-230012",
"operationSetCode": "SigntoolVerify",
"parameters": [
{
"parameterName": "VerifyAll",
"parameterValue": "/all"
}
],
"toolName": "sign",
"toolVersion": "1.0"
}
]
SessionTimeout: 120
- powershell: |
$ErrorActionPreference = "Stop"
$Repo = "$(pwd)"
$Root = "$Repo\.."
$SystemExe = "$Repo\.build\win32-$(VSCODE_ARCH)\system-setup\VSCodeSetup.exe"
+6
View File
@@ -0,0 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<configuration>
<packageSources>
<add key="ESRP" value="https://microsoft.pkgs.visualstudio.com/_packaging/ESRP/nuget/v3/index.json" />
</packageSources>
</configuration>
@@ -0,0 +1,4 @@
<?xml version="1.0" encoding="utf-8"?>
<packages>
<package id="EsrpClient" version="1.0.27" />
</packages>
+14
View File
@@ -0,0 +1,14 @@
Param(
[string]$AuthCertificateBase64,
[string]$AuthCertificateKey
)
# Import auth certificate
$AuthCertificateFileName = [System.IO.Path]::GetTempFileName()
$AuthCertificateBytes = [Convert]::FromBase64String($AuthCertificateBase64)
[IO.File]::WriteAllBytes($AuthCertificateFileName, $AuthCertificateBytes)
$AuthCertificate = Import-PfxCertificate -FilePath $AuthCertificateFileName -CertStoreLocation Cert:\LocalMachine\My -Password (ConvertTo-SecureString $AuthCertificateKey -AsPlainText -Force)
rm $AuthCertificateFileName
$ESRPAuthCertificateSubjectName = $AuthCertificate.Subject
Write-Output ("##vso[task.setvariable variable=ESRPAuthCertificateSubjectName;]$ESRPAuthCertificateSubjectName")
+82
View File
@@ -0,0 +1,82 @@
function Create-TmpJson($Obj) {
$FileName = [System.IO.Path]::GetTempFileName()
ConvertTo-Json -Depth 100 $Obj | Out-File -Encoding UTF8 $FileName
return $FileName
}
$Auth = Create-TmpJson @{
Version = "1.0.0"
AuthenticationType = "AAD_CERT"
ClientId = $env:ESRPClientId
AuthCert = @{
SubjectName = $env:ESRPAuthCertificateSubjectName
StoreLocation = "LocalMachine"
StoreName = "My"
}
RequestSigningCert = @{
SubjectName = $env:ESRPCertificateSubjectName
StoreLocation = "LocalMachine"
StoreName = "My"
}
}
$Policy = Create-TmpJson @{
Version = "1.0.0"
}
$Input = Create-TmpJson @{
Version = "1.0.0"
SignBatches = @(
@{
SourceLocationType = "UNC"
SignRequestFiles = @(
@{
SourceLocation = $args[0]
}
)
SigningInfo = @{
Operations = @(
@{
KeyCode = "CP-229803"
OperationCode = "SigntoolSign"
Parameters = @{
OpusName = "VS Code"
OpusInfo = "https://code.visualstudio.com/"
PageHash = "/NPH"
TimeStamp = "/t `"http://ts4096.gtm.microsoft.com/TSS/AuthenticodeTS`""
}
ToolName = "sign"
ToolVersion = "1.0"
},
@{
KeyCode = "CP-230012"
OperationCode = "SigntoolSign"
Parameters = @{
OpusName = "VS Code"
OpusInfo = "https://code.visualstudio.com/"
Append = "/as"
FileDigest = "/fd `"SHA256`""
PageHash = "/NPH"
TimeStamp = "/tr `"http://rfc3161.gtm.corp.microsoft.com/TSS/HttpTspServer`" /td sha256"
}
ToolName = "sign"
ToolVersion = "1.0"
},
@{
KeyCode = "CP-230012"
OperationCode = "SigntoolVerify"
Parameters = @{
VerifyAll = "/all"
}
ToolName = "sign"
ToolVersion = "1.0"
}
)
}
}
)
}
$Output = [System.IO.Path]::GetTempFileName()
$ScriptPath = Split-Path -Path $MyInvocation.MyCommand.Definition -Parent
& "$ScriptPath\ESRPClient\packages\EsrpClient.1.0.27\tools\ESRPClient.exe" Sign -a $Auth -p $Policy -i $Input -o $Output
+28 -28
View File
@@ -545,33 +545,6 @@
],
"isProd": true
},
{
"name": "retep998/winapi-rs",
"version": "0.3.4",
"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",
@@ -707,6 +680,33 @@
],
"isProd": true
},
{
"name": "retep998/winapi-rs",
"version": "0.3.4",
"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": "rust-lang-nursery/lazy-static.rs",
"version": "1.0.0",
@@ -1791,4 +1791,4 @@
],
"isProd": true
}
]
]
+23 -4
View File
@@ -32,6 +32,7 @@ VersionInfoVersion={#RawVersion}
ShowLanguageDialog=auto
ArchitecturesAllowed={#ArchitecturesAllowed}
ArchitecturesInstallIn64BitMode={#ArchitecturesInstallIn64BitMode}
SignTool=esrp
#if "user" == InstallTarget
DefaultDirName={userpf}\{#DirName}
@@ -91,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
@@ -945,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"
@@ -963,8 +964,26 @@ var
begin
Result := True;
if IsWin64 then begin
RegKey := 'SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\' + copy('{#IncompatibleAppId}', 2, 38) + '_is1';
#if "user" == InstallTarget
#if "ia32" == Arch
#define IncompatibleArchRootKey "HKLM32"
#else
#define IncompatibleArchRootKey "HKLM64"
#endif
if not WizardSilent() then begin
RegKey := 'SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\' + copy('{#IncompatibleTargetAppId}', 2, 38) + '_is1';
if RegKeyExists({#IncompatibleArchRootKey}, RegKey) then begin
if MsgBox('{#NameShort} is already installed on this system for all users. Are you sure you want to install it for this user?', mbConfirmation, MB_YESNO) = IDNO then begin
Result := false;
end;
end;
end;
#endif
if Result and IsWin64 then begin
RegKey := 'SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\' + copy('{#IncompatibleArchAppId}', 2, 38) + '_is1';
if '{#Arch}' = 'ia32' then begin
Result := not RegKeyExists({#Uninstall64RootKey}, RegKey);
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": [
+3 -3
View File
@@ -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",
@@ -8,7 +8,7 @@
"node": "*"
},
"dependencies": {
"vscode-css-languageservice": "^3.0.9-next.18",
"vscode-css-languageservice": "^3.0.9-next.20",
"vscode-languageserver": "^4.1.3",
"vscode-languageserver-protocol-foldingprovider": "^2.0.1"
},
@@ -194,9 +194,9 @@ supports-color@5.4.0:
dependencies:
has-flag "^3.0.0"
vscode-css-languageservice@^3.0.9-next.18:
version "3.0.9-next.18"
resolved "https://registry.yarnpkg.com/vscode-css-languageservice/-/vscode-css-languageservice-3.0.9-next.18.tgz#f8f25123b5a8cdc9f72fafcd2c0088f726322437"
vscode-css-languageservice@^3.0.9-next.20:
version "3.0.9-next.20"
resolved "https://registry.yarnpkg.com/vscode-css-languageservice/-/vscode-css-languageservice-3.0.9-next.20.tgz#8229aee66aa877929af5d2fd81a21731b415c92e"
dependencies:
vscode-languageserver-types "^3.7.2"
vscode-nls "^3.2.2"
+3 -3
View File
@@ -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"
+1 -1
View File
@@ -8,7 +8,7 @@
"vscode": "0.10.x"
},
"scripts": {
"update-grammar": "node ../../build/npm/update-grammar.js atom/language-css grammars/css.cson ./syntaxes/css.tmLanguage.json"
"update-grammar": "node ../../build/npm/update-grammar.js octref/language-css grammars/css.cson ./syntaxes/css.tmLanguage.json"
},
"contributes": {
"languages": [
+42 -3
View File
@@ -1,10 +1,10 @@
{
"information_for_contributors": [
"This file has been converted from https://github.com/atom/language-css/blob/master/grammars/css.cson",
"This file has been converted from https://github.com/octref/language-css/blob/master/grammars/css.cson",
"If you want to provide a fix or improvement, please create a pull request against the original repository.",
"Once accepted there, we are happy to receive an update request."
],
"version": "https://github.com/atom/language-css/commit/17ad55bc5f65c16585e80ea1c7c19e0c0814f6d5",
"version": "https://github.com/octref/language-css/commit/ea1d7e3619966e47c57498913a5eabea0cce7538",
"name": "CSS",
"scopeName": "source.css",
"patterns": [
@@ -604,6 +604,45 @@
"include": "#string"
}
]
},
{
"begin": "(?i)(?=@[\\w-]+(\\s|\\(|/\\*|$))",
"end": "(?<=})(?!\\G)",
"patterns": [
{
"begin": "(?i)\\G(@)[\\w-]+",
"beginCaptures": {
"0": {
"name": "keyword.control.at-rule.css"
},
"1": {
"name": "punctuation.definition.keyword.css"
}
},
"end": "(?=\\s*[{;])",
"name": "meta.at-rule.header.css"
},
{
"begin": "{",
"beginCaptures": {
"0": {
"name": "punctuation.section.begin.bracket.curly.css"
}
},
"end": "}",
"endCaptures": {
"0": {
"name": "punctuation.section.end.bracket.curly.css"
}
},
"name": "meta.at-rule.body.css",
"patterns": [
{
"include": "$self"
}
]
}
]
}
]
},
@@ -1411,7 +1450,7 @@
"name": "invalid.illegal.colon.css"
}
},
"match": "(?xi)\n(:)(:*)\n(?: active|any-link|checked|default|disabled|empty|enabled|first\n | (?:first|last|only)-(?:child|of-type)|focus|focus-within|fullscreen|host|hover\n | in-range|indeterminate|invalid|left|link|optional|out-of-range\n | read-only|read-write|required|right|root|scope|target|unresolved\n | valid|visited\n)(?![\\w-]|\\s*[;}])",
"match": "(?xi)\n(:)(:*)\n(?: active|any-link|checked|default|defined|disabled|empty|enabled|first\n | (?:first|last|only)-(?:child|of-type)|focus|focus-visible|focus-within\n | fullscreen|host|hover|in-range|indeterminate|invalid|left|link\n | optional|out-of-range|placeholder-shown|read-only|read-write\n | required|right|root|scope|target|unresolved\n | valid|visited\n)(?![\\w-]|\\s*[;}])",
"name": "entity.other.attribute-name.pseudo-class.css"
},
"pseudo-elements": {
+1 -1
View File
@@ -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"
}
}
+1 -1
View File
@@ -61,7 +61,7 @@ function balance(out: boolean) {
}
function getRangeToBalanceOut(document: vscode.TextDocument, selection: vscode.Selection, rootNode: HtmlNode): vscode.Selection {
let nodeToBalance = getHtmlNode(document, rootNode, selection.start);
let nodeToBalance = getHtmlNode(document, rootNode, selection.start, false);
if (!nodeToBalance) {
return selection;
}
+1 -1
View File
@@ -34,7 +34,7 @@ function getRangesToReplace(document: vscode.TextDocument, selection: vscode.Sel
let endNodeToUpdate: Node | null;
if (selection.isEmpty) {
startNodeToUpdate = endNodeToUpdate = getNode(rootNode, selection.start);
startNodeToUpdate = endNodeToUpdate = getNode(rootNode, selection.start, true);
} else {
startNodeToUpdate = getNode(rootNode, selection.start, true);
endNodeToUpdate = getNode(rootNode, selection.end, true);
+1 -1
View File
@@ -38,7 +38,7 @@ export function removeTag() {
function getRangeToRemove(editor: vscode.TextEditor, rootNode: HtmlNode, selection: vscode.Selection, indentInSpaces: string): vscode.Range[] {
let nodeToUpdate = getHtmlNode(editor.document, rootNode, selection.start);
let nodeToUpdate = getHtmlNode(editor.document, rootNode, selection.start, true);
if (!nodeToUpdate) {
return [];
}
+4 -4
View File
@@ -8,7 +8,7 @@ import { getDeepestNode, findNextWord, findPrevWord, getHtmlNode } from './util'
import { HtmlNode } from 'EmmetNode';
export function nextItemHTML(selectionStart: vscode.Position, selectionEnd: vscode.Position, editor: vscode.TextEditor, rootNode: HtmlNode): vscode.Selection | undefined {
let currentNode = getHtmlNode(editor.document, rootNode, selectionEnd);
let currentNode = getHtmlNode(editor.document, rootNode, selectionEnd, false);
let nextNode: HtmlNode | undefined = undefined;
if (!currentNode) {
@@ -31,7 +31,7 @@ export function nextItemHTML(selectionStart: vscode.Position, selectionEnd: vsco
// Get the first child of current node which is right after the cursor and is not a comment
nextNode = currentNode.firstChild;
while (nextNode && (selectionEnd.isAfterOrEqual(nextNode.start) || nextNode.type === 'comment')) {
while (nextNode && (selectionEnd.isAfterOrEqual(nextNode.end) || nextNode.type === 'comment')) {
nextNode = nextNode.nextSibling;
}
}
@@ -54,7 +54,7 @@ export function nextItemHTML(selectionStart: vscode.Position, selectionEnd: vsco
}
export function prevItemHTML(selectionStart: vscode.Position, selectionEnd: vscode.Position, editor: vscode.TextEditor, rootNode: HtmlNode): vscode.Selection | undefined {
let currentNode = getHtmlNode(editor.document, rootNode, selectionStart);
let currentNode = getHtmlNode(editor.document, rootNode, selectionStart, false);
let prevNode: HtmlNode | undefined = undefined;
if (!currentNode) {
@@ -63,7 +63,7 @@ export function prevItemHTML(selectionStart: vscode.Position, selectionEnd: vsco
if (currentNode.type !== 'comment' && selectionStart.translate(0, -1).isAfter(currentNode.open.start)) {
if (selectionStart.isBefore(currentNode.open.end) || !currentNode.firstChild) {
if (selectionStart.isBefore(currentNode.open.end) || !currentNode.firstChild || selectionEnd.isBeforeOrEqual(currentNode.firstChild.start)) {
prevNode = currentNode;
} else {
// Select the child that appears just before the cursor and is not a comment
+1 -1
View File
@@ -51,7 +51,7 @@ export function nextItemStylesheet(startOffset: vscode.Position, endOffset: vsco
}
export function prevItemStylesheet(startOffset: vscode.Position, endOffset: vscode.Position, editor: vscode.TextEditor, rootNode: CssNode): vscode.Selection | undefined {
let currentNode = <CssNode>getNode(rootNode, startOffset);
let currentNode = <CssNode>getNode(rootNode, startOffset, false);
if (!currentNode) {
currentNode = rootNode;
}
+1 -1
View File
@@ -20,7 +20,7 @@ export function splitJoinTag() {
return editor.edit(editBuilder => {
editor.selections.reverse().forEach(selection => {
let nodeToUpdate = getHtmlNode(editor.document, rootNode, selection.start);
let nodeToUpdate = getHtmlNode(editor.document, rootNode, selection.start, true);
if (nodeToUpdate) {
let textEdit = getRangesToReplace(editor.document, nodeToUpdate);
editBuilder.replace(textEdit.range, textEdit.newText);
@@ -113,6 +113,22 @@ suite('Tests for Next/Previous Select/Edit point and Balance actions', () => {
});
});
test('Emmet Select Next/Prev item at boundary', function(): any {
return withRandomFileEditor(htmlContents, '.html', (editor, doc) => {
editor.selections = [new Selection(4, 1, 4, 1)];
fetchSelectItem('next');
testSelection(editor.selection, 2, 4, 6);
editor.selections = [new Selection(4, 1, 4, 1)];
fetchSelectItem('prev');
testSelection(editor.selection, 1, 3, 5);
return Promise.resolve();
});
});
test('Emmet Next/Prev Item in html template', function (): any {
const templateContents = `
<script type="text/template">
@@ -56,6 +56,16 @@ suite('Tests for Emmet: Reflect CSS Value command', () => {
});
});
test('Reflect Css Value in css file, selecting entire property', function (): any {
return withRandomFileEditor(cssContents, '.css', (editor, doc) => {
editor.selections = [new Selection(5, 2, 5, 32)];
return reflectCssValue().then(() => {
assert.equal(doc.getText(), cssContents.replace(/\(50deg\)/g, '(20deg)'));
return Promise.resolve();
});
});
});
test('Reflect Css Value in html file', function (): any {
return withRandomFileEditor(htmlContents, '.html', (editor, doc) => {
editor.selections = [new Selection(7, 20, 7, 20)];
@@ -66,4 +76,14 @@ suite('Tests for Emmet: Reflect CSS Value command', () => {
});
});
test('Reflect Css Value in html file, selecting entire property', function (): any {
return withRandomFileEditor(htmlContents, '.html', (editor, doc) => {
editor.selections = [new Selection(7, 4, 7, 34)];
return reflectCssValue().then(() => {
assert.equal(doc.getText(), htmlContents.replace(/\(50deg\)/g, '(20deg)'));
return Promise.resolve();
});
});
});
});
+103 -1
View File
@@ -66,6 +66,31 @@ suite('Tests for Emmet actions on html tags', () => {
});
});
// #region update tag
test('update tag with entire node selected', () => {
const expectedContents = `
<div class="hello">
<ul>
<li><section>Hello</section></li>
<li><span>There</span></li>
<section><li><span>Bye</span></li></section>
</ul>
<span/>
</div>
`;
return withRandomFileEditor(contents, 'html', (editor, doc) => {
editor.selections = [
new Selection(3, 7, 3, 25),
new Selection(5, 3, 5, 39),
];
return updateTag('section')!.then(() => {
assert.equal(doc.getText(), expectedContents);
return Promise.resolve();
});
});
});
test('update tag with template', () => {
const expectedContents = `
<script type="text/template">
@@ -89,8 +114,9 @@ suite('Tests for Emmet actions on html tags', () => {
});
});
});
// #endregion
// #region remove tag
test('remove tag with mutliple cursors', () => {
const expectedContents = `
<div class="hello">
@@ -116,6 +142,31 @@ suite('Tests for Emmet actions on html tags', () => {
});
});
test('remove tag with boundary conditions', () => {
const expectedContents = `
<div class="hello">
<ul>
<li>Hello</li>
<li><span>There</span></li>
<li><span>Bye</span></li>
</ul>
<span/>
</div>
`;
return withRandomFileEditor(contents, 'html', (editor, doc) => {
editor.selections = [
new Selection(3, 7, 3, 25),
new Selection(5, 3, 5, 39),
];
return removeTag()!.then(() => {
assert.equal(doc.getText(), expectedContents);
return Promise.resolve();
});
});
});
test('remove tag with template', () => {
const expectedContents = `
@@ -139,7 +190,9 @@ suite('Tests for Emmet actions on html tags', () => {
});
});
});
// #endregion
// #region split/join tag
test('split/join tag with mutliple cursors', () => {
const expectedContents = `
<div class="hello">
@@ -164,6 +217,30 @@ suite('Tests for Emmet actions on html tags', () => {
});
});
test('split/join tag with boundary selection', () => {
const expectedContents = `
<div class="hello">
<ul>
<li><span/></li>
<li><span>There</span></li>
<div><li><span>Bye</span></li></div>
</ul>
<span></span>
</div>
`;
return withRandomFileEditor(contents, 'html', (editor, doc) => {
editor.selections = [
new Selection(3, 7, 3, 25), // join tag
new Selection(7, 2, 7, 9), // split tag
];
return splitJoinTag()!.then(() => {
assert.equal(doc.getText(), expectedContents);
return Promise.resolve();
});
});
});
test('split/join tag with templates', () => {
const expectedContents = `
<script type="text/template">
@@ -214,7 +291,9 @@ suite('Tests for Emmet actions on html tags', () => {
});
});
});
// #endregion
// #region match tag
test('match tag with mutliple cursors', () => {
return withRandomFileEditor(contents, 'html', (editor, doc) => {
editor.selections = [
@@ -265,6 +344,9 @@ suite('Tests for Emmet actions on html tags', () => {
});
});
// #endregion
// #region merge lines
test('merge lines of tag with children when empty selection', () => {
const expectedContents = `
<div class="hello">
@@ -284,6 +366,25 @@ suite('Tests for Emmet actions on html tags', () => {
});
});
test('merge lines of tag with children when full node selection', () => {
const expectedContents = `
<div class="hello">
<ul><li><span>Hello</span></li><li><span>There</span></li><div><li><span>Bye</span></li></div></ul>
<span/>
</div>
`;
return withRandomFileEditor(contents, 'html', (editor, doc) => {
editor.selections = [
new Selection(2, 3, 6, 7)
];
return mergeLines()!.then(() => {
assert.equal(doc.getText(), expectedContents);
return Promise.resolve();
});
});
});
test('merge lines is no-op when start and end nodes are on the same line', () => {
return withRandomFileEditor(contents, 'html', (editor, doc) => {
editor.selections = [
@@ -298,5 +399,6 @@ suite('Tests for Emmet actions on html tags', () => {
});
});
});
// #endregion
});
+2 -2
View File
@@ -73,13 +73,13 @@ function updateImageSizeHTML(editor: TextEditor, position: Position): Promise<Te
function updateImageSizeStyleTag(editor: TextEditor, position: Position): Promise<TextEdit[] | undefined> {
const getPropertyInsiderStyleTag = (editor: TextEditor): Property | null => {
const rootNode = parseDocument(editor.document);
const currentNode = <HtmlNode>getNode(rootNode, position);
const currentNode = <HtmlNode>getNode(rootNode, position, true);
if (currentNode && currentNode.name === 'style'
&& currentNode.open.end.isBefore(position)
&& currentNode.close.start.isAfter(position)) {
let buffer = new DocumentStreamReader(editor.document, currentNode.open.end, new Range(currentNode.open.end, currentNode.close.start));
let rootNode = parseStylesheet(buffer);
const node = getNode(rootNode, position);
const node = getNode(rootNode, position, true);
return (node && node.type === 'property') ? <Property>node : null;
}
return null;
+1 -1
View File
@@ -30,7 +30,7 @@ export function updateTag(tagName: string): Thenable<boolean> | undefined {
}
function getRangesToUpdate(editor: vscode.TextEditor, selection: vscode.Selection, rootNode: HtmlNode): vscode.Range[] {
let nodeToUpdate = getHtmlNode(editor.document, rootNode, selection.start);
let nodeToUpdate = getHtmlNode(editor.document, rootNode, selection.start, true);
if (!nodeToUpdate) {
return [];
}
+4 -4
View File
@@ -285,7 +285,7 @@ function findClosingCommentAfterPosition(document: vscode.TextDocument, position
/**
* Returns node corresponding to given position in the given root node
*/
export function getNode(root: Node | undefined, position: vscode.Position, includeNodeBoundary: boolean = false) {
export function getNode(root: Node | undefined, position: vscode.Position, includeNodeBoundary: boolean) {
if (!root) {
return null;
}
@@ -310,7 +310,7 @@ export function getNode(root: Node | undefined, position: vscode.Position, inclu
return foundNode;
}
export function getHtmlNode(document: vscode.TextDocument, root: Node | undefined, position: vscode.Position, includeNodeBoundary: boolean = false): HtmlNode | undefined {
export function getHtmlNode(document: vscode.TextDocument, root: Node | undefined, position: vscode.Position, includeNodeBoundary: boolean): HtmlNode | undefined {
let currentNode = <HtmlNode>getNode(root, position, includeNodeBoundary);
if (!currentNode) { return; }
@@ -532,7 +532,7 @@ export function getCssPropertyFromRule(rule: Rule, name: string): Property | und
*/
export function getCssPropertyFromDocument(editor: vscode.TextEditor, position: vscode.Position): Property | null | undefined {
const rootNode = parseDocument(editor.document);
const node = getNode(rootNode, position);
const node = getNode(rootNode, position, true);
if (isStyleSheet(editor.document.languageId)) {
return node && node.type === 'property' ? <Property>node : null;
@@ -545,7 +545,7 @@ export function getCssPropertyFromDocument(editor: vscode.TextEditor, position:
&& htmlNode.close.start.isAfter(position)) {
let buffer = new DocumentStreamReader(editor.document, htmlNode.start, new vscode.Range(htmlNode.start, htmlNode.end));
let rootNode = parseStylesheet(buffer);
const node = getNode(rootNode, position);
const node = getNode(rootNode, position, true);
return (node && node.type === 'property') ? <Property>node : null;
}
}
+3 -3
View File
@@ -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"
+1 -1
View File
@@ -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": [
+3 -3
View File
@@ -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"
+1 -1
View File
@@ -1140,7 +1140,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": {
+38 -33
View File
@@ -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[];
@@ -629,20 +645,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 +661,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 +675,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);
@@ -1273,16 +1281,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 +1654,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 +1667,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 +1692,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();
+31 -17
View File
@@ -336,7 +336,7 @@ export const GitErrorCodes = {
NoStashFound: 'NoStashFound',
LocalChangesOverwritten: 'LocalChangesOverwritten',
NoUpstreamBranch: 'NoUpstreamBranch',
IsInSubmodule: 'IsInSubmodule'
IsInSubmodule: 'IsInSubmodule',
};
function getGitErrorCode(stderr: string): string | undefined {
@@ -876,27 +876,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> {
+56 -8
View File
@@ -299,7 +299,8 @@ export enum Operation {
Stash = 'Stash',
CheckIgnore = 'CheckIgnore',
LSTree = 'LSTree',
SubmoduleUpdate = 'SubmoduleUpdate'
SubmoduleUpdate = 'SubmoduleUpdate',
RebaseContinue = 'RebaseContinue',
}
function isReadOnly(operation: Operation): boolean {
@@ -479,6 +480,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; }
@@ -553,6 +570,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 +662,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> {
@@ -1025,12 +1061,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 +1126,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');
+2 -1
View File
@@ -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',
+3 -3
View File
@@ -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"
+3 -3
View File
@@ -1,8 +1,8 @@
{
"name": "grunt",
"publisher": "vscode",
"description": "Extension to add Grunt capabilities to VSCode.",
"displayName": "Grunt support for VSCode",
"description": "Extension to add Grunt capabilities to VS Code.",
"displayName": "Grunt support for VS Code",
"version": "1.0.0",
"icon": "images/grunt.png",
"engines": {
@@ -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"
+2 -2
View File
@@ -1,6 +1,6 @@
{
"description": "Extension to add Grunt capabilities to VSCode.",
"displayName": "Grunt support for VSCode",
"description": "Extension to add Grunt capabilities to VS Code.",
"displayName": "Grunt support for VS Code",
"config.grunt.autoDetect": "Controls whether auto detection of Grunt tasks is on or off. Default is on.",
"grunt.taskDefinition.type.description": "The Grunt task to customize.",
"grunt.taskDefinition.file.description": "The Grunt file that provides the task. Can be omitted."
+3 -3
View File
@@ -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"
+1 -1
View File
@@ -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"
+3 -3
View File
@@ -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"
@@ -8,12 +8,12 @@
"node": "*"
},
"dependencies": {
"vscode-css-languageservice": "^3.0.9-next.18",
"vscode-css-languageservice": "^3.0.9-next.20",
"vscode-html-languageservice": "^2.1.3-next.5",
"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": {
@@ -194,9 +194,9 @@ supports-color@5.4.0:
dependencies:
has-flag "^3.0.0"
vscode-css-languageservice@^3.0.9-next.18:
version "3.0.9-next.18"
resolved "https://registry.yarnpkg.com/vscode-css-languageservice/-/vscode-css-languageservice-3.0.9-next.18.tgz#f8f25123b5a8cdc9f72fafcd2c0088f726322437"
vscode-css-languageservice@^3.0.9-next.20:
version "3.0.9-next.20"
resolved "https://registry.yarnpkg.com/vscode-css-languageservice/-/vscode-css-languageservice-3.0.9-next.20.tgz#8229aee66aa877929af5d2fd81a21731b415c92e"
dependencies:
vscode-languageserver-types "^3.7.2"
vscode-nls "^3.2.2"
@@ -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"
+3 -3
View File
@@ -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"
+1 -1
View File
@@ -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"
+2 -2
View File
@@ -1,6 +1,6 @@
{
"description": "Extension to add Jake capabilities to VSCode.",
"displayName": "Jake support for VSCode",
"description": "Extension to add Jake capabilities to VS Code.",
"displayName": "Jake support for VS Code",
"jake.taskDefinition.type.description": "The Jake task to customize.",
"jake.taskDefinition.file.description": "The Jake file that provides the task. Can be omitted.",
"config.jake.autoDetect": "Controls whether auto detection of Jake tasks is on or off. Default is on."
+3 -3
View File
@@ -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"
@@ -251,11 +251,22 @@ function getSettings(): Settings {
settings.json!.schemas!.push(schemaSetting);
}
let fileMatches = setting.fileMatch;
let resultingFileMatches = schemaSetting.fileMatch!;
if (Array.isArray(fileMatches)) {
if (fileMatchPrefix) {
fileMatches = fileMatches.map(m => fileMatchPrefix + m);
for (let fileMatch of fileMatches) {
if (fileMatch[0] === '/') {
resultingFileMatches.push(fileMatchPrefix + fileMatch);
resultingFileMatches.push(fileMatchPrefix + '/*' + fileMatch);
} else {
resultingFileMatches.push(fileMatchPrefix + '/' + fileMatch);
resultingFileMatches.push(fileMatchPrefix + '/*/' + fileMatch);
}
}
} else {
resultingFileMatches.push(...fileMatches);
}
schemaSetting.fileMatch!.push(...fileMatches);
}
if (setting.schema) {
schemaSetting.schema = setting.schema;
@@ -276,10 +287,10 @@ function getSettings(): Settings {
let folderSchemas = schemaConfigInfo!.workspaceFolderValue;
if (Array.isArray(folderSchemas)) {
let folderPath = folderUri.toString();
if (folderPath[folderPath.length - 1] !== '/') {
folderPath = folderPath + '/';
if (folderPath[folderPath.length - 1] === '/') {
folderPath = folderPath.substr(0, folderPath.length - 1);
}
collectSchemaSettings(folderSchemas, folderUri.fsPath, folderPath + '*');
collectSchemaSettings(folderSchemas, folderUri.fsPath, folderPath);
}
}
}
@@ -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"
@@ -13,10 +13,10 @@
"dependencies": {
"jsonc-parser": "^2.0.0-next.1",
"request-light": "^0.2.2",
"vscode-json-languageservice": "^3.1.2-next.3",
"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": {
@@ -52,14 +52,14 @@ https-proxy-agent@2.1.1:
agent-base "^4.1.0"
debug "^3.1.0"
jsonc-parser@^2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/jsonc-parser/-/jsonc-parser-2.0.0.tgz#62ff087a7e753875febf3c55f1fc0cd737c36b5a"
jsonc-parser@^2.0.0-next.1:
version "2.0.0-next.1"
resolved "https://registry.yarnpkg.com/jsonc-parser/-/jsonc-parser-2.0.0-next.1.tgz#445a824f765a96abfbb286d759a9b1d226b18088"
jsonc-parser@^2.0.1:
version "2.0.1"
resolved "https://registry.yarnpkg.com/jsonc-parser/-/jsonc-parser-2.0.1.tgz#9d23cd2709714fff508a1a6679d82135bee1ae60"
ms@2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/ms/-/ms-2.0.0.tgz#5608aeadfc00be6c2901df5f9861788de0d597c8"
@@ -72,11 +72,11 @@ request-light@^0.2.2:
https-proxy-agent "2.1.1"
vscode-nls "^2.0.2"
vscode-json-languageservice@^3.1.2-next.3:
version "3.1.2-next.3"
resolved "https://registry.yarnpkg.com/vscode-json-languageservice/-/vscode-json-languageservice-3.1.2-next.3.tgz#cc0902148f898b413987fb1b4c4a9e7fc1a79c78"
vscode-json-languageservice@^3.1.2:
version "3.1.2"
resolved "https://registry.yarnpkg.com/vscode-json-languageservice/-/vscode-json-languageservice-3.1.2.tgz#5c70fc32ad389e6da48452e7b0187ea5e70f68bf"
dependencies:
jsonc-parser "^2.0.0"
jsonc-parser "^2.0.1"
vscode-languageserver-types "^3.7.2"
vscode-nls "^3.2.2"
vscode-uri "^1.0.3"
@@ -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"
+3 -3
View File
@@ -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"
+41
View File
@@ -0,0 +1,41 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
'use strict';
var updateGrammar = require('../../../build/npm/update-grammar');
function adaptJSON(grammar, replacementScope) {
grammar.name = 'JSON with comments';
grammar.scopeName = `source${replacementScope}`;
var fixScopeNames = function(rule) {
if (typeof rule.name === 'string') {
rule.name = rule.name.replace(/\.json/g, replacementScope);
}
if (typeof rule.contentName === 'string') {
rule.contentName = rule.contentName.replace(/\.json/g, replacementScope);
}
for (var property in rule) {
var value = rule[property];
if (typeof value === 'object') {
fixScopeNames(value);
}
}
};
var repository = grammar.repository;
for (var key in repository) {
fixScopeNames(repository[key]);
}
}
var tsGrammarRepo = 'Microsoft/vscode-JSON.tmLanguage';
updateGrammar.update(tsGrammarRepo, 'JSON.tmLanguage', './syntaxes/JSON.tmLanguage.json');
updateGrammar.update(tsGrammarRepo, 'JSON.tmLanguage', './syntaxes/JSONC.tmLanguage.json', grammar => adaptJSON(grammar, '.json.comments'));
+3 -3
View File
@@ -8,7 +8,7 @@
"vscode": "0.10.x"
},
"scripts": {
"update-grammar": "node ../../build/npm/update-grammar.js Microsoft/vscode-JSON.tmLanguage JSON.tmLanguage ./syntaxes/JSON.tmLanguage.json"
"update-grammar": "node ./build/update-grammars.js"
},
"contributes": {
"languages": [
@@ -58,8 +58,8 @@
},
{
"language": "jsonc",
"scopeName": "source.json",
"path": "./syntaxes/JSON.tmLanguage.json"
"scopeName": "source.json.comments",
"path": "./syntaxes/JSONC.tmLanguage.json"
}
],
"jsonValidation": [
@@ -0,0 +1,213 @@
{
"information_for_contributors": [
"This file has been converted from https://github.com/Microsoft/vscode-JSON.tmLanguage/blob/master/JSON.tmLanguage",
"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/vscode-JSON.tmLanguage/commit/9bd83f1c252b375e957203f21793316203f61f70",
"name": "JSON with comments",
"scopeName": "source.json.comments",
"patterns": [
{
"include": "#value"
}
],
"repository": {
"array": {
"begin": "\\[",
"beginCaptures": {
"0": {
"name": "punctuation.definition.array.begin.json.comments"
}
},
"end": "\\]",
"endCaptures": {
"0": {
"name": "punctuation.definition.array.end.json.comments"
}
},
"name": "meta.structure.array.json.comments",
"patterns": [
{
"include": "#value"
},
{
"match": ",",
"name": "punctuation.separator.array.json.comments"
},
{
"match": "[^\\s\\]]",
"name": "invalid.illegal.expected-array-separator.json.comments"
}
]
},
"comments": {
"patterns": [
{
"begin": "/\\*\\*(?!/)",
"captures": {
"0": {
"name": "punctuation.definition.comment.json.comments"
}
},
"end": "\\*/",
"name": "comment.block.documentation.json.comments"
},
{
"begin": "/\\*",
"captures": {
"0": {
"name": "punctuation.definition.comment.json.comments"
}
},
"end": "\\*/",
"name": "comment.block.json.comments"
},
{
"captures": {
"1": {
"name": "punctuation.definition.comment.json.comments"
}
},
"match": "(//).*$\\n?",
"name": "comment.line.double-slash.js"
}
]
},
"constant": {
"match": "\\b(?:true|false|null)\\b",
"name": "constant.language.json.comments"
},
"number": {
"match": "(?x) # turn on extended mode\n -? # an optional minus\n (?:\n 0 # a zero\n | # ...or...\n [1-9] # a 1-9 character\n \\d* # followed by zero or more digits\n )\n (?:\n (?:\n \\. # a period\n \\d+ # followed by one or more digits\n )?\n (?:\n [eE] # an e character\n [+-]? # followed by an option +/-\n \\d+ # followed by one or more digits\n )? # make exponent optional\n )? # make decimal portion optional",
"name": "constant.numeric.json.comments"
},
"object": {
"begin": "\\{",
"beginCaptures": {
"0": {
"name": "punctuation.definition.dictionary.begin.json.comments"
}
},
"end": "\\}",
"endCaptures": {
"0": {
"name": "punctuation.definition.dictionary.end.json.comments"
}
},
"name": "meta.structure.dictionary.json.comments",
"patterns": [
{
"comment": "the JSON object key",
"include": "#objectkey"
},
{
"include": "#comments"
},
{
"begin": ":",
"beginCaptures": {
"0": {
"name": "punctuation.separator.dictionary.key-value.json.comments"
}
},
"end": "(,)|(?=\\})",
"endCaptures": {
"1": {
"name": "punctuation.separator.dictionary.pair.json.comments"
}
},
"name": "meta.structure.dictionary.value.json.comments",
"patterns": [
{
"comment": "the JSON object value",
"include": "#value"
},
{
"match": "[^\\s,]",
"name": "invalid.illegal.expected-dictionary-separator.json.comments"
}
]
},
{
"match": "[^\\s\\}]",
"name": "invalid.illegal.expected-dictionary-separator.json.comments"
}
]
},
"string": {
"begin": "\"",
"beginCaptures": {
"0": {
"name": "punctuation.definition.string.begin.json.comments"
}
},
"end": "\"",
"endCaptures": {
"0": {
"name": "punctuation.definition.string.end.json.comments"
}
},
"name": "string.quoted.double.json.comments",
"patterns": [
{
"include": "#stringcontent"
}
]
},
"objectkey": {
"begin": "\"",
"beginCaptures": {
"0": {
"name": "punctuation.support.type.property-name.begin.json.comments"
}
},
"end": "\"",
"endCaptures": {
"0": {
"name": "punctuation.support.type.property-name.end.json.comments"
}
},
"name": "string.json.comments support.type.property-name.json.comments",
"patterns": [
{
"include": "#stringcontent"
}
]
},
"stringcontent": {
"patterns": [
{
"match": "(?x) # turn on extended mode\n \\\\ # a literal backslash\n (?: # ...followed by...\n [\"\\\\/bfnrt] # one of these characters\n | # ...or...\n u # a u\n [0-9a-fA-F]{4}) # and four hex digits",
"name": "constant.character.escape.json.comments"
},
{
"match": "\\\\.",
"name": "invalid.illegal.unrecognized-string-escape.json.comments"
}
]
},
"value": {
"patterns": [
{
"include": "#constant"
},
{
"include": "#number"
},
{
"include": "#string"
},
{
"include": "#array"
},
{
"include": "#object"
},
{
"include": "#comments"
}
]
}
}
}
@@ -120,6 +120,11 @@ Visual Studio-like style based on original C# coloring by Jason Diamond <jason@d
*/
.vscode-light .hljs-function,
.vscode-light .hljs-params {
color: inherit;
}
.vscode-light .hljs-comment,
.vscode-light .hljs-quote,
.vscode-light .hljs-variable {
@@ -196,18 +196,15 @@ pre code {
}
.vscode-light pre:not(.hljs),
.vscode-light code > div {
.vscode-light pre {
background-color: rgba(220, 220, 220, 0.4);
}
.vscode-dark pre:not(.hljs),
.vscode-dark code > div {
.vscode-dark pre {
background-color: rgba(10, 10, 10, 0.4);
}
.vscode-high-contrast pre:not(.hljs),
.vscode-high-contrast code > div {
.vscode-high-contrast pre {
background-color: rgb(0, 0, 0);
}
@@ -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",
@@ -5,8 +5,13 @@
import * as vscode from 'vscode';
import { MarkdownEngine } from '../markdownEngine';
import { TableOfContentsProvider, SkinnyTextDocument } from '../tableOfContentsProvider';
import { TableOfContentsProvider, SkinnyTextDocument, TocEntry } from '../tableOfContentsProvider';
interface MarkdownSymbol {
readonly level: number;
readonly parent: MarkdownSymbol | undefined;
readonly children: vscode.DocumentSymbol[];
}
export default class MDDocumentSymbolProvider implements vscode.DocumentSymbolProvider {
@@ -14,10 +19,57 @@ export default class MDDocumentSymbolProvider implements vscode.DocumentSymbolPr
private readonly engine: MarkdownEngine
) { }
public async provideDocumentSymbols(document: SkinnyTextDocument): Promise<vscode.SymbolInformation[]> {
public async provideDocumentSymbolInformation(document: SkinnyTextDocument): Promise<vscode.SymbolInformation[]> {
const toc = await new TableOfContentsProvider(this.engine, document).getToc();
return toc.map(entry => {
return new vscode.SymbolInformation('#'.repeat(entry.level) + ' ' + entry.text, vscode.SymbolKind.String, '', entry.location);
});
return toc.map(entry => this.toSymbolInformation(entry));
}
public async provideDocumentSymbols(document: SkinnyTextDocument): Promise<vscode.DocumentSymbol[]> {
const toc = await new TableOfContentsProvider(this.engine, document).getToc();
const root: MarkdownSymbol = {
level: -Infinity,
children: [],
parent: undefined
};
this.buildTree(root, toc);
return root.children;
}
private buildTree(parent: MarkdownSymbol, entries: TocEntry[]) {
if (!entries.length) {
return;
}
const entry = entries[0];
const symbol = this.toDocumentSymbol(entry);
symbol.children = [];
while (parent && entry.level <= parent.level) {
parent = parent.parent!;
}
parent.children.push(symbol);
this.buildTree({ level: entry.level, children: symbol.children, parent }, entries.slice(1));
}
private toSymbolInformation(entry: TocEntry): vscode.SymbolInformation {
return new vscode.SymbolInformation(
this.getSymbolName(entry),
vscode.SymbolKind.String,
'',
entry.location);
}
private toDocumentSymbol(entry: TocEntry) {
return new vscode.DocumentSymbol(
this.getSymbolName(entry),
'',
vscode.SymbolKind.String,
entry.location.range,
entry.location.range);
}
private getSymbolName(entry: TocEntry): string {
return '#'.repeat(entry.level) + ' ' + entry.text;
}
}
@@ -136,7 +136,7 @@ export default class MarkdownWorkspaceSymbolProvider implements vscode.Workspace
private getSymbols(document: SkinnyTextDocument): Lazy<Thenable<vscode.SymbolInformation[]>> {
return lazy(async () => {
return this._symbolProvider.provideDocumentSymbols(document);
return this._symbolProvider.provideDocumentSymbolInformation(document);
});
}
@@ -0,0 +1,86 @@
/*---------------------------------------------------------------------------------------------
* 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 * as vscode from 'vscode';
import SymbolProvider from '../features/documentSymbolProvider';
import { InMemoryDocument } from './inMemoryDocument';
import { createNewMarkdownEngine } from './engine';
const testFileName = vscode.Uri.parse('test.md');
function getSymbolsForFile(fileContents: string) {
const doc = new InMemoryDocument(testFileName, fileContents);
const provider = new SymbolProvider(createNewMarkdownEngine());
return provider.provideDocumentSymbols(doc);
}
suite('markdown.DocumentSymbolProvider', () => {
test('Should not return anything for empty document', async () => {
const symbols = await getSymbolsForFile('');
assert.strictEqual(symbols.length, 0);
});
test('Should not return anything for document with no headers', async () => {
const symbols = await getSymbolsForFile('a\na');
assert.strictEqual(symbols.length, 0);
});
test('Should not return anything for document with # but no real headers', async () => {
const symbols = await getSymbolsForFile('a#a\na#');
assert.strictEqual(symbols.length, 0);
});
test('Should return single symbol for single header', async () => {
const symbols = await getSymbolsForFile('# h');
assert.strictEqual(symbols.length, 1);
assert.strictEqual(symbols[0].name, '# h');
});
test('Should not care about symbol level for single header', async () => {
const symbols = await getSymbolsForFile('### h');
assert.strictEqual(symbols.length, 1);
assert.strictEqual(symbols[0].name, '### h');
});
test('Should put symbols of same level in flat list', async () => {
const symbols = await getSymbolsForFile('## h\n## h2');
assert.strictEqual(symbols.length, 2);
assert.strictEqual(symbols[0].name, '## h');
assert.strictEqual(symbols[1].name, '## h2');
});
test('Should nest symbol of level - 1 under parent', async () => {
const symbols = await getSymbolsForFile('# h\n## h2\n## h3');
assert.strictEqual(symbols.length, 1);
assert.strictEqual(symbols[0].name, '# h');
assert.strictEqual(symbols[0].children.length, 2);
assert.strictEqual(symbols[0].children[0].name, '## h2');
assert.strictEqual(symbols[0].children[1].name, '## h3');
});
test('Should nest symbol of level - n under parent', async () => {
const symbols = await getSymbolsForFile('# h\n#### h2');
assert.strictEqual(symbols.length, 1);
assert.strictEqual(symbols[0].name, '# h');
assert.strictEqual(symbols[0].children.length, 1);
assert.strictEqual(symbols[0].children[0].name, '#### h2');
});
test('Should flatten children where lower level occurs first', async () => {
const symbols = await getSymbolsForFile('# h\n### h2\n## h3');
assert.strictEqual(symbols.length, 1);
assert.strictEqual(symbols[0].name, '# h');
assert.strictEqual(symbols[0].children.length, 2);
assert.strictEqual(symbols[0].children[0].name, '### h2');
assert.strictEqual(symbols[0].children[1].name, '## h3');
});
});
@@ -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"
+1 -1
View File
@@ -100,7 +100,7 @@
}
},
"dependencies": {
"vscode-nls": "^3.2.1"
"vscode-nls": "^3.2.4"
},
"devDependencies": {
"@types/node": "8.0.33"
+3 -3
View File
@@ -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"
+1 -1
View File
@@ -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",
+1 -1
View File
@@ -1,6 +1,6 @@
{
"description": "Extension to add task support for npm scripts.",
"displayName": "Npm support for VSCode",
"displayName": "Npm support for VS Code",
"config.npm.autoDetect": "Controls whether auto detection of npm scripts is on or off. Default is on.",
"config.npm.runSilent": "Run npm commands with the `--silent` option.",
"config.npm.packageManager": "The package manager used to run scripts.",
+7 -3
View File
@@ -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];
+3 -3
View File
@@ -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"
+3 -3
View File
@@ -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"
+1 -1
View File
@@ -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": {
@@ -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
View 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
View 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
}
@@ -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;
}
@@ -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
View 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
View 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;
}
+26 -3
View File
@@ -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());
}
}
+16 -25
View File
@@ -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 {
+17 -14
View File
@@ -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
});
}
+3 -3
View File
@@ -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"
@@ -290,7 +290,9 @@
}
},
{
"scope": "support.type.property-name.json",
"scope": [
"support.type.property-name.json"
],
"settings": {
"foreground": "#0451a5"
}
@@ -40,7 +40,8 @@
"name": "Comments: Documentation",
"scope": [
"comment.documentation",
"comment.block.documentation"
"comment.block.documentation",
"comment.block.documentation punctuation.definition.comment "
],
"settings": {
"foreground": "#448C27"
@@ -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"

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