Initial VS Code 1.19 source merge (#571)

* Initial 1.19 xcopy

* Fix yarn build

* Fix numerous build breaks

* Next batch of build break fixes

* More build break fixes

* Runtime breaks

* Additional post merge fixes

* Fix windows setup file

* Fix test failures.

* Update license header blocks to refer to source eula
This commit is contained in:
Karl Burtram
2018-01-28 23:37:17 -08:00
committed by GitHub
parent 9a1ac20710
commit 251ae01c3e
8009 changed files with 93378 additions and 35634 deletions

View File

@@ -11,6 +11,6 @@ trim_trailing_whitespace = true
# The indent size used in the `package.json` file cannot be changed # The indent size used in the `package.json` file cannot be changed
# https://github.com/npm/npm/pull/3180#issuecomment-16336516 # https://github.com/npm/npm/pull/3180#issuecomment-16336516
[{*.yml,*.yaml,npm-shrinkwrap.json,package.json}] [{*.yml,*.yaml,package.json}]
indent_style = space indent_style = space
indent_size = 2 indent_size = 2

View File

@@ -10,5 +10,10 @@
"no-extra-semi": "warn", "no-extra-semi": "warn",
"semi": "warn" "semi": "warn"
}, },
"extends": "eslint:recommended" "extends": "eslint:recommended",
"parserOptions": {
"ecmaFeatures": {
"experimentalObjectRestSpread": true
}
}
} }

0
.gitattributes vendored
View File

17
.gitignore vendored
View File

@@ -1,22 +1,8 @@
.DS_Store .DS_Store
npm-debug.log npm-debug.log
Thumbs.db Thumbs.db
.DS_Store
*.dat
*.db
*.exe
*.log
*.nupkg
*.orig
*.vsix
*BROWSE.VC*
sqltoolsservice
coverage
test-reports
.vscode-test
node_modules/ node_modules/
.build/ .build/
.vs/
out/ out/
out-build/ out-build/
out-editor/ out-editor/
@@ -26,4 +12,5 @@ out-vscode/
out-vscode-min/ out-vscode-min/
build/node_modules build/node_modules
coverage/ coverage/
_site test_data/
yarn-error.log

1
.nvmrc Normal file
View File

@@ -0,0 +1 @@
8.9.2

View File

@@ -7,10 +7,13 @@ os:
cache: cache:
directories: directories:
- $HOME/.npm - $HOME/.cache/yarn
notifications: notifications:
email: false email: false
webhooks:
- http://vscode-probot.westus.cloudapp.azure.com:3450/travis/notifications
- http://vscode-test-probot.westus.cloudapp.azure.com:3450/travis/notifications
addons: addons:
apt: apt:
@@ -31,24 +34,29 @@ before_install:
- git submodule update --init --recursive - git submodule update --init --recursive
- git clone --depth 1 https://github.com/creationix/nvm.git ./.nvm - git clone --depth 1 https://github.com/creationix/nvm.git ./.nvm
- source ./.nvm/nvm.sh - source ./.nvm/nvm.sh
- nvm install 7.9.0 - nvm install 8.9.1
- nvm use 7.9.0 - nvm use 8.9.1
- npm config set python `which python` - npm i -g yarn
- npm install -g gulp # - npm config set python `which python`
- if [ $TRAVIS_OS_NAME == "linux" ]; then - if [ $TRAVIS_OS_NAME == "linux" ]; then
export CXX="g++-4.9" CC="gcc-4.9" DISPLAY=:99.0; export CXX="g++-4.9" CC="gcc-4.9" DISPLAY=:99.0;
sh -e /etc/init.d/xvfb start; sh -e /etc/init.d/xvfb start;
sleep 3; sleep 3;
fi fi
# Make npm logs less verbose
# - npm config set depth 0
# - npm config set loglevel warn
install: install:
- ./scripts/npm.sh install - yarn
script: script:
- gulp electron --silent - node_modules/.bin/gulp hygiene
- gulp compile --silent --max_old_space_size=4096 - node_modules/.bin/gulp electron --silent
- gulp optimize-vscode --silent --max_old_space_size=4096 - node_modules/.bin/gulp compile --silent --max_old_space_size=4096
- node_modules/.bin/gulp optimize-vscode --silent --max_old_space_size=4096
- if [[ "$TRAVIS_OS_NAME" == "linux" ]]; then ./scripts/test.sh --coverage --reporter dot; else ./scripts/test.sh --reporter dot; fi - if [[ "$TRAVIS_OS_NAME" == "linux" ]]; then ./scripts/test.sh --coverage --reporter dot; else ./scripts/test.sh --reporter dot; fi
- ./scripts/test-integration.sh
after_success: after_success:
- if [[ "$TRAVIS_OS_NAME" == "linux" ]]; then node_modules/.bin/coveralls < .build/coverage/lcov.info; fi - if [[ "$TRAVIS_OS_NAME" == "linux" ]]; then node_modules/.bin/coveralls < .build/coverage/lcov.info; fi

1
.vscode/launch.json vendored
View File

@@ -104,6 +104,7 @@
}, },
"stopOnEntry": false, "stopOnEntry": false,
"args": [ "args": [
"--delay",
"--timeout", "--timeout",
"2000" "2000"
], ],

View File

@@ -34,5 +34,7 @@
"command": "${workspaceFolder}\\scripts\\test.bat --coverage --run ${file}" "command": "${workspaceFolder}\\scripts\\test.bat --coverage --run ${file}"
} }
} }
] ],
"typescript.tsdk": "node_modules/typescript/lib",
"git.ignoreLimitWarning": true
} }

6
.vscode/tasks.json vendored
View File

@@ -33,11 +33,11 @@
"task": "tslint", "task": "tslint",
"label": "Run tslint", "label": "Run tslint",
"problemMatcher": [ "problemMatcher": [
"$tslint4" "$tslint5"
] ]
}, },
{ {
"taskName": "Run tests", "label": "Run tests",
"type": "shell", "type": "shell",
"command": "./scripts/test.sh", "command": "./scripts/test.sh",
"windows": { "windows": {
@@ -50,7 +50,7 @@
} }
}, },
{ {
"taskName": "Run Dev", "label": "Run Dev",
"type": "shell", "type": "shell",
"command": "./scripts/code.sh", "command": "./scripts/code.sh",
"windows": { "windows": {

3
.yarnrc Normal file
View File

@@ -0,0 +1,3 @@
disturl "https://atom.io/download/electron"
target "1.7.11"
runtime "electron"

View File

@@ -1,46 +1,103 @@
## Contributing Issues # Contributing to VS Code
### Before Submitting an Issue Welcome, and thank you for your interest in contributing to VS Code!
First, please do a search in [open issues](https://github.com/Microsoft/sqlopsstudio/issues) to see if the issue or feature request has already been filed. Use this [query](https://github.com/Microsoft/sqlopsstudio/issues?q=is%3Aopen+is%3Aissue+label%3Afeature-request+sort%3Areactions-%2B1-desc) to search for the most popular feature requests.
If you find your issue already exists, make relevant comments and add your [reaction](https://github.com/blog/2119-add-reactions-to-pull-requests-issues-and-comments). Use a reaction in place of a "+1" comment. There are many ways that you can contribute, beyond writing code. The goal of this document is to provide a high-level overview of how you can get involved.
👍 - upvote ## Asking Questions
👎 - downvote Have a question? Rather than opening an issue, please ask away on [Stack Overflow](https://stackoverflow.com/questions/tagged/vscode) using the tag `vscode`.
If you cannot find an existing issue that describes your bug or feature, submit an issue using the guidelines below. The active community will be eager to assist you. Your well-worded question will serve as a resource to others searching for help.
## Writing Good Bug Reports and Feature Requests ## Providing Feedback
File a single issue per problem and feature request. Your comments and feedback are welcome, and the development team is available via handful of different channels.
* Do not enumerate multiple bugs or feature requests in the same issue. See the [Feedback Channels](https://github.com/Microsoft/vscode/wiki/Feedback-Channels) wiki page for details about how to share your thoughts.
* Do not add your issue as a comment to an existing issue unless it's for the identical input. Many issues look similar, but have different causes.
The more information you can provide, the more likely someone will be successful reproducing the issue and finding a fix. ## Reporting Issues
Please include the following with each issue. Have you identified a reproducible problem in VS Code? Have a feature request? We want to hear about it! Here's how you can make reporting your issue as effective as possible.
* Version of SQL Ops Studio ### Identify Where to Report
> **Tip:** You can easily create an issue using `Report Issues` from SQL Operations Studio Help menu. The VS Code project is distributed across multiple repositories. Try to file the issue against the correct repository. Check the list of [Related Projects](https://github.com/Microsoft/vscode/wiki/Related-Projects) if you aren't sure which repo is correct.
* Reproducible steps (1... 2... 3...) and what you expected versus what you actually saw. Can you recreate the issue even after [disabling all extensions](https://code.visualstudio.com/docs/editor/extension-gallery#_disable-an-extension)? If you find the issue is caused by an extension you have installed, please file an issue on the extension's repo directly.
* Images, animations, or a link to a video.
* A code snippet that demonstrates the issue or a link to a code repository we can easily pull down onto our machine to recreate the issue.
> **Note:** Because we need to copy and paste the code snippet, including a code snippet as a media file (i.e. .gif) is not sufficient. ### Look For an Existing Issue
* Errors in the Dev Tools Console (Help | Toggle Developer Tools) Before you create a new issue, please do a search in [open issues](https://github.com/Microsoft/vscode/issues) to see if the issue or feature request has already been filed.
Be sure to scan through the [most popular](https://github.com/Microsoft/vscode/issues?q=is%3Aopen+is%3Aissue+label%3Afeature-request+sort%3Areactions-%2B1-desc) feature requests.
If you find your issue already exists, make relevant comments and add your [reaction](https://github.com/blog/2119-add-reactions-to-pull-requests-issues-and-comments). Use a reaction in place of a "+1" comment:
* 👍 - upvote
* 👎 - downvote
If you cannot find an existing issue that describes your bug or feature, create a new issue using the guidelines below.
### Writing Good Bug Reports and Feature Requests
File a single issue per problem and feature request. Do not enumerate multiple bugs or feature requests in the same issue.
Do not add your issue as a comment to an existing issue unless it's for the identical input. Many issues look similar, but have different causes.
The more information you can provide, the more likely someone will be successful reproducing the issue and finding a fix.
Please include the following with each issue:
* Version of VS Code
* List of extensions that you have installed.
* **Tip:** You can easily add the list of extensions by creating the issue using `Report Issues` from VS Code's Help menu
* Reproducible steps (1... 2... 3...) that cause the issue
* What you expected to see, versus what you actually saw
* Images, animations, or a link to a video showing the issue occuring
* A code snippet that demonstrates the issue or a link to a code repository the developers can easily pull down to recreate the issue locally
* **Note:** Because the developers need to copy and paste the code snippet, including a code snippet as a media file (i.e. .gif) is not sufficient.
* Errors from the Dev Tools Console (open from the menu: Help > Toggle Developer Tools)
### Final Checklist
Please remember to do the following: Please remember to do the following:
* Search the issue repository to see if there exists a duplicate. * [ ] Search the issue repository to ensure your report is a new issue
* Simplify your scripts around the issue so we can better isolate the problem.
Don't feel bad if we can't reproduce the issue and ask for more information! * [ ] Recreate the issue after disabling all extensions
* [ ] Simplify your code around the issue to better isolate the problem
Don't feel bad if the developers can't reproduce the issue right away. They will simply ask for more information!
### Follow Your Issue
Once submitted, your report will go into the [issue tracking](https://github.com/Microsoft/vscode/wiki/Issue-Tracking) work flow. Be sure to understand what will happen next, so you know what to expect, and how to continue to assist throughout the process.
## Automated Issue Management
We use a bot to help us manage issues. This bot currently:
* Automatically closes any issue marked `needs-more-info` if there has been no response in past 7 days.
* Automatically locks 45 days after they are closed.
If you believe the bot got something wrong, please open a new issue and let us know.
## Contributing Fixes ## Contributing Fixes
If you are interested in fixing issues and contributing directly to the code base,
please see the document [How to Contribute](https://github.com/Microsoft/sqlopsstudio/wiki/How-to-Contribute). If you are interested in writing code to fix issues,
please see [How to Contribute](https://github.com/Microsoft/vscode/wiki/How-to-Contribute) in the wiki.
# Thank You!
Your contributions to open source, large or small, make great projects like this possible. Thank you for taking the time to contribute.

View File

@@ -771,5 +771,42 @@
"\"\"\"" "\"\"\""
], ],
"isProd": true "isProd": true
},
{
"name": "spdlog original",
"version": "0.14.0",
"repositoryURL": "https://github.com/gabime/spdlog",
"license": "MIT",
"isProd": true
},
{
"isLicense": true,
"name": "spdlog",
"version": "0.14.0",
"repositoryURL": "https://github.com/gabime/spdlog",
"license": "MIT",
"licenseDetail": [
"MIT License",
"",
"Copyright (c) Microsoft Corporation. All rights reserved.",
"",
"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"
]
} }
] ]

View File

@@ -1,56 +1,54 @@
# SQL Operations Studio # Visual Studio Code - Open Source
SQL Operations Studio is a data management tool that enables you to work with SQL Server, Azure SQL DB and SQL DW from Windows, macOS and Linux. [![Build Status](https://travis-ci.org/Microsoft/vscode.svg?branch=master)](https://travis-ci.org/Microsoft/vscode)
[![Build Status](https://ci.appveyor.com/api/projects/status/vuhlhg80tj3e2a0l/branch/master?svg=true)](https://ci.appveyor.com/project/VSCode/vscode)
[![Coverage Status](https://img.shields.io/coveralls/Microsoft/vscode/master.svg)](https://coveralls.io/github/Microsoft/vscode?branch=master)
[![Gitter](https://img.shields.io/badge/chat-on%20gitter-blue.svg)](https://gitter.im/Microsoft/vscode)
**Download SQL Operations Studio January Public Preview** [VS Code](https://code.visualstudio.com) is a new type of tool that combines the simplicity of
a code editor with what developers need for their core edit-build-debug cycle. Code
provides comprehensive editing and debugging support, an extensibility model, and lightweight integration with existing tools.
Platform | Link VS Code is updated monthly with new features and bug fixes. You can download it for Windows, macOS, and Linux on [VS Code's website](https://code.visualstudio.com/Download). To get the latest releases every day, you can install the [Insiders version of VS Code](https://code.visualstudio.com/insiders). This builds from the master branch and is updated at least daily.
-- | --
Windows Setup Installer | https://go.microsoft.com/fwlink/?linkid=866480
Windows ZIP | https://go.microsoft.com/fwlink/?linkid=866479
macOS ZIP | https://go.microsoft.com/fwlink/?linkid=866481
Linux TAR.GZ | https://go.microsoft.com/fwlink/?linkid=866482
Linux DEB | https://go.microsoft.com/fwlink/?linkid=866484
Linux RPM | https://go.microsoft.com/fwlink/?linkid=866483
Go to our [download page](https://aka.ms/sqlopsstudio) for more specific instructions. <p align="center">
<img alt="VS Code in action" src="https://cloud.githubusercontent.com/assets/11839736/16642200/6624dde0-43bd-11e6-8595-c81885ba0dc2.png">
</p>
Try out the latest insiders build from `master` at https://github.com/Microsoft/sqlopsstudio/releases. The [`vscode`](https://github.com/microsoft/vscode) repository is where we do development and there are many ways you can participate in the project, for example:
**Feature Highlights** * [Submit bugs and feature requests](https://github.com/microsoft/vscode/issues) and help us verify as they are checked in
* Review [source code changes](https://github.com/microsoft/vscode/pulls)
- Cross-Platform DB management for Windows, macOS and Linux with simple XCopy deployment * Review the [documentation](https://github.com/microsoft/vscode-docs) and make pull requests for anything from typos to new content
- SQL Server Connection Management with Connection Dialog, Server Groups, Azure Integration and Registered Servers
- Object Explorer supporting schema browsing and contextual command execution
- T-SQL Query Editor with advanced coding features such as autosuggestions, error diagnostics, tooltips, formatting and peek definition
- Query Results Viewer with advanced data grid supporting large result sets, export to JSON\CSV\Excel, query plan and charting
- Management Dashboard supporting customizable widgets with drill-through actionable insights
- Visual Data Editor that enables direct row insertion, update and deletion into tables
- Backup and Restore dialogs that enables advanced customization and remote filesystem browsing, configured tasks can be executed or scripted
- Task History window to view current task execution status, completion results with error messages and task T-SQL scripting
- Scripting support to generate CREATE, SELECT, ALTER and DROP statements for database objects
- Workspaces with full Git integration and Find In Files support to managing T-SQL script libraries
- Modern light-weight shell with theming, user settings, full screen support, integrated terminal and numerous other features
Here's some of these features in action.
<img src='https://github.com/Microsoft/sqlopsstudio/blob/master/docs/overview_screen.jpg' width='800px'>
## Contributing ## Contributing
If you are interested in fixing issues and contributing directly to the code base, If you are interested in fixing issues and contributing directly to the code base,
please see the document [How to Contribute](https://github.com/Microsoft/sqlopsstudio/wiki/How-to-Contribute), which covers the following: please see the document [How to Contribute](https://github.com/Microsoft/vscode/wiki/How-to-Contribute), which covers the following:
* [How to build and run from source](https://github.com/Microsoft/sqlopsstudio/wiki/How-to-Contribute#Build-and-Run-From-Source) * [How to build and run from source](https://github.com/Microsoft/vscode/wiki/How-to-Contribute#build-and-run-from-source)
* [The development workflow, including debugging and running tests](https://github.com/Microsoft/sqlopsstudio/wiki/How-to-Contribute#development-workflow) * [The development workflow, including debugging and running tests](https://github.com/Microsoft/vscode/wiki/How-to-Contribute#development-workflow)
* [Submitting pull requests](https://github.com/Microsoft/sqlopsstudio/wiki/How-to-Contribute#pull-requests) * [Coding Guidelines](https://github.com/Microsoft/vscode/wiki/Coding-Guidelines)
* [Submitting pull requests](https://github.com/Microsoft/vscode/wiki/How-to-Contribute#pull-requests)
* [Contributing to translations](https://aka.ms/vscodeloc)
This project has adopted the [Microsoft Open Source Code of Conduct](https://opensource.microsoft.com/codeofconduct/). For more information see the [Code of Conduct FAQ](https://opensource.microsoft.com/codeofconduct/faq/) or contact [opencode@microsoft.com](mailto:opencode@microsoft.com) with any additional questions or comments. Please see also our [Code of Conduct](CODE_OF_CONDUCT.md).
## Privacy Statement ## Feedback
The [Microsoft Enterprise and Developer Privacy Statement](https://privacy.microsoft.com/en-us/privacystatement) describes the privacy statement of this software.
* Ask a question on [Stack Overflow](https://stackoverflow.com/questions/tagged/vscode).
* Request a new feature on [GitHub](CONTRIBUTING.md).
* Vote for [popular feature requests](https://github.com/Microsoft/vscode/issues?q=is%3Aopen+is%3Aissue+label%3Afeature-request+sort%3Areactions-%2B1-desc).
* File a bug in [GitHub Issues](https://github.com/Microsoft/vscode/issues).
* [Tweet](https://twitter.com/code) us with other feedback.
## Related Projects
Many of the core components and extensions to Code live in their own repositories on GitHub. For example, the [node debug adapter](https://github.com/microsoft/vscode-node-debug) and the [mono debug adapter](https://github.com/microsoft/vscode-mono-debug).
For a complete list, please see the [Related Projects](https://github.com/Microsoft/vscode/wiki/Related-Projects) page on our wiki.
## License ## License
Copyright (c) Microsoft Corporation. All rights reserved. Copyright (c) Microsoft Corporation. All rights reserved.
Licensed under the [Source EULA](LICENSE.txt). Licensed under the [MIT](LICENSE.txt) License.

View File

@@ -3,19 +3,17 @@ environment:
VSCODE_BUILD_VERBOSE: true VSCODE_BUILD_VERBOSE: true
cache: cache:
- '%APPDATA%\npm-cache' - '%LOCALAPPDATA%\Yarn\cache'
install: install:
- ps: Install-Product node 7.9.0 x64 - ps: Install-Product node 8.9.1 x64
- npm install -g npm@4 --silent
build_script: build_script:
- .\scripts\npm.bat install - yarn
- .\node_modules\.bin\gulp electron - .\node_modules\.bin\gulp electron
- npm run compile - npm run compile
test_script: test_script:
- node --version - node --version
- npm --version
- .\scripts\test.bat - .\scripts\test.bat
- .\scripts\test-integration.bat - .\scripts\test-integration.bat

74
build/dependencies.js Normal file
View File

@@ -0,0 +1,74 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the Source EULA. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
'use strict';
const path = require('path');
const parseSemver = require('parse-semver');
const cp = require('child_process');
const _ = require('underscore');
function asYarnDependency(prefix, tree) {
let parseResult;
try {
parseResult = parseSemver(tree.name);
} catch (err) {
err.message += `: ${tree.name}`;
console.warn(`Could not parse semver: ${tree.name}`);
return null;
}
// not an actual dependency in disk
if (parseResult.version !== parseResult.range) {
return null;
}
const name = parseResult.name;
const version = parseResult.version;
const dependencyPath = path.join(prefix, name);
const children = [];
for (const child of (tree.children || [])) {
const dep = asYarnDependency(path.join(prefix, name, 'node_modules'), child);
if (dep) {
children.push(dep);
}
}
return { name, version, path: dependencyPath, children };
}
function getYarnProductionDependencies(cwd) {
const raw = cp.execSync('yarn list --json', { cwd, encoding: 'utf8', env: { ...process.env, NODE_ENV: 'production' }, stdio: [null, null, 'ignore'] });
const match = /^{"type":"tree".*$/m.exec(raw);
if (!match || match.length !== 1) {
throw new Error('Could not parse result of `yarn list --json`');
}
const trees = JSON.parse(match[0]).data.trees;
return trees
.map(tree => asYarnDependency(path.join(cwd, 'node_modules'), tree))
.filter(dep => !!dep);
}
function getProductionDependencies(cwd) {
const result = [];
const deps = getYarnProductionDependencies(cwd);
const flatten = dep => { result.push({ name: dep.name, version: dep.version, path: dep.path }); dep.children.forEach(flatten); };
deps.forEach(flatten);
return _.uniq(result);
}
module.exports.getProductionDependencies = getProductionDependencies;
if (require.main === module) {
const root = path.dirname(__dirname);
console.log(JSON.stringify(getProductionDependencies(root), null, ' '));
}

View File

@@ -62,6 +62,8 @@ const tasks = compilations.map(function (tsconfigFile) {
const reporter = createReporter(); const reporter = createReporter();
tsOptions.inlineSources = !!build; tsOptions.inlineSources = !!build;
tsOptions.base = path.dirname(absolutePath);
const compilation = tsb.create(tsOptions, null, null, err => reporter(err.toString())); const compilation = tsb.create(tsOptions, null, null, err => reporter(err.toString()));
return function () { return function () {

View File

@@ -37,6 +37,7 @@ const eolFilter = [
'!ThirdPartyNotices.txt', '!ThirdPartyNotices.txt',
'!LICENSE.txt', '!LICENSE.txt',
'!extensions/**/out/**', '!extensions/**/out/**',
'!test/smoke/out/**',
'!**/node_modules/**', '!**/node_modules/**',
'!**/fixtures/**', '!**/fixtures/**',
'!**/*.{svg,exe,png,bmp,scpt,bat,cmd,cur,ttf,woff,eot}', '!**/*.{svg,exe,png,bmp,scpt,bat,cmd,cur,ttf,woff,eot}',
@@ -56,6 +57,7 @@ const indentationFilter = [
'!**/*.template', '!**/*.template',
'!**/*.yaml', '!**/*.yaml',
'!**/*.yml', '!**/*.yml',
'!**/yarn.lock',
'!**/lib/**', '!**/lib/**',
'!extensions/**/*.d.ts', '!extensions/**/*.d.ts',
'!src/typings/**/*.d.ts', '!src/typings/**/*.d.ts',
@@ -63,11 +65,11 @@ const indentationFilter = [
'!**/*.d.ts.recipe', '!**/*.d.ts.recipe',
'!test/assert.js', '!test/assert.js',
'!**/package.json', '!**/package.json',
'!**/npm-shrinkwrap.json',
'!**/octicons/**', '!**/octicons/**',
'!**/vs/base/common/marked/raw.marked.js', '!**/vs/base/common/marked/raw.marked.js',
'!**/vs/base/common/winjs.base.raw.js', '!**/vs/base/common/winjs.base.raw.js',
'!**/vs/base/node/terminateProcess.sh', '!**/vs/base/node/terminateProcess.sh',
'!**/vs/base/node/ps-win.ps1',
'!**/vs/nls.js', '!**/vs/nls.js',
'!**/vs/css.js', '!**/vs/css.js',
'!**/vs/loader.js', '!**/vs/loader.js',
@@ -122,7 +124,8 @@ const tslintFilter = [
'!**/node_modules/**', '!**/node_modules/**',
'!extensions/typescript/test/colorize-fixtures/**', '!extensions/typescript/test/colorize-fixtures/**',
'!extensions/vscode-api-tests/testWorkspace/**', '!extensions/vscode-api-tests/testWorkspace/**',
'!extensions/**/*.test.ts' '!extensions/**/*.test.ts',
'!extensions/html/server/lib/jquery.d.ts'
]; ];
const copyrightHeader = [ const copyrightHeader = [
@@ -132,17 +135,6 @@ const copyrightHeader = [
' *--------------------------------------------------------------------------------------------*/' ' *--------------------------------------------------------------------------------------------*/'
].join('\n'); ].join('\n');
function reportFailures(failures) {
failures.forEach(failure => {
const name = failure.name || failure.fileName;
const position = failure.startPosition;
const line = position.lineAndCharacter ? position.lineAndCharacter.line : position.line;
const character = position.lineAndCharacter ? position.lineAndCharacter.character : position.character;
console.error(`${name}:${line + 1}:${character + 1}:${failure.failure}`);
});
}
gulp.task('eslint', () => { gulp.task('eslint', () => {
return vfs.src(all, { base: '.', follow: true, allowEmpty: true }) return vfs.src(all, { base: '.', follow: true, allowEmpty: true })
.pipe(filter(eslintFilter)) .pipe(filter(eslintFilter))
@@ -152,12 +144,12 @@ gulp.task('eslint', () => {
}); });
gulp.task('tslint', () => { gulp.task('tslint', () => {
const options = { summarizeFailureOutput: true }; const options = { emitError: false };
return vfs.src(all, { base: '.', follow: true, allowEmpty: true }) return vfs.src(all, { base: '.', follow: true, allowEmpty: true })
.pipe(filter(tslintFilter)) .pipe(filter(tslintFilter))
.pipe(gulptslint({ rulesDirectory: 'build/lib/tslint' })) .pipe(gulptslint({ rulesDirectory: 'build/lib/tslint' }))
.pipe(gulptslint.report(reportFailures, options)); .pipe(gulptslint.report(options));
}); });
const hygiene = exports.hygiene = (some, options) => { const hygiene = exports.hygiene = (some, options) => {
@@ -219,6 +211,17 @@ const hygiene = exports.hygiene = (some, options) => {
}); });
}); });
function reportFailures(failures) {
failures.forEach(failure => {
const name = failure.name || failure.fileName;
const position = failure.startPosition;
const line = position.lineAndCharacter ? position.lineAndCharacter.line : position.line;
const character = position.lineAndCharacter ? position.lineAndCharacter.character : position.character;
// console.error(`${name}:${line + 1}:${character + 1}:${failure.failure}`);
});
}
const tsl = es.through(function (file) { const tsl = es.through(function (file) {
const configuration = tslint.Configuration.findConfiguration(null, '.'); const configuration = tslint.Configuration.findConfiguration(null, '.');
const options = { formatter: 'json', rulesDirectory: 'build/lib/tslint' }; const options = { formatter: 'json', rulesDirectory: 'build/lib/tslint' };
@@ -227,9 +230,9 @@ const hygiene = exports.hygiene = (some, options) => {
linter.lint(file.relative, contents, configuration.results); linter.lint(file.relative, contents, configuration.results);
const result = linter.getResult(); const result = linter.getResult();
if (result.failureCount > 0) { if (result.failures.length > 0) {
reportFailures(result.failures); reportFailures(result.failures);
errorCount += result.failureCount; errorCount += result.failures.length;
} }
this.emit('data', file); this.emit('data', file);
@@ -254,20 +257,20 @@ const hygiene = exports.hygiene = (some, options) => {
const javascript = result const javascript = result
.pipe(filter(eslintFilter)) .pipe(filter(eslintFilter))
.pipe(gulpeslint('src/.eslintrc')) .pipe(gulpeslint('src/.eslintrc'))
.pipe(gulpeslint.formatEach('compact')); .pipe(gulpeslint.formatEach('compact'))
// {{SQL CARBON EDIT}} // {{SQL CARBON EDIT}}
// .pipe(gulpeslint.failAfterError()); // .pipe(gulpeslint.failAfterError());
return es.merge(typescript, javascript) return es.merge(typescript, javascript)
.pipe(es.through(null, function () { .pipe(es.through(null, function () {
// {{SQL CARBON EDIT}} // {{SQL CARBON EDIT}}
// if (errorCount > 0) { // if (errorCount > 0) {
// this.emit('error', 'Hygiene failed with ' + errorCount + ' errors. Check \'build/gulpfile.hygiene.js\'.'); // this.emit('error', 'Hygiene failed with ' + errorCount + ' errors. Check \'build/gulpfile.hygiene.js\'.');
// } else { // } else {
// this.emit('end'); // this.emit('end');
// } // }
this.emit('end'); this.emit('end');
})); }));
}; };
gulp.task('hygiene', () => hygiene('')); gulp.task('hygiene', () => hygiene(''));
@@ -303,11 +306,13 @@ if (require.main === module) {
.split(/\r?\n/) .split(/\r?\n/)
.filter(l => !!l); .filter(l => !!l);
hygiene(some, { skipEOL: skipEOL }).on('error', err => { if (some.length > 0) {
console.error(); hygiene(some, { skipEOL: skipEOL }).on('error', err => {
console.error(err); console.error();
process.exit(1); console.error(err);
}); process.exit(1);
});
}
}); });
}); });
} }

View File

@@ -6,27 +6,64 @@
'use strict'; 'use strict';
const gulp = require('gulp'); const gulp = require('gulp');
const jeditor = require('gulp-json-editor'); const json = require('gulp-json-editor');
const buffer = require('gulp-buffer');
const filter = require('gulp-filter');
const es = require('event-stream');
const util = require('./lib/util');
const remote = require('gulp-remote-src');
const zip = require('gulp-vinyl-zip');
const assign = require('object-assign');
const pkg = require('../package.json');
gulp.task('mixin', function () { gulp.task('mixin', function () {
const updateUrl = process.env['SQLOPS_UPDATEURL']; const repo = process.env['VSCODE_MIXIN_REPO'];
if (!updateUrl) {
console.log('Missing SQLOPS_UPDATEURL, skipping mixin'); if (!repo) {
console.log('Missing VSCODE_MIXIN_REPO, skipping mixin');
return; return;
} }
const quality = process.env['VSCODE_QUALITY']; const quality = process.env['VSCODE_QUALITY'];
if (!quality) { if (!quality) {
console.log('Missing VSCODE_QUALITY, skipping mixin'); console.log('Missing VSCODE_QUALITY, skipping mixin');
return; return;
} }
let newValues = { const url = `https://github.com/${repo}/archive/${pkg.distro}.zip`;
"updateUrl": updateUrl, const opts = { base: url };
"quality": quality const username = process.env['VSCODE_MIXIN_USERNAME'];
}; const password = process.env['VSCODE_MIXIN_PASSWORD'];
return gulp.src('./product.json') if (username || password) {
.pipe(jeditor(newValues)) opts.auth = { user: username || '', pass: password || '' };
}
console.log('Mixing in sources from \'' + url + '\':');
let all = remote('', opts)
.pipe(zip.src())
.pipe(filter(function (f) { return !f.isDirectory(); }))
.pipe(util.rebase(1));
if (quality) {
const productJsonFilter = filter('product.json', { restore: true });
const mixin = all
.pipe(filter(['quality/' + quality + '/**']))
.pipe(util.rebase(2))
.pipe(productJsonFilter)
.pipe(buffer())
.pipe(json(o => assign({}, require('../product.json'), o)))
.pipe(productJsonFilter.restore);
all = es.merge(mixin);
}
return all
.pipe(es.mapSync(function (f) {
console.log(f.relative);
return f;
}))
.pipe(gulp.dest('.')); .pipe(gulp.dest('.'));
}); });

View File

@@ -29,18 +29,15 @@ const root = path.dirname(__dirname);
const commit = util.getVersion(root); const commit = util.getVersion(root);
const packageJson = require('../package.json'); const packageJson = require('../package.json');
const product = require('../product.json'); const product = require('../product.json');
const shrinkwrap = require('../npm-shrinkwrap.json');
const crypto = require('crypto'); const crypto = require('crypto');
const i18n = require('./lib/i18n'); const i18n = require('./lib/i18n');
var del = require('del');
// {{SQL CARBON EDIT}} // {{SQL CARBON EDIT}}
const serviceInstaller = require('extensions-modules/lib/languageservice/serviceInstallerUtil'); const serviceInstaller = require('extensions-modules/lib/languageservice/serviceInstallerUtil');
const glob = require('glob'); const glob = require('glob');
const deps = require('./dependencies');
const getElectronVersion = require('./lib/electron').getElectronVersion;
const productDependencies = Object.keys(product.dependencies || {}); const productionDependencies = deps.getProductionDependencies(path.dirname(__dirname));
const dependencies = Object.keys(shrinkwrap.dependencies)
.concat(productDependencies); // additional dependencies from our product configuration
const baseModules = Object.keys(process.binding('natives')).filter(n => !/^_|\//.test(n)); const baseModules = Object.keys(process.binding('natives')).filter(n => !/^_|\//.test(n));
// {{SQL CARBON EDIT}} // {{SQL CARBON EDIT}}
const nodeModules = [ const nodeModules = [
@@ -50,14 +47,15 @@ const nodeModules = [
'rxjs/Subject', 'rxjs/Subject',
'rxjs/Observer', 'rxjs/Observer',
'ng2-charts/ng2-charts'] 'ng2-charts/ng2-charts']
.concat(dependencies) .concat(Object.keys(product.dependencies || {}))
.concat(_.uniq(productionDependencies.map(d => d.name)))
.concat(baseModules); .concat(baseModules);
// Build // Build
const builtInExtensions = [ const builtInExtensions = [
{ name: 'ms-vscode.node-debug', version: '1.18.3' }, { name: 'ms-vscode.node-debug', version: '1.19.8' },
{ name: 'ms-vscode.node-debug2', version: '1.18.5' } { name: 'ms-vscode.node-debug2', version: '1.19.4' }
]; ];
const excludedExtensions = [ const excludedExtensions = [
@@ -79,8 +77,8 @@ const vscodeResources = [
'out-build/bootstrap-amd.js', 'out-build/bootstrap-amd.js',
'out-build/paths.js', 'out-build/paths.js',
'out-build/vs/**/*.{svg,png,cur,html}', 'out-build/vs/**/*.{svg,png,cur,html}',
'out-build/vs/base/node/startupTimers.js', 'out-build/vs/base/common/performance.js',
'out-build/vs/base/node/{stdForkStart.js,terminateProcess.sh}', 'out-build/vs/base/node/{stdForkStart.js,terminateProcess.sh,ps-win.ps1}',
'out-build/vs/base/browser/ui/octiconLabel/octicons/**', 'out-build/vs/base/browser/ui/octiconLabel/octicons/**',
'out-build/vs/workbench/browser/media/*-theme.css', 'out-build/vs/workbench/browser/media/*-theme.css',
'out-build/vs/workbench/electron-browser/bootstrap/**', 'out-build/vs/workbench/electron-browser/bootstrap/**',
@@ -154,10 +152,10 @@ gulp.task('minify-vscode', ['clean-minified-vscode', 'optimize-index-js'], commo
const darwinCreditsTemplate = product.darwinCredits && _.template(fs.readFileSync(path.join(root, product.darwinCredits), 'utf8')); const darwinCreditsTemplate = product.darwinCredits && _.template(fs.readFileSync(path.join(root, product.darwinCredits), 'utf8'));
const config = { const config = {
version: packageJson.electronVersion, version: getElectronVersion(),
productAppName: product.nameLong, productAppName: product.nameLong,
companyName: 'Microsoft Corporation', companyName: 'Microsoft Corporation',
copyright: 'Copyright (C) 2018 Microsoft. All rights reserved', copyright: 'Copyright (C) 2017 Microsoft. All rights reserved',
darwinIcon: 'resources/darwin/code.icns', darwinIcon: 'resources/darwin/code.icns',
darwinBundleIdentifier: product.darwinBundleIdentifier, darwinBundleIdentifier: product.darwinBundleIdentifier,
darwinApplicationCategoryType: 'public.app-category.developer-tools', darwinApplicationCategoryType: 'public.app-category.developer-tools',
@@ -167,7 +165,7 @@ const config = {
name: product.nameLong + ' document', name: product.nameLong + ' document',
role: 'Editor', role: 'Editor',
ostypes: ["TEXT", "utxt", "TUTX", "****"], ostypes: ["TEXT", "utxt", "TUTX", "****"],
// {{SQL CARBON EDIT}} // {{SQL CARBON EDIT}}
extensions: ["csv", "json", "sqlplan", "sql", "xml"], extensions: ["csv", "json", "sqlplan", "sql", "xml"],
iconFile: 'resources/darwin/code_file.icns' iconFile: 'resources/darwin/code_file.icns'
}], }],
@@ -318,8 +316,10 @@ function packageTask(platform, arch, opts) {
// {{SQL CARBON EDIT}} // {{SQL CARBON EDIT}}
const dataApi = gulp.src('src/vs/data.d.ts').pipe(rename('out/sql/data.d.ts')); const dataApi = gulp.src('src/vs/data.d.ts').pipe(rename('out/sql/data.d.ts'));
const depsSrc = _.flatten(dependencies const depsSrc = [
.map(function (d) { return ['node_modules/' + d + '/**', '!node_modules/' + d + '/**/{test,tests}/**']; })); ..._.flatten(productionDependencies.map(d => path.relative(root, d.path)).map(d => [`${d}/**`, `!${d}/**/{test,tests}/**`])),
..._.flatten(Object.keys(product.dependencies || {}).map(d => [`node_modules/${d}/**`, `!node_modules/${d}/**/{test,tests}/**`]))
];
const deps = gulp.src(depsSrc, { base: '.', dot: true }) const deps = gulp.src(depsSrc, { base: '.', dot: true })
.pipe(filter(['**', '!**/package-lock.json'])) .pipe(filter(['**', '!**/package-lock.json']))
@@ -328,11 +328,11 @@ function packageTask(platform, arch, opts) {
.pipe(util.cleanNodeModule('windows-mutex', ['binding.gyp', 'build/**', 'src/**'], ['**/*.node'])) .pipe(util.cleanNodeModule('windows-mutex', ['binding.gyp', 'build/**', 'src/**'], ['**/*.node']))
.pipe(util.cleanNodeModule('native-keymap', ['binding.gyp', 'build/**', 'src/**', 'deps/**'], ['**/*.node'])) .pipe(util.cleanNodeModule('native-keymap', ['binding.gyp', 'build/**', 'src/**', 'deps/**'], ['**/*.node']))
.pipe(util.cleanNodeModule('native-watchdog', ['binding.gyp', 'build/**', 'src/**'], ['**/*.node'])) .pipe(util.cleanNodeModule('native-watchdog', ['binding.gyp', 'build/**', 'src/**'], ['**/*.node']))
.pipe(util.cleanNodeModule('spdlog', ['binding.gyp', 'build/**', 'deps/**', 'src/**', 'test/**'], ['**/*.node']))
.pipe(util.cleanNodeModule('jschardet', ['dist/**'])) .pipe(util.cleanNodeModule('jschardet', ['dist/**']))
.pipe(util.cleanNodeModule('windows-foreground-love', ['binding.gyp', 'build/**', 'src/**'], ['**/*.node'])) .pipe(util.cleanNodeModule('windows-foreground-love', ['binding.gyp', 'build/**', 'src/**'], ['**/*.node']))
.pipe(util.cleanNodeModule('windows-process-tree', ['binding.gyp', 'build/**', 'src/**'], ['**/*.node'])) .pipe(util.cleanNodeModule('windows-process-tree', ['binding.gyp', 'build/**', 'src/**'], ['**/*.node']))
.pipe(util.cleanNodeModule('gc-signals', ['binding.gyp', 'build/**', 'src/**', 'deps/**'], ['**/*.node', 'src/index.js'])) .pipe(util.cleanNodeModule('gc-signals', ['binding.gyp', 'build/**', 'src/**', 'deps/**'], ['**/*.node', 'src/index.js']))
.pipe(util.cleanNodeModule('v8-profiler', ['binding.gyp', 'build/**', 'src/**', 'deps/**'], ['**/*.node', 'src/index.js']))
.pipe(util.cleanNodeModule('keytar', ['binding.gyp', 'build/**', 'src/**', 'script/**', 'node_modules/**'], ['**/*.node'])) .pipe(util.cleanNodeModule('keytar', ['binding.gyp', 'build/**', 'src/**', 'script/**', 'node_modules/**'], ['**/*.node']))
.pipe(util.cleanNodeModule('node-pty', ['binding.gyp', 'build/**', 'src/**', 'tools/**'], ['build/Release/**'])) .pipe(util.cleanNodeModule('node-pty', ['binding.gyp', 'build/**', 'src/**', 'tools/**'], ['build/Release/**']))
.pipe(util.cleanNodeModule('nsfw', ['binding.gyp', 'build/**', 'src/**', 'openpa/**', 'includes/**'], ['**/*.node', '**/*.a'])) .pipe(util.cleanNodeModule('nsfw', ['binding.gyp', 'build/**', 'src/**', 'openpa/**', 'includes/**'], ['**/*.node', '**/*.a']))
@@ -487,7 +487,7 @@ gulp.task('upload-vscode-sourcemaps', ['minify-vscode'], () => {
const allConfigDetailsPath = path.join(os.tmpdir(), 'configuration.json'); const allConfigDetailsPath = path.join(os.tmpdir(), 'configuration.json');
gulp.task('upload-vscode-configuration', ['generate-vscode-configuration'], () => { gulp.task('upload-vscode-configuration', ['generate-vscode-configuration'], () => {
const branch = process.env.BUILD_SOURCEBRANCH; const branch = process.env.BUILD_SOURCEBRANCH;
if (!branch.endsWith('/master') && !branch.indexOf('/release/') >= 0) { if (!branch.endsWith('/master') && branch.indexOf('/release/') < 0) {
console.log(`Only runs on master and release branches, not ${branch}`); console.log(`Only runs on master and release branches, not ${branch}`);
return; return;
} }

28
build/lib/electron.js Normal file
View File

@@ -0,0 +1,28 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the Source EULA. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
'use strict';
const fs = require('fs');
const path = require('path');
const root = path.dirname(path.dirname(__dirname));
function getElectronVersion() {
const yarnrc = fs.readFileSync(path.join(root, '.yarnrc'), 'utf8');
const target = /^target "(.*)"$/m.exec(yarnrc)[1];
return target;
}
module.exports.getElectronVersion = getElectronVersion;
// returns 0 if the right version of electron is in .build/electron
if (require.main === module) {
const version = getElectronVersion();
const versionFile = path.join(root, '.build', 'electron', 'version');
const isUpToDate = fs.existsSync(versionFile) && fs.readFileSync(versionFile, 'utf8') === `v${version}`;
process.exit(isUpToDate ? 0 : 1);
}

View File

@@ -20,7 +20,7 @@ var vsce = require("vsce");
var File = require("vinyl"); var File = require("vinyl");
function fromLocal(extensionPath) { function fromLocal(extensionPath) {
var result = es.through(); var result = es.through();
vsce.listFiles({ cwd: extensionPath }) vsce.listFiles({ cwd: extensionPath, packageManager: vsce.PackageManager.Yarn })
.then(function (fileNames) { .then(function (fileNames) {
var files = fileNames var files = fileNames
.map(function (fileName) { return path.join(extensionPath, fileName); }) .map(function (fileName) { return path.join(extensionPath, fileName); })

View File

@@ -22,7 +22,7 @@ import * as File from 'vinyl';
export function fromLocal(extensionPath: string): Stream { export function fromLocal(extensionPath: string): Stream {
const result = es.through(); const result = es.through();
vsce.listFiles({ cwd: extensionPath }) vsce.listFiles({ cwd: extensionPath, packageManager: vsce.PackageManager.Yarn })
.then(fileNames => { .then(fileNames => {
const files = fileNames const files = fileNames
.map(fileName => path.join(extensionPath, fileName)) .map(fileName => path.join(extensionPath, fileName))

View File

@@ -141,7 +141,7 @@ var XLF = /** @class */ (function () {
}; };
XLF.prototype.addStringItem = function (item) { XLF.prototype.addStringItem = function (item) {
if (!item.id || !item.message) { if (!item.id || !item.message) {
throw new Error('No item ID or value specified.'); throw new Error("No item ID or value specified: " + JSON.stringify(item));
} }
this.appendNewLine("<trans-unit id=\"" + item.id + "\">", 4); this.appendNewLine("<trans-unit id=\"" + item.id + "\">", 4);
this.appendNewLine("<source xml:lang=\"en\">" + item.message + "</source>", 6); this.appendNewLine("<source xml:lang=\"en\">" + item.message + "</source>", 6);

View File

@@ -192,7 +192,7 @@ export class XLF {
private addStringItem(item: Item): void { private addStringItem(item: Item): void {
if (!item.id || !item.message) { if (!item.id || !item.message) {
throw new Error('No item ID or value specified.'); throw new Error(`No item ID or value specified: ${JSON.stringify(item)}`);
} }
this.appendNewLine(`<trans-unit id="${item.id}">`, 4); this.appendNewLine(`<trans-unit id="${item.id}">`, 4);

View File

@@ -212,8 +212,7 @@ function uglifyWithCopyrights() {
return stream.pipe(minify({ return stream.pipe(minify({
output: { output: {
comments: preserveComments(f), comments: preserveComments(f),
// linux tfs build agent is crashing, does this help?§ max_line_len: 1024
max_line_len: 3200000
} }
})); }));
})); }));

View File

@@ -287,8 +287,7 @@ function uglifyWithCopyrights(): NodeJS.ReadWriteStream {
return stream.pipe(minify({ return stream.pipe(minify({
output: { output: {
comments: preserveComments(<FileWithCopyright>f), comments: preserveComments(<FileWithCopyright>f),
// linux tfs build agent is crashing, does this help?§ max_line_len: 1024
max_line_len: 3200000
} }
})); }));
})); }));

View File

@@ -88,10 +88,11 @@ var NoUnexternalizedStringsRuleWalker = /** @class */ (function (_super) {
var info = this.findDescribingParent(node); var info = this.findDescribingParent(node);
// Ignore strings in import and export nodes. // Ignore strings in import and export nodes.
if (info && info.isImport && doubleQuoted) { if (info && info.isImport && doubleQuoted) {
this.addFailureAtNode(node, NoUnexternalizedStringsRuleWalker.ImportFailureMessage, new Lint.Fix(NoUnexternalizedStringsRuleWalker.ImportFailureMessage, [ var fix = [
this.createReplacement(node.getStart(), 1, '\''), Lint.Replacement.replaceFromTo(node.getStart(), 1, '\''),
this.createReplacement(node.getStart() + text.length - 1, 1, '\''), Lint.Replacement.replaceFromTo(node.getStart() + text.length - 1, 1, '\''),
])); ];
this.addFailureAtNode(node, NoUnexternalizedStringsRuleWalker.ImportFailureMessage, fix);
return; return;
} }
var callInfo = info ? info.callInfo : null; var callInfo = info ? info.callInfo : null;
@@ -101,8 +102,9 @@ var NoUnexternalizedStringsRuleWalker = /** @class */ (function (_super) {
} }
if (doubleQuoted && (!callInfo || callInfo.argIndex === -1 || !this.signatures[functionName])) { if (doubleQuoted && (!callInfo || callInfo.argIndex === -1 || !this.signatures[functionName])) {
var s = node.getText(); var s = node.getText();
var replacement = new Lint.Replacement(node.getStart(), node.getWidth(), "nls.localize('KEY-" + s.substring(1, s.length - 1) + "', " + s + ")"); var fix = [
var fix = new Lint.Fix('Unexternalitzed string', [replacement]); Lint.Replacement.replaceFromTo(node.getStart(), node.getWidth(), "nls.localize('KEY-" + s.substring(1, s.length - 1) + "', " + s + ")"),
];
this.addFailure(this.createFailure(node.getStart(), node.getWidth(), "Unexternalized string found: " + node.getText(), fix)); this.addFailure(this.createFailure(node.getStart(), node.getWidth(), "Unexternalized string found: " + node.getText(), fix));
return; return;
} }
@@ -134,16 +136,24 @@ var NoUnexternalizedStringsRuleWalker = /** @class */ (function (_super) {
} }
} }
} }
var messageArg = callInfo.argIndex === this.messageIndex var messageArg = callInfo.callExpression.arguments[this.messageIndex];
? callInfo.callExpression.arguments[this.messageIndex] if (messageArg && messageArg.kind !== ts.SyntaxKind.StringLiteral) {
: null;
if (messageArg && messageArg !== node) {
this.addFailure(this.createFailure(messageArg.getStart(), messageArg.getWidth(), "Message argument to '" + callInfo.callExpression.expression.getText() + "' must be a string literal.")); this.addFailure(this.createFailure(messageArg.getStart(), messageArg.getWidth(), "Message argument to '" + callInfo.callExpression.expression.getText() + "' must be a string literal."));
return; return;
} }
}; };
NoUnexternalizedStringsRuleWalker.prototype.recordKey = function (keyNode, messageNode) { NoUnexternalizedStringsRuleWalker.prototype.recordKey = function (keyNode, messageNode) {
var text = keyNode.getText(); var text = keyNode.getText();
// We have an empty key
if (text.match(/(['"]) *\1/)) {
if (messageNode) {
this.addFailureAtNode(keyNode, "Key is empty for message: " + messageNode.getText());
}
else {
this.addFailureAtNode(keyNode, "Key is empty.");
}
return;
}
var occurrences = this.usedKeys[text]; var occurrences = this.usedKeys[text];
if (!occurrences) { if (!occurrences) {
occurrences = []; occurrences = [];
@@ -176,7 +186,7 @@ var NoUnexternalizedStringsRuleWalker = /** @class */ (function (_super) {
node = parent; node = parent;
} }
}; };
NoUnexternalizedStringsRuleWalker.ImportFailureMessage = 'Do not use double qoutes for imports.'; NoUnexternalizedStringsRuleWalker.ImportFailureMessage = 'Do not use double quotes for imports.';
NoUnexternalizedStringsRuleWalker.DOUBLE_QUOTE = '"'; NoUnexternalizedStringsRuleWalker.DOUBLE_QUOTE = '"';
return NoUnexternalizedStringsRuleWalker; return NoUnexternalizedStringsRuleWalker;
}(Lint.RuleWalker)); }(Lint.RuleWalker));

View File

@@ -45,7 +45,7 @@ interface KeyMessagePair {
class NoUnexternalizedStringsRuleWalker extends Lint.RuleWalker { class NoUnexternalizedStringsRuleWalker extends Lint.RuleWalker {
private static ImportFailureMessage = 'Do not use double qoutes for imports.'; private static ImportFailureMessage = 'Do not use double quotes for imports.';
private static DOUBLE_QUOTE: string = '"'; private static DOUBLE_QUOTE: string = '"';
@@ -104,13 +104,14 @@ class NoUnexternalizedStringsRuleWalker extends Lint.RuleWalker {
let info = this.findDescribingParent(node); let info = this.findDescribingParent(node);
// Ignore strings in import and export nodes. // Ignore strings in import and export nodes.
if (info && info.isImport && doubleQuoted) { if (info && info.isImport && doubleQuoted) {
const fix = [
Lint.Replacement.replaceFromTo(node.getStart(), 1, '\''),
Lint.Replacement.replaceFromTo(node.getStart() + text.length - 1, 1, '\''),
];
this.addFailureAtNode( this.addFailureAtNode(
node, node,
NoUnexternalizedStringsRuleWalker.ImportFailureMessage, NoUnexternalizedStringsRuleWalker.ImportFailureMessage,
new Lint.Fix(NoUnexternalizedStringsRuleWalker.ImportFailureMessage, [ fix
this.createReplacement(node.getStart(), 1, '\''),
this.createReplacement(node.getStart() + text.length - 1, 1, '\''),
])
); );
return; return;
} }
@@ -122,8 +123,9 @@ class NoUnexternalizedStringsRuleWalker extends Lint.RuleWalker {
if (doubleQuoted && (!callInfo || callInfo.argIndex === -1 || !this.signatures[functionName])) { if (doubleQuoted && (!callInfo || callInfo.argIndex === -1 || !this.signatures[functionName])) {
const s = node.getText(); const s = node.getText();
const replacement = new Lint.Replacement(node.getStart(), node.getWidth(), `nls.localize('KEY-${s.substring(1, s.length - 1)}', ${s})`); const fix = [
const fix = new Lint.Fix('Unexternalitzed string', [replacement]); Lint.Replacement.replaceFromTo(node.getStart(), node.getWidth(), `nls.localize('KEY-${s.substring(1, s.length - 1)}', ${s})`),
];
this.addFailure(this.createFailure(node.getStart(), node.getWidth(), `Unexternalized string found: ${node.getText()}`, fix)); this.addFailure(this.createFailure(node.getStart(), node.getWidth(), `Unexternalized string found: ${node.getText()}`, fix));
return; return;
} }
@@ -154,10 +156,10 @@ class NoUnexternalizedStringsRuleWalker extends Lint.RuleWalker {
} }
} }
} }
let messageArg: ts.Expression = callInfo.argIndex === this.messageIndex
? callInfo.callExpression.arguments[this.messageIndex] const messageArg = callInfo.callExpression.arguments[this.messageIndex];
: null;
if (messageArg && messageArg !== node) { if (messageArg && messageArg.kind !== ts.SyntaxKind.StringLiteral) {
this.addFailure(this.createFailure( this.addFailure(this.createFailure(
messageArg.getStart(), messageArg.getWidth(), messageArg.getStart(), messageArg.getWidth(),
`Message argument to '${callInfo.callExpression.expression.getText()}' must be a string literal.`)); `Message argument to '${callInfo.callExpression.expression.getText()}' must be a string literal.`));
@@ -167,6 +169,15 @@ class NoUnexternalizedStringsRuleWalker extends Lint.RuleWalker {
private recordKey(keyNode: ts.StringLiteral, messageNode: ts.Node) { private recordKey(keyNode: ts.StringLiteral, messageNode: ts.Node) {
let text = keyNode.getText(); let text = keyNode.getText();
// We have an empty key
if (text.match(/(['"]) *\1/)) {
if (messageNode) {
this.addFailureAtNode(keyNode, `Key is empty for message: ${messageNode.getText()}`);
} else {
this.addFailureAtNode(keyNode, `Key is empty.`);
}
return;
}
let occurrences: KeyMessagePair[] = this.usedKeys[text]; let occurrences: KeyMessagePair[] = this.usedKeys[text];
if (!occurrences) { if (!occurrences) {
occurrences = []; occurrences = [];

1
build/lib/watch/.gitignore vendored Normal file
View File

@@ -0,0 +1 @@
.yarnrc

1302
build/lib/watch/yarn.lock Normal file

File diff suppressed because it is too large Load Diff

1
build/monaco/LICENSE Normal file
View File

@@ -0,0 +1 @@
See project root directory

View File

@@ -52,7 +52,7 @@ declare module monaco.editor {
#include(vs/editor/standalone/common/standaloneThemeService): BuiltinTheme, IStandaloneThemeData, IColors #include(vs/editor/standalone/common/standaloneThemeService): BuiltinTheme, IStandaloneThemeData, IColors
#include(vs/editor/common/modes/supports/tokenization): ITokenThemeRule #include(vs/editor/common/modes/supports/tokenization): ITokenThemeRule
#include(vs/editor/common/services/webWorker): MonacoWebWorker, IWebWorkerOptions #include(vs/editor/common/services/webWorker): MonacoWebWorker, IWebWorkerOptions
#include(vs/editor/standalone/browser/standaloneCodeEditor): IEditorConstructionOptions, IDiffEditorConstructionOptions, IStandaloneCodeEditor, IStandaloneDiffEditor #include(vs/editor/standalone/browser/standaloneCodeEditor): IActionDescriptor, IEditorConstructionOptions, IDiffEditorConstructionOptions, IStandaloneCodeEditor, IStandaloneDiffEditor
export interface ICommandHandler { export interface ICommandHandler {
(...args:any[]): void; (...args:any[]): void;
} }
@@ -74,7 +74,7 @@ declare module monaco.languages {
#includeAll(vs/editor/standalone/browser/standaloneLanguages;modes.=>;editorCommon.=>editor.;IMarkerData=>editor.IMarkerData): #includeAll(vs/editor/standalone/browser/standaloneLanguages;modes.=>;editorCommon.=>editor.;IMarkerData=>editor.IMarkerData):
#includeAll(vs/editor/common/modes/languageConfiguration): #includeAll(vs/editor/common/modes/languageConfiguration):
#includeAll(vs/editor/common/modes;editorCommon.IRange=>IRange;editorCommon.IPosition=>IPosition;editorCommon.=>editor.): #includeAll(vs/editor/common/modes;editorCommon.IRange=>IRange;editorCommon.IPosition=>IPosition;editorCommon.=>editor.;IMarkerData=>editor.IMarkerData):
#include(vs/editor/common/services/modeService): ILanguageExtensionPoint #include(vs/editor/common/services/modeService): ILanguageExtensionPoint
#includeAll(vs/editor/standalone/common/monarch/monarchTypes): #includeAll(vs/editor/standalone/common/monarch/monarchTypes):

View File

@@ -11,47 +11,5 @@
}, },
"bugs": { "bugs": {
"url": "https://github.com/Microsoft/vscode/issues" "url": "https://github.com/Microsoft/vscode/issues"
},
"devDependencies": {
"@types/minimist": "1.2.0",
"@types/mocha": "2.2.39",
"@types/semver": "5.3.30",
"@types/sinon": "1.16.34",
"debounce": "^1.0.0",
"eslint": "^3.4.0",
"event-stream": "^3.1.7",
"ghooks": "1.0.3",
"glob": "^5.0.13",
"gulp": "^3.8.9",
"gulp-bom": "^1.0.0",
"gulp-concat": "^2.6.0",
"gulp-cssnano": "^2.1.0",
"gulp-filter": "^3.0.0",
"gulp-flatmap": "^1.0.0",
"gulp-rename": "^1.2.0",
"gulp-sourcemaps": "^1.11.0",
"gulp-tsb": "^2.0.3",
"gulp-tslint": "^7.0.1",
"gulp-uglify": "^2.0.0",
"gulp-util": "^3.0.6",
"gulp-watch": "^4.3.9",
"is": "^3.1.0",
"istanbul": "^0.3.17",
"jsdom-no-contextify": "^3.1.0",
"lazy.js": "^0.4.2",
"minimatch": "^2.0.10",
"mocha": "^2.2.5",
"object-assign": "^4.0.1",
"pump": "^1.0.1",
"remap-istanbul": "^0.6.4",
"rimraf": "^2.2.8",
"sinon": "^1.17.2",
"source-map": "^0.4.4",
"tslint": "^4.3.1",
"typescript": "2.5.2",
"typescript-formatter": "4.0.1",
"underscore": "^1.8.2",
"vinyl": "^0.4.5",
"vscode-nls-dev": "^2.0.1"
} }
} }

4668
build/monaco/yarn.lock Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -5,14 +5,15 @@
const cp = require('child_process'); const cp = require('child_process');
const path = require('path'); const path = require('path');
const npm = process.platform === 'win32' ? 'npm.cmd' : 'npm'; const fs = require('fs');
const yarn = process.platform === 'win32' ? 'yarn.cmd' : 'yarn';
function npmInstall(location, opts) { function yarnInstall(location, opts) {
opts = opts || {}; opts = opts || {};
opts.cwd = location; opts.cwd = location;
opts.stdio = 'inherit'; opts.stdio = 'inherit';
const result = cp.spawnSync(npm, ['install'], opts); const result = cp.spawnSync(yarn, ['install'], opts);
if (result.error || result.status !== 0) { if (result.error || result.status !== 0) {
process.exit(1); process.exit(1);
@@ -20,36 +21,46 @@ function npmInstall(location, opts) {
} }
// {{SQL CARBON EDIT}} // {{SQL CARBON EDIT}}
npmInstall('dataprotocol-client'); yarnInstall('dataprotocol-client');
npmInstall('extensions-modules'); yarnInstall('extensions-modules');
npmInstall('extensions'); // node modules shared by all extensions yarnInstall('extensions'); // node modules shared by all extensions
yarnInstall('extensions'); // node modules shared by all extensions
const extensions = [ const extensions = [
'vscode-colorize-tests', 'vscode-colorize-tests',
'git',
'json', 'json',
'mssql', 'mssql',
'configuration-editing', 'configuration-editing',
'extension-editing', 'extension-editing',
'markdown', 'markdown',
'git',
'merge-conflict', 'merge-conflict',
'insights-default', 'insights-default',
'account-provider-azure' 'account-provider-azure'
]; ];
extensions.forEach(extension => npmInstall(`extensions/${extension}`)); extensions.forEach(extension => yarnInstall(`extensions/${extension}`));
function npmInstallBuildDependencies() { function yarnInstallBuildDependencies() {
// make sure we install gulp watch for the system installed // make sure we install the deps of build/lib/watch for the system installed
// node, since that is the driver of gulp // node, since that is the driver of gulp
const env = Object.assign({}, process.env); const env = Object.assign({}, process.env);
const watchPath = path.join(path.dirname(__dirname), 'lib', 'watch');
const yarnrcPath = path.join(watchPath, '.yarnrc');
delete env['npm_config_disturl']; const disturl = 'https://nodejs.org/download/release';
delete env['npm_config_target']; const target = process.versions.node;
delete env['npm_config_runtime']; const runtime = 'node';
npmInstall(path.join(path.dirname(__dirname), 'lib', 'watch'), { env }); const yarnrc = `disturl "${disturl}"
target "${target}"
runtime "${runtime}"`;
fs.writeFileSync(yarnrcPath, yarnrc, 'utf8');
yarnInstall(watchPath, { env });
} }
npmInstall(`build`); // node modules required for build yarnInstall(`build`); // node modules required for build
npmInstallBuildDependencies(); // node modules for watching, specific to host node version, not electron yarnInstallBuildDependencies(); // node modules for watching, specific to host node version, not electron

View File

@@ -3,13 +3,21 @@
* Licensed under the Source EULA. See License.txt in the project root for license information. * Licensed under the Source EULA. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/ *--------------------------------------------------------------------------------------------*/
if (process.env['npm_config_disturl'] !== 'https://atom.io/download/electron') { let err = false;
console.error("You can't use plain npm to install Code's dependencies.");
console.error(
/^win/.test(process.platform)
? "Please run '.\\scripts\\npm.bat install' instead."
: "Please run './scripts/npm.sh install' instead."
);
const major = parseInt(/^(\d+)\./.exec(process.versions.node)[1]);
if (major < 8) {
console.error('\033[1;31m*** Please use node>=8.\033[0;0m');
err = true;
}
if (!/yarn\.js$|yarnpkg$/.test(process.env['npm_execpath'])) {
console.error('\033[1;31m*** Please use yarn to install dependencies.\033[0;0m');
err = true;
}
if (err) {
console.error('');
process.exit(1); process.exit(1);
} }

View File

@@ -18,7 +18,7 @@ function updateGrammar(location) {
} }
const extensions = [ const extensions = [
// 'bat' Grammar no longer available 'bat',
'clojure', 'clojure',
'coffeescript', 'coffeescript',
'cpp', 'cpp',

View File

@@ -11,13 +11,13 @@
"@types/xml2js": "0.0.33", "@types/xml2js": "0.0.33",
"azure-storage": "^2.1.0", "azure-storage": "^2.1.0",
"decompress": "^4.2.0", "decompress": "^4.2.0",
"documentdb": "^1.11.0", "documentdb": "1.13.0",
"extensions-modules": "file:../extensions-modules", "extensions-modules": "file:../extensions-modules",
"fs-extra-promise": "^1.0.1", "fs-extra-promise": "^1.0.1",
"mime": "^1.3.4", "mime": "^1.3.4",
"minimist": "^1.2.0", "minimist": "^1.2.0",
"typescript": "2.5.2", "typescript": "2.6.1",
"vscode": "^1.0.1", "vscode": "^1.0.1",
"xml2js": "^0.4.17" "xml2js": "^0.4.17"
}, },
"scripts": { "scripts": {
@@ -25,4 +25,4 @@
"watch": "tsc --watch", "watch": "tsc --watch",
"postinstall": "npm run compile" "postinstall": "npm run compile"
} }
} }

View File

@@ -6,6 +6,9 @@ if [ -n "$AGENT_WORKFOLDER" ]
then then
export npm_config_cache="$AGENT_WORKFOLDER/npm-cache" export npm_config_cache="$AGENT_WORKFOLDER/npm-cache"
echo "Using npm cache: $npm_config_cache" echo "Using npm cache: $npm_config_cache"
export YARN_CACHE_FOLDER="$AGENT_WORKFOLDER/yarn-cache"
echo "Using yarn cache: $YARN_CACHE_FOLDER"
fi fi
SUMMARY="Task;Duration"$'\n' SUMMARY="Task;Duration"$'\n'

View File

@@ -4,23 +4,15 @@
*--------------------------------------------------------------------------------------------*/ *--------------------------------------------------------------------------------------------*/
const cp = require('child_process'); const cp = require('child_process');
const npm = process.platform === 'win32' ? 'npm.cmd' : 'npm';
function npmInstall(package: string, args: string[]): void { function yarnInstall(package: string): void {
const result = cp.spawnSync(npm, ['install', package, ...args], { cp.execSync(`yarn add --no-lockfile ${package}`);
stdio: 'inherit'
});
if (result.error || result.status !== 0) {
process.exit(1);
}
} }
const product = require('../../../product.json'); const product = require('../../../product.json');
const dependencies = product.dependencies || {} as { [name: string]: string; }; const dependencies = product.dependencies || {} as { [name: string]: string; };
const [, , ...args] = process.argv;
Object.keys(dependencies).forEach(name => { Object.keys(dependencies).forEach(name => {
const url = dependencies[name]; const url = dependencies[name];
npmInstall(url, args); yarnInstall(url);
}); });

View File

@@ -10,6 +10,9 @@ else
fi fi
# install node # install node
NODE_VERSION=7.10.0 NODE_VERSION=8.9.1
nvm install $NODE_VERSION nvm install $NODE_VERSION
nvm use $NODE_VERSION nvm use $NODE_VERSION
# install yarn
npm i -g yarn

View File

@@ -14,8 +14,8 @@ import * as mime from 'mime';
import * as minimist from 'minimist'; import * as minimist from 'minimist';
import { DocumentClient, NewDocument } from 'documentdb'; import { DocumentClient, NewDocument } from 'documentdb';
if (process.argv.length < 9) { if (process.argv.length < 6) {
console.error('Usage: node publish.js <product_quality> <platform> <file_type> <file_name> <version> <is_update> <file> [commit_id]'); console.error('Usage: node publish.js <product> <platform> <type> <name> <version> <commit> <is_update> <file>');
process.exit(-1); process.exit(-1);
} }
@@ -183,9 +183,21 @@ async function publish(commit: string, quality: string, platform: string, type:
const blobService = azure.createBlobService(storageAccount, process.env['AZURE_STORAGE_ACCESS_KEY_2']) const blobService = azure.createBlobService(storageAccount, process.env['AZURE_STORAGE_ACCESS_KEY_2'])
.withFilter(new azure.ExponentialRetryPolicyFilter(20)); .withFilter(new azure.ExponentialRetryPolicyFilter(20));
await assertContainer(blobService, quality); const mooncakeBlobService = azure.createBlobService(storageAccount, process.env['MOONCAKE_STORAGE_ACCESS_KEY'], `${storageAccount}.blob.core.chinacloudapi.cn`)
.withFilter(new azure.ExponentialRetryPolicyFilter(20));
const blobExists = await doesAssetExist(blobService, quality, blobName); // mooncake is fussy and far away, this is needed!
mooncakeBlobService.defaultClientRequestTimeoutInMs = 10 * 60 * 1000;
await Promise.all([
assertContainer(blobService, quality),
assertContainer(mooncakeBlobService, quality)
]);
const [blobExists, moooncakeBlobExists] = await Promise.all([
doesAssetExist(blobService, quality, blobName),
doesAssetExist(mooncakeBlobService, quality, blobName)
]);
const promises = []; const promises = [];
@@ -193,22 +205,8 @@ async function publish(commit: string, quality: string, platform: string, type:
promises.push(uploadBlob(blobService, quality, blobName, file)); promises.push(uploadBlob(blobService, quality, blobName, file));
} }
if (process.env['MOONCAKE_STORAGE_ACCESS_KEY']) { if (!moooncakeBlobExists) {
const mooncakeBlobService = azure.createBlobService(storageAccount, process.env['MOONCAKE_STORAGE_ACCESS_KEY'], `${storageAccount}.blob.core.chinacloudapi.cn`) promises.push(uploadBlob(mooncakeBlobService, quality, blobName, file));
.withFilter(new azure.ExponentialRetryPolicyFilter(20));
// mooncake is fussy and far away, this is needed!
mooncakeBlobService.defaultClientRequestTimeoutInMs = 10 * 60 * 1000;
await assertContainer(mooncakeBlobService, quality);
const mooncakeBlobExists = await doesAssetExist(mooncakeBlobService, quality, blobName);
if (!mooncakeBlobExists) {
promises.push(uploadBlob(mooncakeBlobService, quality, blobName, file));
}
} else {
console.log('Skipping Mooncake publishing.');
} }
if (promises.length === 0) { if (promises.length === 0) {
@@ -230,7 +228,7 @@ async function publish(commit: string, quality: string, platform: string, type:
platform: platform, platform: platform,
type: type, type: type,
url: `${process.env['AZURE_CDN_URL']}/${quality}/${blobName}`, url: `${process.env['AZURE_CDN_URL']}/${quality}/${blobName}`,
mooncakeUrl: process.env['MOONCAKE_CDN_URL'] ? `${process.env['MOONCAKE_CDN_URL']}/${quality}/${blobName}` : undefined, mooncakeUrl: `${process.env['MOONCAKE_CDN_URL']}/${quality}/${blobName}`,
hash: sha1hash, hash: sha1hash,
sha256hash, sha256hash,
size size
@@ -263,10 +261,8 @@ function main(): void {
boolean: ['upload-only'] boolean: ['upload-only']
}); });
let [quality, platform, type, name, version, _isUpdate, file, commit] = opts._; const [quality, platform, type, name, version, _isUpdate, file] = opts._;
if (!commit) { const commit = execSync('git rev-parse HEAD', { encoding: 'utf8' }).trim();
commit = execSync('git rev-parse HEAD', { encoding: 'utf8' }).trim();
}
publish(commit, quality, platform, type, name, version, _isUpdate, file, opts).catch(err => { publish(commit, quality, platform, type, name, version, _isUpdate, file, opts).catch(err => {
console.error(err); console.error(err);

View File

@@ -14,7 +14,7 @@ VSO_PAT="$6"
echo "machine monacotools.visualstudio.com password $VSO_PAT" > ~/.netrc echo "machine monacotools.visualstudio.com password $VSO_PAT" > ~/.netrc
step "Install dependencies" \ step "Install dependencies" \
npm install yarn
step "Hygiene" \ step "Hygiene" \
npm run gulp -- hygiene npm run gulp -- hygiene

View File

@@ -3,10 +3,6 @@
. ./scripts/env.sh . ./scripts/env.sh
. ./build/tfs/common/common.sh . ./build/tfs/common/common.sh
(cd $BUILD_SOURCESDIRECTORY/build/tfs/common && \
step "Install build dependencies" \
npm i)
REPO=`pwd` REPO=`pwd`
ZIP=$REPO/../VSCode-darwin-selfsigned.zip ZIP=$REPO/../VSCode-darwin-selfsigned.zip
UNSIGNEDZIP=$REPO/../VSCode-darwin-unsigned.zip UNSIGNEDZIP=$REPO/../VSCode-darwin-unsigned.zip

View File

@@ -1 +1,2 @@
pat pat
*.js

View File

@@ -5,6 +5,7 @@
. ./build/tfs/common/common.sh . ./build/tfs/common/common.sh
export ARCH="$1" export ARCH="$1"
export npm_config_arch="$ARCH"
export VSCODE_MIXIN_PASSWORD="$2" export VSCODE_MIXIN_PASSWORD="$2"
export AZURE_STORAGE_ACCESS_KEY="$3" export AZURE_STORAGE_ACCESS_KEY="$3"
export AZURE_STORAGE_ACCESS_KEY_2="$4" export AZURE_STORAGE_ACCESS_KEY_2="$4"
@@ -16,7 +17,7 @@ VSO_PAT="$8"
echo "machine monacotools.visualstudio.com password $VSO_PAT" > ~/.netrc echo "machine monacotools.visualstudio.com password $VSO_PAT" > ~/.netrc
step "Install dependencies" \ step "Install dependencies" \
npm install --arch=$ARCH --unsafe-perm yarn
step "Hygiene" \ step "Hygiene" \
npm run gulp -- hygiene npm run gulp -- hygiene
@@ -28,7 +29,7 @@ step "Get Electron" \
npm run gulp -- "electron-$ARCH" npm run gulp -- "electron-$ARCH"
step "Install distro dependencies" \ step "Install distro dependencies" \
node build/tfs/common/installDistro.js --arch=$ARCH node build/tfs/common/installDistro.js
step "Build minified" \ step "Build minified" \
npm run gulp -- "vscode-linux-$ARCH-min" npm run gulp -- "vscode-linux-$ARCH-min"

View File

@@ -0,0 +1,42 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the Source EULA. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
'use strict';
import { DocumentClient } from 'documentdb';
interface Config {
id: string;
frozen: boolean;
}
function createDefaultConfig(quality: string): Config {
return {
id: quality,
frozen: false
};
}
function getConfig(quality: string): Promise<Config> {
const client = new DocumentClient(process.env['AZURE_DOCUMENTDB_ENDPOINT'], { masterKey: process.env['AZURE_DOCUMENTDB_MASTERKEY'] });
const collection = 'dbs/builds/colls/config';
const query = {
query: `SELECT TOP 1 * FROM c WHERE c.id = @quality`,
parameters: [
{ name: '@quality', value: quality }
]
};
return new Promise<Config>((c, e) => {
client.queryDocuments(collection, query).toArray((err, results) => {
if (err && err.code !== 409) { return e(err); }
c(!results || results.length === 0 ? createDefaultConfig(quality) : results[0] as any as Config);
});
});
}
getConfig(process.argv[2])
.then(c => console.log(c.frozen), e => console.error(e));

View File

@@ -0,0 +1,6 @@
{
"name": "PACKAGENAME",
"version": "PACKAGEVERSION",
"repositoryId": "REPOSITORYID",
"sourceUrl": "PACKAGEURL"
}

View File

@@ -12,10 +12,6 @@ step "Build RPM package" \
# step "Build snap package" \ # step "Build snap package" \
# npm run gulp -- "vscode-linux-$ARCH-build-snap" # npm run gulp -- "vscode-linux-$ARCH-build-snap"
(cd $BUILD_SOURCESDIRECTORY/build/tfs/common && \
step "Install build dependencies" \
npm install --unsafe-perm)
# Variables # Variables
PLATFORM_LINUX="linux-$ARCH" PLATFORM_LINUX="linux-$ARCH"
PLATFORM_DEB="linux-deb-$ARCH" PLATFORM_DEB="linux-deb-$ARCH"
@@ -55,36 +51,29 @@ step "Publish RPM package" \
# SNAP_FILENAME="$(ls $REPO/.build/linux/snap/$ARCH/ | grep .snap)" # SNAP_FILENAME="$(ls $REPO/.build/linux/snap/$ARCH/ | grep .snap)"
# SNAP_PATH="$REPO/.build/linux/snap/$ARCH/$SNAP_FILENAME" # SNAP_PATH="$REPO/.build/linux/snap/$ARCH/$SNAP_FILENAME"
IS_FROZEN="$(node build/tfs/linux/frozen-check.js $VSCODE_QUALITY)"
if [ -z "$VSCODE_QUALITY" ]; then if [ -z "$VSCODE_QUALITY" ]; then
echo "VSCODE_QUALITY is not set, skipping repo package publish" echo "VSCODE_QUALITY is not set, skipping repo package publish"
elif [ "$IS_FROZEN" = "true" ]; then
echo "$VSCODE_QUALITY is frozen, skipping repo package publish"
else else
if [ "$BUILD_SOURCEBRANCH" = "master" ] || [ "$BUILD_SOURCEBRANCH" = "refs/heads/master" ]; then if [ "$BUILD_SOURCEBRANCH" = "master" ] || [ "$BUILD_SOURCEBRANCH" = "refs/heads/master" ]; then
if [[ $BUILD_QUEUEDBY = *"Project Collection Service Accounts"* || $BUILD_QUEUEDBY = *"Microsoft.VisualStudio.Services.TFS"* ]]; then if [[ $BUILD_QUEUEDBY = *"Project Collection Service Accounts"* || $BUILD_QUEUEDBY = *"Microsoft.VisualStudio.Services.TFS"* ]]; then
# Get necessary information
pushd $REPO && COMMIT_HASH=$(git rev-parse HEAD) && popd
PACKAGE_NAME="$(ls $REPO/.build/linux/deb/$DEB_ARCH/deb/ | sed -e 's/_.*//g')"
DEB_URL="https://az764295.vo.msecnd.net/$VSCODE_QUALITY/$COMMIT_HASH/$DEB_FILENAME"
RPM_URL="https://az764295.vo.msecnd.net/$VSCODE_QUALITY/$COMMIT_HASH/$RPM_FILENAME"
PACKAGE_VERSION="$(ls $REPO/.build/linux/deb/$DEB_ARCH/deb/ | sed -e 's/code-[a-z]*_//g' -e 's/\_.*$//g')"
# Write config files needed by API, use eval to force environment variable expansion # Write config files needed by API, use eval to force environment variable expansion
DIRNAME=$(dirname $(readlink -f $0)) DIRNAME=$(dirname $(readlink -f $0))
pushd $DIRNAME pushd $DIRNAME
# Submit to apt repo # Submit to apt repo
if [ "$DEB_ARCH" = "amd64" ]; then if [ "$DEB_ARCH" = "amd64" ]; then
eval echo '{ \"server\": \"azure-apt-cat.cloudapp.net\", \"protocol\": \"https\", \"port\": \"443\", \"repositoryId\": \"58a4adf642421134a1a48d1a\", \"username\": \"$LINUX_REPO_USERNAME\", \"password\": \"$LINUX_REPO_PASSWORD\" }' > apt-config.json eval echo '{ \"server\": \"azure-apt-cat.cloudapp.net\", \"protocol\": \"https\", \"port\": \"443\", \"repositoryId\": \"58a4adf642421134a1a48d1a\", \"username\": \"$LINUX_REPO_USERNAME\", \"password\": \"$LINUX_REPO_PASSWORD\" }' > apt-config.json
eval echo '{ \"name\": \"$PACKAGE_NAME\", \"version\": \"$PACKAGE_VERSION\", \"repositoryId\": \"58a4adf642421134a1a48d1a\", \"sourceUrl\": \"$DEB_URL\" }' > apt-addpkg.json
echo "Submitting apt-addpkg.json:"
cat apt-addpkg.json
step "Publish to repositories" \ step "Publish to repositories" \
./repoapi_client.sh -config apt-config.json -addpkg apt-addpkg.json ./repoapi_client.sh -config apt-config.json -addfile $DEB_PATH
fi fi
# Submit to yum repo (disabled as it's manual until signing is automated) # Submit to yum repo (disabled as it's manual until signing is automated)
# eval echo '{ \"server\": \"azure-apt-cat.cloudapp.net\", \"protocol\": \"https\", \"port\": \"443\", \"repositoryId\": \"58a4ae3542421134a1a48d1b\", \"username\": \"$LINUX_REPO_USERNAME\", \"password\": \"$LINUX_REPO_PASSWORD\" }' > yum-config.json # eval echo '{ \"server\": \"azure-apt-cat.cloudapp.net\", \"protocol\": \"https\", \"port\": \"443\", \"repositoryId\": \"58a4ae3542421134a1a48d1b\", \"username\": \"$LINUX_REPO_USERNAME\", \"password\": \"$LINUX_REPO_PASSWORD\" }' > yum-config.json
# eval echo '{ \"name\": \"$PACKAGE_NAME\", \"version\": \"$PACKAGE_VERSION\", \"repositoryId\": \"58a4ae3542421134a1a48d1b\", \"sourceUrl\": \"$RPM_URL\" }' > yum-addpkg.json
# echo "Submitting yum-addpkg.json:" # ./repoapi_client.sh -config yum-config.json -addfile $RPM_PATH
# cat yum-addpkg.json
# ./repoapi_client.sh -config yum-config.json -addpkg yum-addpkg.json
popd popd
echo "To check repo publish status run ./repoapi_client.sh -config config.json -check <id>" echo "To check repo publish status run ./repoapi_client.sh -config config.json -check <id>"
fi fi

View File

@@ -2,9 +2,9 @@
# This is a VERY basic script for Create/Delete operations on repos and packages # This is a VERY basic script for Create/Delete operations on repos and packages
# #
cmd=$1 cmd=$1
urls=urls.txt docDir="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" # chrmarti: Changed to script's directory.
defaultPackageFile=new_package.json packageJsonTemplate=$docDir/new_package.json.template
defaultRepoFile=new_repo.json repoJsonTemplate=$docDir/new_repo.json.template
function Bail function Bail
{ {
@@ -24,14 +24,21 @@ function Usage {
echo "$0 -config FILENAME -listrepos | -listpkgs | -addrepo FILENAME | -addpkg FILENAME |" echo "$0 -config FILENAME -listrepos | -listpkgs | -addrepo FILENAME | -addpkg FILENAME |"
echo "-addpkgs FILENAME | -check ID | -delrepo REPOID | -delpkg PKGID" echo "-addpkgs FILENAME | -check ID | -delrepo REPOID | -delpkg PKGID"
echo -e "\t-config FILENAME : JSON file containing API server name and creds" echo -e "\t-config FILENAME : JSON file containing API server name and creds"
echo -e "\t-listrepos : List repositories" echo -e "Package Operations:"
echo -e "\t-listpkgs [REGEX] : List packages, optionally filter by REGEX" echo -e "\t-listpkgs [REGEX] : List packages, optionally filter by REGEX"
echo -e "\t-addrepo FILENAME : Create a new repo using the specified JSON file"
echo -e "\t-addpkg FILENAME : Add package to repo using the specified JSON file" echo -e "\t-addpkg FILENAME : Add package to repo using the specified JSON file"
echo -e "\t-addpkgs FILENAME : Add packages to repo using urls contained in FILENAME" echo -e "\t-addpkgs FILENAME : Add packages to repo using urls contained in FILENAME"
echo -e "\t-check ID : Check upload operation by ID" echo -e "\t-check ID : Check upload operation by ID"
echo -e "\t-delrepo REPOID : Delete the specified repo by ID"
echo -e "\t-delpkg PKGID : Delete the specified package by ID" echo -e "\t-delpkg PKGID : Delete the specified package by ID"
echo -e "File Operations:"
echo -e "\t-uploadfile FILENAME: Upload FILENAME (does not publish) "
echo -e "\t-addfile FILENAME : Upload FILENAME AND publish to the repo"
echo -e "\t-listfiles : List uploaded files"
echo -e "\t-delfile FILEID : Delete uploaded file by ID"
echo -e "Repository Operations:"
echo -e "\t-listrepos : List repositories"
echo -e "\t-addrepo FILENAME : Create a new repo using the specified JSON file"
echo -e "\t-delrepo REPOID : Delete the specified repo by ID"
exit 1 exit 1
} }
@@ -84,33 +91,136 @@ function AddRepo
{ {
repoFile=$1 repoFile=$1
if [ -z $repoFile ]; then if [ -z $repoFile ]; then
Bail "Error: Must specify a JSON-formatted file. Reference $defaultRepoFile.template" Bail "Error: Must specify a JSON-formatted file. Reference $repoJsonTemplate"
fi fi
if [ ! -f $repoFile ]; then if [ ! -f $repoFile ]; then
Bail "Error: Cannot create repo - $repoFile does not exist" Bail "Error: Cannot create repo - $repoFile does not exist"
fi fi
packageUrl=$(grep "url" $repoFile | head -n 1 | awk '{print $2}' | tr -d ',') packageUrl=$(grep "url" $repoFile | head -n 1 | awk '{print $2}' | tr -d ',')
echo "Creating new repo on $server [$packageUrl]" echo "Creating new repo on $server [$packageUrl]"
curl -i -k "$baseurl/v1/repositories" --data @./$repoFile -H "Content-Type: application/json" curl -i -k "$baseurl/v1/repositories" --data @$repoFile -H "Content-Type: application/json"
echo "" echo ""
} }
# Upload AND publish the file
function AddFile
{
packageFile=$1
# Validity checks are performed by UploadFile
echo "Uploading package to $server [$packageFile]"
response=$(UploadFile $packageFile "true")
id=$(echo $response | jq -r ".id")
# Parse package metadata first to confirm it's a valid deb/rpm
# Needs to be performed in this function so we can use it to publish the package
jsonFile=$(WritePackageInfoToFile $packageFile)
sed -i "s/REPOSITORYID/$repositoryId/g" $jsonFile
# Replace the url field with fileId
sed -i "s/PACKAGEURL/$id/g" $jsonFile
sed -i "s/sourceUrl/fileId/g" $jsonFile
AddPackage $jsonFile
rm -f $jsonFile
echo ""
}
# Upload a file
function UploadFile
{
packageFile=$1
quick=$2
if [ -z $packageFile ]; then
Bail "Error: Must specify the path to a file to upload "
fi
if [ ! -f $packageFile ]; then
Bail "Error: Cannot upload - $packageFile does not exist"
fi
# Additional validation and output if quick mode isn't enabled
# Basically, if this is part of a publish operation, these steps are handled elsewhere
if [ "$quick" != "true" ]; then
# Parse package metadata first to confirm it's a valid deb/rpm
jsonFile=$(WritePackageInfoToFile $packageFile)
rm -f $jsonFile
echo "Uploading package to $server [$packageFile]"
fi
curl -s -k -X POST -F file=@$packageFile "$baseurl/v1/files"
echo ""
}
function ListFiles
{
curl -s -k "$baseurl/v1/files" | jq
}
function DeleteFile
{
fileId=$1
if [ -z "$fileId" ]; then
Bail "Error: Must specify an ID to delete"
fi
curl -s -X DELETE "$baseurl/v1/files/$fileId"
}
# Upload a single package using the specified JSON file # Upload a single package using the specified JSON file
function AddPackage function AddPackage
{ {
packageFile=$1 packageFile=$1
if [ -z $packageFile ]; then if [ -z $packageFile ]; then
Bail "Error: Must specify a JSON-formatted file. Reference $defaultPackageFile.template" Bail "Error: Must specify a JSON-formatted file. Reference $packageJsonTemplate"
fi fi
if [ ! -f $packageFile ]; then if [ ! -f $packageFile ]; then
Bail "Error: Cannot add package - $packageFile does not exist" Bail "Error: Cannot add package - $packageFile does not exist"
fi fi
packageUrl=$(grep "sourceUrl" $packageFile | head -n 1 | awk '{print $2}') packageUrl=$(grep "sourceUrl" $packageFile | head -n 1 | awk '{print $2}')
echo "Adding package to $server [$packageUrl]" echo "Adding package to $server [$packageUrl]"
curl -i -k "$baseurl/v1/packages" --data @./$packageFile -H "Content-Type: application/json" curl -i -k "$baseurl/v1/packages" --data @$packageFile -H "Content-Type: application/json"
echo "" echo ""
} }
# Gets the package name and version and writes it to a file
function WritePackageInfoToFile
{
packageFile=$1
tmpOut=$(mktemp)
if [ -z "$packageFile" ]; then
Bail "Error: Must specify path to a deb/rpm package"
elif [ ! -f "$packageFile" ]; then
Bail "Error: Specified file $packageFile does not exist"
fi
if dpkg -I $packageFile > $tmpOut 2> /dev/null; then
>&2 echo "File is deb format"
pkgName=$(grep "^\s*Package:" $tmpOut | awk '{print $2}')
pkgVer=$(grep "^\s*Version:" $tmpOut | awk '{print $2}')
elif rpm -qpi $packageFile > $tmpOut 2> /dev/null; then
>&2 echo "File is rpm format"
pkgName=$(egrep "^Name" $tmpOut | tr -d ':' | awk '{print $2}')
pkgVer=$(egrep "^Version" $tmpOut | tr -d ':' | awk '{print $2}')
else
rm -f $tmpOut
Bail "File is not a valid deb/rpm package $url"
fi
rm -f $tmpOut
if [ -z "$pkgName" ]; then
Bail "Unable to parse package name for $url"
elif [ -z "$pkgVer" ]; then
Bail "Unable to parse package version number for $url"
fi
# Create Package .json file
outJson=$(mktemp)
escapedUrl=$(echo "$url" | sed 's/\//\\\//g' | sed 's/\&/\\\&/g')
cp $packageJsonTemplate $outJson
sed -i "s/PACKAGENAME/$pkgName/g" $outJson
sed -i "s/PACKAGEVERSION/$pkgVer/g" $outJson
# Return path to json file
echo $outJson
}
# Upload a single package by dynamically creating a JSON file using a provided URL # Upload a single package by dynamically creating a JSON file using a provided URL
function AddPackageByUrl function AddPackageByUrl
{ {
@@ -119,41 +229,20 @@ function AddPackageByUrl
Bail "Unable to publish package because no URL was specified" Bail "Unable to publish package because no URL was specified"
fi fi
tmpFile=$(mktemp) tmpFile=$(mktemp)
tmpOut=$(mktemp)
if ! wget -q "$url" -O $tmpFile; then if ! wget -q "$url" -O $tmpFile; then
rm -f $tmpFile $tmpFile rm -f $tmpFile
Bail "Unable to download URL $url" Bail "Unable to download URL $url"
elif dpkg -I $tmpFile > $tmpOut 2> /dev/null; then
echo "File is deb format"
pkgName=$(grep "^\s*Package:" $tmpOut | awk '{print $2}')
pkgVer=$(grep "^\s*Version:" $tmpOut | awk '{print $2}')
elif rpm -qpi $tmpFile > $tmpOut 2> /dev/null; then
echo "File is rpm format"
pkgName=$(egrep "^Name" $tmpOut | tr -d ':' | awk '{print $2}')
pkgVer=$(egrep "^Version" $tmpOut | tr -d ':' | awk '{print $2}')
else
rm -f $tmpFile $tmpOut
Bail "File is not a valid deb/rpm package $url"
fi
rm -f $tmpFile $tmpOut
if [ -z "$pkgName" ]; then
Bail "Unable to parse package name for $url"
elif [ -z "$pkgVer" ]; then
Bail "Unable to parse package version number for $url"
fi fi
jsonFile=$(WritePackageInfoToFile $tmpFile)
# Create Package .json file # Create Package .json file
escapedUrl=$(echo "$url" | sed 's/\//\\\//g' | sed 's/\&/\\\&/g') escapedUrl=$(echo "$url" | sed 's/\//\\\//g' | sed 's/\&/\\\&/g')
cp $defaultPackageFile.template $defaultPackageFile sed -i "s/PACKAGEURL/$escapedUrl/g" $jsonFile
sed -i "s/PACKAGENAME/$pkgName/g" $defaultPackageFile sed -i "s/REPOSITORYID/$repositoryId/g" $jsonFile
sed -i "s/PACKAGEVERSION/$pkgVer/g" $defaultPackageFile
sed -i "s/PACKAGEURL/$escapedUrl/g" $defaultPackageFile
sed -i "s/REPOSITORYID/$repositoryId/g" $defaultPackageFile
# Perform Upload # Perform Upload
AddPackage $defaultPackageFile AddPackage $jsonFile
# Cleanup # Cleanup
rm -f $defaultPackageFile rm -f $jsonFile
} }
# Upload multiple packages by reading urls line-by-line from the specified file # Upload multiple packages by reading urls line-by-line from the specified file
@@ -180,7 +269,7 @@ function CheckUpload {
if [ -z "$id" ]; then if [ -z "$id" ]; then
Bail "Must specify an ID" Bail "Must specify an ID"
fi fi
curl -k $baseurl/v1/packages/queue/$id curl -s -k $baseurl/v1/packages/queue/$id | jq
echo "" echo ""
} }
@@ -232,6 +321,20 @@ while (( "$#" )); do
operation=AddPackages operation=AddPackages
shift shift
operand="$1" operand="$1"
elif [[ "$1" == "-addfile" ]]; then
operation=AddFile
shift
operand="$1"
elif [[ "$1" == "-uploadfile" ]]; then
operation=UploadFile
shift
operand="$1"
elif [[ "$1" == "-listfiles" ]]; then
operation=ListFiles
elif [[ "$1" == "-delfile" ]]; then
operation=DeleteFile
shift
operand="$1"
elif [[ "$1" == "-check" ]]; then elif [[ "$1" == "-check" ]]; then
operation=CheckUpload operation=CheckUpload
shift shift

View File

@@ -14,9 +14,10 @@ Param(
# Set the right architecture # Set the right architecture
$env:npm_config_arch="$arch" $env:npm_config_arch="$arch"
$env:CHILD_CONCURRENCY="1"
step "Install dependencies" { step "Install dependencies" {
exec { & npm install } exec { & yarn }
} }
step "Hygiene" { step "Hygiene" {

View File

@@ -17,9 +17,10 @@ Param(
# Set the right architecture # Set the right architecture
$env:npm_config_arch="$arch" $env:npm_config_arch="$arch"
$env:CHILD_CONCURRENCY="1"
step "Install dependencies" { step "Install dependencies" {
exec { & npm install } exec { & yarn }
} }
step "Hygiene" { step "Hygiene" {

View File

@@ -6,6 +6,7 @@ $env:HOME=$env:USERPROFILE
if (Test-Path env:AGENT_WORKFOLDER) { if (Test-Path env:AGENT_WORKFOLDER) {
$env:HOME="${env:AGENT_WORKFOLDER}\home" $env:HOME="${env:AGENT_WORKFOLDER}\home"
$env:npm_config_cache="${env:HOME}\npm-cache" $env:npm_config_cache="${env:HOME}\npm-cache"
$env:YARN_CACHE_FOLDER="${env:HOME}\yarn-cache"
$env:npm_config_devdir="${env:HOME}\npm-devdir" $env:npm_config_devdir="${env:HOME}\npm-devdir"
New-Item -Path "$env:HOME" -Type directory -Force | out-null New-Item -Path "$env:HOME" -Type directory -Force | out-null
New-Item -Path "$env:npm_config_cache" -Type directory -Force | out-null New-Item -Path "$env:npm_config_cache" -Type directory -Force | out-null

View File

@@ -1,6 +1,7 @@
# install node # install node
$env:Path = $env:NVM_HOME + ";" + $env:NVM_SYMLINK + ";" + $env:Path $env:Path = $env:NVM_HOME + ";" + $env:NVM_SYMLINK + ";" + $env:Path
$NodeVersion = "7.10.0" $NodeVersion = "8.9.1"
nvm install $NodeVersion nvm install $NodeVersion
nvm use $NodeVersion nvm use $NodeVersion
npm install -g yarn
$env:Path = $env:NVM_HOME + "\v" + $NodeVersion + ";" + $env:Path $env:Path = $env:NVM_HOME + "\v" + $NodeVersion + ";" + $env:Path

View File

@@ -2,10 +2,10 @@
"rules": { "rules": {
"no-unused-expression": true, "no-unused-expression": true,
"no-duplicate-variable": true, "no-duplicate-variable": true,
"no-unused-variable": true,
"curly": true, "curly": true,
"class-name": true, "class-name": true,
"semicolon": [ "semicolon": [
true,
"always" "always"
], ],
"triple-equals": true "triple-equals": true

View File

@@ -75,7 +75,6 @@ Filename: "{app}\{#ExeBasename}.exe"; Description: "{cm:LaunchProgram,{#NameLong
Root: HKCR; Subkey: "{#RegValueName}SourceFile"; ValueType: string; ValueName: ""; ValueData: "{cm:SourceFile,{#NameLong}}"; Flags: uninsdeletekey Root: HKCR; Subkey: "{#RegValueName}SourceFile"; ValueType: string; ValueName: ""; ValueData: "{cm:SourceFile,{#NameLong}}"; Flags: uninsdeletekey
Root: HKCR; Subkey: "{#RegValueName}SourceFile\DefaultIcon"; ValueType: string; ValueName: ""; ValueData: "{app}\resources\app\resources\win32\code_file.ico" Root: HKCR; Subkey: "{#RegValueName}SourceFile\DefaultIcon"; ValueType: string; ValueName: ""; ValueData: "{app}\resources\app\resources\win32\code_file.ico"
Root: HKCR; Subkey: "{#RegValueName}SourceFile\shell\open\command"; ValueType: string; ValueName: ""; ValueData: """{app}\{#ExeBasename}.exe"" ""%1""" Root: HKCR; Subkey: "{#RegValueName}SourceFile\shell\open\command"; ValueType: string; ValueName: ""; ValueData: """{app}\{#ExeBasename}.exe"" ""%1"""
Root: HKCU; Subkey: "Environment"; ValueType: expandsz; ValueName: "Path"; ValueData: "{olddata};{app}\bin"; Tasks: addtopath; Check: NeedsAddPath(ExpandConstant('{app}\bin')) Root: HKCU; Subkey: "Environment"; ValueType: expandsz; ValueName: "Path"; ValueData: "{olddata};{app}\bin"; Tasks: addtopath; Check: NeedsAddPath(ExpandConstant('{app}\bin'))
[Code] [Code]

View File

@@ -2,7 +2,7 @@
AddContextMenuFiles=エクスプローラーのファイル コンテキスト メニューに [%1 で開く] アクションを追加する AddContextMenuFiles=エクスプローラーのファイル コンテキスト メニューに [%1 で開く] アクションを追加する
AddContextMenuFolders=エクスプローラーのディレクトリ コンテキスト メニューに [%1 で開く] アクションを追加する AddContextMenuFolders=エクスプローラーのディレクトリ コンテキスト メニューに [%1 で開く] アクションを追加する
AssociateWithFiles=サポートされているファイルの種類のエディターとして、%1 を登録する AssociateWithFiles=サポートされているファイルの種類のエディターとして、%1 を登録する
AddToPath=PATH への追加 (再起動後に使用可能になる) AddToPath=PATH への追加再起動後に使用可能
RunAfter=インストール後に %1 を実行する RunAfter=インストール後に %1 を実行する
Other=その他: Other=その他:
SourceFile=%1 ソース ファイル SourceFile=%1 ソース ファイル

2319
build/yarn.lock Normal file

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

2566
extensions-modules/yarn.lock Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,7 @@
[{
"name": "typescript",
"version": "2.6.2",
"license": "Apache-2.0",
"repositoryURL": "https://github.com/Microsoft/TypeScript",
"isProd": true
}]

View File

@@ -0,0 +1,608 @@
# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY.
# yarn lockfile v1
"@types/node@^8.0.24", "@types/node@^8.0.47":
version "8.5.9"
resolved "https://registry.yarnpkg.com/@types/node/-/node-8.5.9.tgz#7155cfb4ae405bca4dd8df1a214c339e939109bf"
adal-node@0.1.25:
version "0.1.25"
resolved "https://registry.yarnpkg.com/adal-node/-/adal-node-0.1.25.tgz#6554350ab42914870004c45c0d64448f3dbfcd03"
dependencies:
"@types/node" "^8.0.47"
async ">=0.6.0"
date-utils "*"
jws "3.x.x"
request ">= 2.52.0"
underscore ">= 1.3.1"
uuid "^3.1.0"
xmldom ">= 0.1.x"
xpath.js "~1.0.5"
ajv@^5.1.0:
version "5.5.2"
resolved "https://registry.yarnpkg.com/ajv/-/ajv-5.5.2.tgz#73b5eeca3fab653e3d3f9422b341ad42205dc965"
dependencies:
co "^4.6.0"
fast-deep-equal "^1.0.0"
fast-json-stable-stringify "^2.0.0"
json-schema-traverse "^0.3.0"
ansi-regex@^2.0.0:
version "2.1.1"
resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-2.1.1.tgz#c3b33ab5ee360d86e0e628f0468ae7ef27d654df"
ansi-styles@^2.2.1:
version "2.2.1"
resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-2.2.1.tgz#b432dd3358b634cf75e1e4664368240533c1ddbe"
asn1@0.1.11:
version "0.1.11"
resolved "https://registry.yarnpkg.com/asn1/-/asn1-0.1.11.tgz#559be18376d08a4ec4dbe80877d27818639b2df7"
asn1@~0.2.3:
version "0.2.3"
resolved "https://registry.yarnpkg.com/asn1/-/asn1-0.2.3.tgz#dac8787713c9966849fc8180777ebe9c1ddf3b86"
assert-plus@1.0.0, assert-plus@^1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/assert-plus/-/assert-plus-1.0.0.tgz#f12e0f3c5d77b0b1cdd9146942e4e96c1e4dd525"
assert-plus@^0.1.5:
version "0.1.5"
resolved "https://registry.yarnpkg.com/assert-plus/-/assert-plus-0.1.5.tgz#ee74009413002d84cec7219c6ac811812e723160"
async@>=0.6.0, async@^2.0.1:
version "2.6.0"
resolved "https://registry.yarnpkg.com/async/-/async-2.6.0.tgz#61a29abb6fcc026fea77e56d1c6ec53a795951f4"
dependencies:
lodash "^4.14.0"
asynckit@^0.4.0:
version "0.4.0"
resolved "https://registry.yarnpkg.com/asynckit/-/asynckit-0.4.0.tgz#c79ed97f7f34cb8f2ba1bc9790bcc366474b4b79"
aws-sign2@~0.5.0:
version "0.5.0"
resolved "https://registry.yarnpkg.com/aws-sign2/-/aws-sign2-0.5.0.tgz#c57103f7a17fc037f02d7c2e64b602ea223f7d63"
aws-sign2@~0.7.0:
version "0.7.0"
resolved "https://registry.yarnpkg.com/aws-sign2/-/aws-sign2-0.7.0.tgz#b46e890934a9591f2d2f6f86d7e6a9f1b3fe76a8"
aws4@^1.6.0:
version "1.6.0"
resolved "https://registry.yarnpkg.com/aws4/-/aws4-1.6.0.tgz#83ef5ca860b2b32e4a0deedee8c771b9db57471e"
base64url@2.0.0, base64url@^2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/base64url/-/base64url-2.0.0.tgz#eac16e03ea1438eff9423d69baa36262ed1f70bb"
bcrypt-pbkdf@^1.0.0:
version "1.0.1"
resolved "https://registry.yarnpkg.com/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.1.tgz#63bc5dcb61331b92bc05fd528953c33462a06f8d"
dependencies:
tweetnacl "^0.14.3"
bl@~1.0.0:
version "1.0.3"
resolved "https://registry.yarnpkg.com/bl/-/bl-1.0.3.tgz#fc5421a28fd4226036c3b3891a66a25bc64d226e"
dependencies:
readable-stream "~2.0.5"
bluebird@^2.9.30:
version "2.11.0"
resolved "https://registry.yarnpkg.com/bluebird/-/bluebird-2.11.0.tgz#534b9033c022c9579c56ba3b3e5a5caafbb650e1"
boom@2.x.x:
version "2.10.1"
resolved "https://registry.yarnpkg.com/boom/-/boom-2.10.1.tgz#39c8918ceff5799f83f9492a848f625add0c766f"
dependencies:
hoek "2.x.x"
boom@4.x.x:
version "4.3.1"
resolved "https://registry.yarnpkg.com/boom/-/boom-4.3.1.tgz#4f8a3005cb4a7e3889f749030fd25b96e01d2e31"
dependencies:
hoek "4.x.x"
boom@5.x.x:
version "5.2.0"
resolved "https://registry.yarnpkg.com/boom/-/boom-5.2.0.tgz#5dd9da6ee3a5f302077436290cb717d3f4a54e02"
dependencies:
hoek "4.x.x"
buffer-equal-constant-time@1.0.1:
version "1.0.1"
resolved "https://registry.yarnpkg.com/buffer-equal-constant-time/-/buffer-equal-constant-time-1.0.1.tgz#f8e71132f7ffe6e01a5c9697a4c6f3e48d5cc819"
caseless@~0.11.0:
version "0.11.0"
resolved "https://registry.yarnpkg.com/caseless/-/caseless-0.11.0.tgz#715b96ea9841593cc33067923f5ec60ebda4f7d7"
caseless@~0.12.0:
version "0.12.0"
resolved "https://registry.yarnpkg.com/caseless/-/caseless-0.12.0.tgz#1b681c21ff84033c826543090689420d187151dc"
chalk@^1.0.0:
version "1.1.3"
resolved "https://registry.yarnpkg.com/chalk/-/chalk-1.1.3.tgz#a8115c55e4a702fe4d150abd3872822a7e09fc98"
dependencies:
ansi-styles "^2.2.1"
escape-string-regexp "^1.0.2"
has-ansi "^2.0.0"
strip-ansi "^3.0.0"
supports-color "^2.0.0"
co@^4.6.0:
version "4.6.0"
resolved "https://registry.yarnpkg.com/co/-/co-4.6.0.tgz#6ea6bdf3d853ae54ccb8e47bfa0bf3f9031fb184"
combined-stream@^1.0.5, combined-stream@~1.0.1, combined-stream@~1.0.5:
version "1.0.5"
resolved "https://registry.yarnpkg.com/combined-stream/-/combined-stream-1.0.5.tgz#938370a57b4a51dea2c77c15d5c5fdf895164009"
dependencies:
delayed-stream "~1.0.0"
commander@^2.8.1:
version "2.13.0"
resolved "https://registry.yarnpkg.com/commander/-/commander-2.13.0.tgz#6964bca67685df7c1f1430c584f07d7597885b9c"
core-util-is@1.0.2, core-util-is@~1.0.0:
version "1.0.2"
resolved "https://registry.yarnpkg.com/core-util-is/-/core-util-is-1.0.2.tgz#b5fd54220aa2bc5ab57aab7140c940754503c1a7"
cryptiles@2.x.x:
version "2.0.5"
resolved "https://registry.yarnpkg.com/cryptiles/-/cryptiles-2.0.5.tgz#3bdfecdc608147c1c67202fa291e7dca59eaa3b8"
dependencies:
boom "2.x.x"
cryptiles@3.x.x:
version "3.1.2"
resolved "https://registry.yarnpkg.com/cryptiles/-/cryptiles-3.1.2.tgz#a89fbb220f5ce25ec56e8c4aa8a4fd7b5b0d29fe"
dependencies:
boom "5.x.x"
ctype@0.5.3:
version "0.5.3"
resolved "https://registry.yarnpkg.com/ctype/-/ctype-0.5.3.tgz#82c18c2461f74114ef16c135224ad0b9144ca12f"
dashdash@^1.12.0:
version "1.14.1"
resolved "https://registry.yarnpkg.com/dashdash/-/dashdash-1.14.1.tgz#853cfa0f7cbe2fed5de20326b8dd581035f6e2f0"
dependencies:
assert-plus "^1.0.0"
date-utils@*:
version "1.2.21"
resolved "https://registry.yarnpkg.com/date-utils/-/date-utils-1.2.21.tgz#61fb16cdc1274b3c9acaaffe9fc69df8720a2b64"
delayed-stream@~1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/delayed-stream/-/delayed-stream-1.0.0.tgz#df3ae199acadfb7d440aaae0b29e2272b24ec619"
ecc-jsbn@~0.1.1:
version "0.1.1"
resolved "https://registry.yarnpkg.com/ecc-jsbn/-/ecc-jsbn-0.1.1.tgz#0fc73a9ed5f0d53c38193398523ef7e543777505"
dependencies:
jsbn "~0.1.0"
ecdsa-sig-formatter@1.0.9:
version "1.0.9"
resolved "https://registry.yarnpkg.com/ecdsa-sig-formatter/-/ecdsa-sig-formatter-1.0.9.tgz#4bc926274ec3b5abb5016e7e1d60921ac262b2a1"
dependencies:
base64url "^2.0.0"
safe-buffer "^5.0.1"
escape-string-regexp@^1.0.2:
version "1.0.5"
resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz#1b61c0562190a8dff6ae3bb2cf0200ca130b86d4"
extend@~3.0.0, extend@~3.0.1:
version "3.0.1"
resolved "https://registry.yarnpkg.com/extend/-/extend-3.0.1.tgz#a755ea7bc1adfcc5a31ce7e762dbaadc5e636444"
extsprintf@1.3.0:
version "1.3.0"
resolved "https://registry.yarnpkg.com/extsprintf/-/extsprintf-1.3.0.tgz#96918440e3041a7a414f8c52e3c574eb3c3e1e05"
extsprintf@^1.2.0:
version "1.4.0"
resolved "https://registry.yarnpkg.com/extsprintf/-/extsprintf-1.4.0.tgz#e2689f8f356fad62cca65a3a91c5df5f9551692f"
fast-deep-equal@^1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/fast-deep-equal/-/fast-deep-equal-1.0.0.tgz#96256a3bc975595eb36d82e9929d060d893439ff"
fast-json-stable-stringify@^2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/fast-json-stable-stringify/-/fast-json-stable-stringify-2.0.0.tgz#d5142c0caee6b1189f87d3a76111064f86c8bbf2"
forever-agent@~0.6.0, forever-agent@~0.6.1:
version "0.6.1"
resolved "https://registry.yarnpkg.com/forever-agent/-/forever-agent-0.6.1.tgz#fbc71f0c41adeb37f96c577ad1ed42d8fdacca91"
form-data@~1.0.0-rc1:
version "1.0.1"
resolved "https://registry.yarnpkg.com/form-data/-/form-data-1.0.1.tgz#ae315db9a4907fa065502304a66d7733475ee37c"
dependencies:
async "^2.0.1"
combined-stream "^1.0.5"
mime-types "^2.1.11"
form-data@~2.3.1:
version "2.3.1"
resolved "https://registry.yarnpkg.com/form-data/-/form-data-2.3.1.tgz#6fb94fbd71885306d73d15cc497fe4cc4ecd44bf"
dependencies:
asynckit "^0.4.0"
combined-stream "^1.0.5"
mime-types "^2.1.12"
generate-function@^2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/generate-function/-/generate-function-2.0.0.tgz#6858fe7c0969b7d4e9093337647ac79f60dfbe74"
generate-object-property@^1.1.0:
version "1.2.0"
resolved "https://registry.yarnpkg.com/generate-object-property/-/generate-object-property-1.2.0.tgz#9c0e1c40308ce804f4783618b937fa88f99d50d0"
dependencies:
is-property "^1.0.0"
getpass@^0.1.1:
version "0.1.7"
resolved "https://registry.yarnpkg.com/getpass/-/getpass-0.1.7.tgz#5eff8e3e684d569ae4cb2b1282604e8ba62149fa"
dependencies:
assert-plus "^1.0.0"
har-schema@^2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/har-schema/-/har-schema-2.0.0.tgz#a94c2224ebcac04782a0d9035521f24735b7ec92"
har-validator@^1.6.1:
version "1.8.0"
resolved "https://registry.yarnpkg.com/har-validator/-/har-validator-1.8.0.tgz#d83842b0eb4c435960aeb108a067a3aa94c0eeb2"
dependencies:
bluebird "^2.9.30"
chalk "^1.0.0"
commander "^2.8.1"
is-my-json-valid "^2.12.0"
har-validator@~5.0.3:
version "5.0.3"
resolved "https://registry.yarnpkg.com/har-validator/-/har-validator-5.0.3.tgz#ba402c266194f15956ef15e0fcf242993f6a7dfd"
dependencies:
ajv "^5.1.0"
har-schema "^2.0.0"
has-ansi@^2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/has-ansi/-/has-ansi-2.0.0.tgz#34f5049ce1ecdf2b0649af3ef24e45ed35416d91"
dependencies:
ansi-regex "^2.0.0"
hawk@~3.1.0:
version "3.1.3"
resolved "https://registry.yarnpkg.com/hawk/-/hawk-3.1.3.tgz#078444bd7c1640b0fe540d2c9b73d59678e8e1c4"
dependencies:
boom "2.x.x"
cryptiles "2.x.x"
hoek "2.x.x"
sntp "1.x.x"
hawk@~6.0.2:
version "6.0.2"
resolved "https://registry.yarnpkg.com/hawk/-/hawk-6.0.2.tgz#af4d914eb065f9b5ce4d9d11c1cb2126eecc3038"
dependencies:
boom "4.x.x"
cryptiles "3.x.x"
hoek "4.x.x"
sntp "2.x.x"
hoek@2.x.x:
version "2.16.3"
resolved "https://registry.yarnpkg.com/hoek/-/hoek-2.16.3.tgz#20bb7403d3cea398e91dc4710a8ff1b8274a25ed"
hoek@4.x.x:
version "4.2.0"
resolved "https://registry.yarnpkg.com/hoek/-/hoek-4.2.0.tgz#72d9d0754f7fe25ca2d01ad8f8f9a9449a89526d"
http-signature@~0.11.0:
version "0.11.0"
resolved "https://registry.yarnpkg.com/http-signature/-/http-signature-0.11.0.tgz#1796cf67a001ad5cd6849dca0991485f09089fe6"
dependencies:
asn1 "0.1.11"
assert-plus "^0.1.5"
ctype "0.5.3"
http-signature@~1.2.0:
version "1.2.0"
resolved "https://registry.yarnpkg.com/http-signature/-/http-signature-1.2.0.tgz#9aecd925114772f3d95b65a60abb8f7c18fbace1"
dependencies:
assert-plus "^1.0.0"
jsprim "^1.2.2"
sshpk "^1.7.0"
inherits@~2.0.1:
version "2.0.3"
resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.3.tgz#633c2c83e3da42a502f52466022480f4208261de"
is-my-json-valid@^2.12.0:
version "2.17.1"
resolved "https://registry.yarnpkg.com/is-my-json-valid/-/is-my-json-valid-2.17.1.tgz#3da98914a70a22f0a8563ef1511a246c6fc55471"
dependencies:
generate-function "^2.0.0"
generate-object-property "^1.1.0"
jsonpointer "^4.0.0"
xtend "^4.0.0"
is-property@^1.0.0:
version "1.0.2"
resolved "https://registry.yarnpkg.com/is-property/-/is-property-1.0.2.tgz#57fe1c4e48474edd65b09911f26b1cd4095dda84"
is-typedarray@~1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/is-typedarray/-/is-typedarray-1.0.0.tgz#e479c80858df0c1b11ddda6940f96011fcda4a9a"
isarray@~1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/isarray/-/isarray-1.0.0.tgz#bb935d48582cba168c06834957a54a3e07124f11"
isstream@~0.1.1, isstream@~0.1.2:
version "0.1.2"
resolved "https://registry.yarnpkg.com/isstream/-/isstream-0.1.2.tgz#47e63f7af55afa6f92e1500e690eb8b8529c099a"
jsbn@~0.1.0:
version "0.1.1"
resolved "https://registry.yarnpkg.com/jsbn/-/jsbn-0.1.1.tgz#a5e654c2e5a2deb5f201d96cefbca80c0ef2f513"
json-schema-traverse@^0.3.0:
version "0.3.1"
resolved "https://registry.yarnpkg.com/json-schema-traverse/-/json-schema-traverse-0.3.1.tgz#349a6d44c53a51de89b40805c5d5e59b417d3340"
json-schema@0.2.3:
version "0.2.3"
resolved "https://registry.yarnpkg.com/json-schema/-/json-schema-0.2.3.tgz#b480c892e59a2f05954ce727bd3f2a4e882f9e13"
json-stringify-safe@~5.0.0, json-stringify-safe@~5.0.1:
version "5.0.1"
resolved "https://registry.yarnpkg.com/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz#1296a2d58fd45f19a0f6ce01d65701e2c735b6eb"
jsonpointer@^4.0.0:
version "4.0.1"
resolved "https://registry.yarnpkg.com/jsonpointer/-/jsonpointer-4.0.1.tgz#4fd92cb34e0e9db3c89c8622ecf51f9b978c6cb9"
jsprim@^1.2.2:
version "1.4.1"
resolved "https://registry.yarnpkg.com/jsprim/-/jsprim-1.4.1.tgz#313e66bc1e5cc06e438bc1b7499c2e5c56acb6a2"
dependencies:
assert-plus "1.0.0"
extsprintf "1.3.0"
json-schema "0.2.3"
verror "1.10.0"
jwa@^1.1.4:
version "1.1.5"
resolved "https://registry.yarnpkg.com/jwa/-/jwa-1.1.5.tgz#a0552ce0220742cd52e153774a32905c30e756e5"
dependencies:
base64url "2.0.0"
buffer-equal-constant-time "1.0.1"
ecdsa-sig-formatter "1.0.9"
safe-buffer "^5.0.1"
jws@3.x.x:
version "3.1.4"
resolved "https://registry.yarnpkg.com/jws/-/jws-3.1.4.tgz#f9e8b9338e8a847277d6444b1464f61880e050a2"
dependencies:
base64url "^2.0.0"
jwa "^1.1.4"
safe-buffer "^5.0.1"
lodash@^4.14.0:
version "4.17.4"
resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.4.tgz#78203a4d1c328ae1d86dca6460e369b57f4055ae"
mime-db@~1.30.0:
version "1.30.0"
resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.30.0.tgz#74c643da2dd9d6a45399963465b26d5ca7d71f01"
mime-types@^2.1.11, mime-types@^2.1.12, mime-types@~2.1.17, mime-types@~2.1.2:
version "2.1.17"
resolved "https://registry.yarnpkg.com/mime-types/-/mime-types-2.1.17.tgz#09d7a393f03e995a79f8af857b70a9e0ab16557a"
dependencies:
mime-db "~1.30.0"
node-uuid@~1.4.0:
version "1.4.8"
resolved "https://registry.yarnpkg.com/node-uuid/-/node-uuid-1.4.8.tgz#b040eb0923968afabf8d32fb1f17f1167fdab907"
oauth-sign@~0.8.0, oauth-sign@~0.8.2:
version "0.8.2"
resolved "https://registry.yarnpkg.com/oauth-sign/-/oauth-sign-0.8.2.tgz#46a6ab7f0aead8deae9ec0565780b7d4efeb9d43"
performance-now@^2.1.0:
version "2.1.0"
resolved "https://registry.yarnpkg.com/performance-now/-/performance-now-2.1.0.tgz#6309f4e0e5fa913ec1c69307ae364b4b377c9e7b"
process-nextick-args@~1.0.6:
version "1.0.7"
resolved "https://registry.yarnpkg.com/process-nextick-args/-/process-nextick-args-1.0.7.tgz#150e20b756590ad3f91093f25a4f2ad8bff30ba3"
punycode@^1.4.1:
version "1.4.1"
resolved "https://registry.yarnpkg.com/punycode/-/punycode-1.4.1.tgz#c0d5a63b2718800ad8e1eb0fa5269c84dd41845e"
qs@~5.1.0:
version "5.1.0"
resolved "https://registry.yarnpkg.com/qs/-/qs-5.1.0.tgz#4d932e5c7ea411cca76a312d39a606200fd50cd9"
qs@~6.5.1:
version "6.5.1"
resolved "https://registry.yarnpkg.com/qs/-/qs-6.5.1.tgz#349cdf6eef89ec45c12d7d5eb3fc0c870343a6d8"
readable-stream@~2.0.5:
version "2.0.6"
resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-2.0.6.tgz#8f90341e68a53ccc928788dacfcd11b36eb9b78e"
dependencies:
core-util-is "~1.0.0"
inherits "~2.0.1"
isarray "~1.0.0"
process-nextick-args "~1.0.6"
string_decoder "~0.10.x"
util-deprecate "~1.0.1"
request@2.63.0:
version "2.63.0"
resolved "https://registry.yarnpkg.com/request/-/request-2.63.0.tgz#c83e7c3485e5d9bf9b146318429bc48f1253d8be"
dependencies:
aws-sign2 "~0.5.0"
bl "~1.0.0"
caseless "~0.11.0"
combined-stream "~1.0.1"
extend "~3.0.0"
forever-agent "~0.6.0"
form-data "~1.0.0-rc1"
har-validator "^1.6.1"
hawk "~3.1.0"
http-signature "~0.11.0"
isstream "~0.1.1"
json-stringify-safe "~5.0.0"
mime-types "~2.1.2"
node-uuid "~1.4.0"
oauth-sign "~0.8.0"
qs "~5.1.0"
stringstream "~0.0.4"
tough-cookie ">=0.12.0"
tunnel-agent "~0.4.0"
"request@>= 2.52.0":
version "2.83.0"
resolved "https://registry.yarnpkg.com/request/-/request-2.83.0.tgz#ca0b65da02ed62935887808e6f510381034e3356"
dependencies:
aws-sign2 "~0.7.0"
aws4 "^1.6.0"
caseless "~0.12.0"
combined-stream "~1.0.5"
extend "~3.0.1"
forever-agent "~0.6.1"
form-data "~2.3.1"
har-validator "~5.0.3"
hawk "~6.0.2"
http-signature "~1.2.0"
is-typedarray "~1.0.0"
isstream "~0.1.2"
json-stringify-safe "~5.0.1"
mime-types "~2.1.17"
oauth-sign "~0.8.2"
performance-now "^2.1.0"
qs "~6.5.1"
safe-buffer "^5.1.1"
stringstream "~0.0.5"
tough-cookie "~2.3.3"
tunnel-agent "^0.6.0"
uuid "^3.1.0"
safe-buffer@^5.0.1, safe-buffer@^5.1.1:
version "5.1.1"
resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.1.1.tgz#893312af69b2123def71f57889001671eeb2c853"
sntp@1.x.x:
version "1.0.9"
resolved "https://registry.yarnpkg.com/sntp/-/sntp-1.0.9.tgz#6541184cc90aeea6c6e7b35e2659082443c66198"
dependencies:
hoek "2.x.x"
sntp@2.x.x:
version "2.1.0"
resolved "https://registry.yarnpkg.com/sntp/-/sntp-2.1.0.tgz#2c6cec14fedc2222739caf9b5c3d85d1cc5a2cc8"
dependencies:
hoek "4.x.x"
sshpk@^1.7.0:
version "1.13.1"
resolved "https://registry.yarnpkg.com/sshpk/-/sshpk-1.13.1.tgz#512df6da6287144316dc4c18fe1cf1d940739be3"
dependencies:
asn1 "~0.2.3"
assert-plus "^1.0.0"
dashdash "^1.12.0"
getpass "^0.1.1"
optionalDependencies:
bcrypt-pbkdf "^1.0.0"
ecc-jsbn "~0.1.1"
jsbn "~0.1.0"
tweetnacl "~0.14.0"
string_decoder@~0.10.x:
version "0.10.31"
resolved "https://registry.yarnpkg.com/string_decoder/-/string_decoder-0.10.31.tgz#62e203bc41766c6c28c9fc84301dab1c5310fa94"
stringstream@~0.0.4, stringstream@~0.0.5:
version "0.0.5"
resolved "https://registry.yarnpkg.com/stringstream/-/stringstream-0.0.5.tgz#4e484cd4de5a0bbbee18e46307710a8a81621878"
strip-ansi@^3.0.0:
version "3.0.1"
resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-3.0.1.tgz#6a385fb8853d952d5ff05d0e8aaf94278dc63dcf"
dependencies:
ansi-regex "^2.0.0"
supports-color@^2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-2.0.0.tgz#535d045ce6b6363fa40117084629995e9df324c7"
tough-cookie@>=0.12.0, tough-cookie@~2.3.3:
version "2.3.3"
resolved "https://registry.yarnpkg.com/tough-cookie/-/tough-cookie-2.3.3.tgz#0b618a5565b6dea90bf3425d04d55edc475a7561"
dependencies:
punycode "^1.4.1"
tunnel-agent@^0.6.0:
version "0.6.0"
resolved "https://registry.yarnpkg.com/tunnel-agent/-/tunnel-agent-0.6.0.tgz#27a5dea06b36b04a0a9966774b290868f0fc40fd"
dependencies:
safe-buffer "^5.0.1"
tunnel-agent@~0.4.0:
version "0.4.3"
resolved "https://registry.yarnpkg.com/tunnel-agent/-/tunnel-agent-0.4.3.tgz#6373db76909fe570e08d73583365ed828a74eeeb"
tweetnacl@^0.14.3, tweetnacl@~0.14.0:
version "0.14.5"
resolved "https://registry.yarnpkg.com/tweetnacl/-/tweetnacl-0.14.5.tgz#5ae68177f192d4456269d108afa93ff8743f4f64"
"underscore@>= 1.3.1":
version "1.8.3"
resolved "https://registry.yarnpkg.com/underscore/-/underscore-1.8.3.tgz#4f3fb53b106e6097fcf9cb4109f2a5e9bdfa5022"
util-deprecate@~1.0.1:
version "1.0.2"
resolved "https://registry.yarnpkg.com/util-deprecate/-/util-deprecate-1.0.2.tgz#450d4dc9fa70de732762fbd2d4a28981419a0ccf"
uuid@^3.1.0:
version "3.2.1"
resolved "https://registry.yarnpkg.com/uuid/-/uuid-3.2.1.tgz#12c528bb9d58d0b9265d9a2f6f0fe8be17ff1f14"
verror@1.10.0:
version "1.10.0"
resolved "https://registry.yarnpkg.com/verror/-/verror-1.10.0.tgz#3a105ca17053af55d6e270c1f8288682e18da400"
dependencies:
assert-plus "^1.0.0"
core-util-is "1.0.2"
extsprintf "^1.2.0"
vscode-nls@2.0.2:
version "2.0.2"
resolved "https://registry.yarnpkg.com/vscode-nls/-/vscode-nls-2.0.2.tgz#808522380844b8ad153499af5c3b03921aea02da"
"xmldom@>= 0.1.x":
version "0.1.27"
resolved "https://registry.yarnpkg.com/xmldom/-/xmldom-0.1.27.tgz#d501f97b3bdb403af8ef9ecc20573187aadac0e9"
xpath.js@~1.0.5:
version "1.0.7"
resolved "https://registry.yarnpkg.com/xpath.js/-/xpath.js-1.0.7.tgz#7e94627f541276cbc6a6b02b5d35e9418565b3e4"
xtend@^4.0.0:
version "4.0.1"
resolved "https://registry.yarnpkg.com/xtend/-/xtend-4.0.1.tgz#a5c6d532be656e23db820efb943a1f04998d63af"

View File

@@ -1,22 +1,7 @@
// ATTENTION - THIS DIRECTORY CONTAINS THIRD PARTY OPEN SOURCE MATERIALS: // ATTENTION - THIS DIRECTORY CONTAINS THIRD PARTY OPEN SOURCE MATERIALS:
[{ [{
"name": "sublimehq/Packages", "name": "mmims/language-batchfile",
"version": "0.0.0", "version": "0.0.0",
"license": "TextMate Bundle License", "license": "MIT",
"repositoryURL": "https://github.com/sublimehq/Packages", "repositoryURL": "https://github.com/mmims/language-batchfile"
"licenseDetail": [
"Copyright (c) Sublime Packages project authors",
"",
"If not otherwise specified (see below), files in this folder fall under the following license: ",
"",
"Permission to copy, use, modify, sell and distribute this",
"software is granted. This software is provided \"as is\" without",
"express or implied warranty, and with no claim as to its",
"suitability for any purpose.",
"",
"An exception is made for files in readable text which contain their own license information, ",
"or files where an accompanying file exists (in the same directory) with a \"-license\" suffix added ",
"to the base-name name of the original file, and an extension of txt, html, or similar. For example ",
"\"tidy\" is accompanied by \"tidy-license.txt\"."
]
}] }]

View File

@@ -3,6 +3,9 @@
"version": "0.1.0", "version": "0.1.0",
"publisher": "vscode", "publisher": "vscode",
"engines": { "vscode": "*" }, "engines": { "vscode": "*" },
"scripts": {
"update-grammar": "node ../../build/npm/update-grammar.js mmims/language-batchfile grammars/batchfile.cson ./syntaxes/batchfile.tmLanguage.json"
},
"contributes": { "contributes": {
"languages": [{ "languages": [{
"id": "bat", "id": "bat",
@@ -12,8 +15,12 @@
}], }],
"grammars": [{ "grammars": [{
"language": "bat", "language": "bat",
"scopeName": "source.dosbatch", "scopeName": "source.batchfile",
"path": "./syntaxes/Batch File.tmLanguage" "path": "./syntaxes/batchfile.tmLanguage.json"
}],
"snippets": [{
"language": "bat",
"path": "./snippets/batchfile.snippets.json"
}] }]
} }
} }

View File

@@ -0,0 +1,16 @@
{
"Region Start": {
"prefix": "#region",
"body": [
"::#region"
],
"description": "Folding Region Start"
},
"Region End": {
"prefix": "#endregion",
"body": [
"::#endregion"
],
"description": "Folding Region End"
}
}

View File

@@ -0,0 +1,693 @@
{
"information_for_contributors": [
"This file has been converted from https://github.com/mmims/language-batchfile/blob/master/grammars/batchfile.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/mmims/language-batchfile/commit/40b605c75db3967a24b7015f6d3a885360b84e28",
"scopeName": "source.batchfile",
"name": "Batch File",
"fileTypes": [
"bat",
"cmd"
],
"patterns": [
{
"include": "#commands"
},
{
"include": "#comments"
},
{
"include": "#constants"
},
{
"include": "#controls"
},
{
"include": "#escaped_characters"
},
{
"include": "#labels"
},
{
"include": "#numbers"
},
{
"include": "#operators"
},
{
"include": "#parens"
},
{
"include": "#strings"
},
{
"include": "#variables"
}
],
"repository": {
"commands": {
"patterns": [
{
"match": "(?<=^|[\\s@])(?i:adprep|append|arp|assoc|at|atmadm|attrib|auditpol|autochk|autoconv|autofmt|bcdboot|bcdedit|bdehdcfg|bitsadmin|bootcfg|brea|cacls|cd|certreq|certutil|change|chcp|chdir|chglogon|chgport|chgusr|chkdsk|chkntfs|choice|cipher|clip|clscluadmin|cluster|cmd|cmdkey|cmstp|color|comp|compact|convert|copy|cprofile|cscript|csvde|date|dcdiag|dcgpofix|dcpromo|defra|del|dfscmd|dfsdiag|dfsrmig|diantz|dir|dirquota|diskcomp|diskcopy|diskpart|diskperf|diskraid|diskshadow|dispdiag|doin|dnscmd|doskey|driverquery|dsacls|dsadd|dsamain|dsdbutil|dsget|dsmgmt|dsmod|dsmove|dsquery|dsrm|edit|endlocal|eraseesentutl|eventcreate|eventquery|eventtriggers|evntcmd|expand|extract|fc|filescrn|find|findstr|finger|flattemp|fonde|forfiles|format|freedisk|fsutil|ftp|ftype|fveupdate|getmac|gettype|gpfixup|gpresult|gpupdate|graftabl|hashgen|hep|helpctr|hostname|icacls|iisreset|inuse|ipconfig|ipxroute|irftp|ismserv|jetpack|klist|ksetup|ktmutil|ktpass|label|ldifd|ldp|lodctr|logman|logoff|lpq|lpr|macfile|makecab|manage-bde|mapadmin|md|mkdir|mklink|mmc|mode|more|mount|mountvol|move|mqbup|mqsvc|mqtgsvc|msdt|msg|msiexec|msinfo32|mstsc|nbtstat|net computer|net group|net localgroup|net print|net session|net share|net start|net stop|net use|net user|net view|net|netcfg|netdiag|netdom|netsh|netstat|nfsadmin|nfsshare|nfsstat|nlb|nlbmgr|nltest|nslookup|ntackup|ntcmdprompt|ntdsutil|ntfrsutl|openfiles|pagefileconfig|path|pathping|pause|pbadmin|pentnt|perfmon|ping|pnpunatten|pnputil|popd|powercfg|powershell|powershell_ise|print|prncnfg|prndrvr|prnjobs|prnmngr|prnport|prnqctl|prompt|pubprn|pushd|pushprinterconnections|pwlauncher|qappsrv|qprocess|query|quser|qwinsta|rasdial|rcp|rd|rdpsign|regentc|recover|redircmp|redirusr|reg|regini|regsvr32|relog|ren|rename|rendom|repadmin|repair-bde|replace|reset session|rxec|risetup|rmdir|robocopy|route|rpcinfo|rpcping|rsh|runas|rundll32|rwinsta|sc|schtasks|scwcmd|secedit|serverceipoptin|servrmanagercmd|serverweroptin|setlocal|setspn|setx|sfc|shadow|shift|showmount|shutdown|sort|start|storrept|subst|sxstrace|ysocmgr|systeminfo|takeown|tapicfg|taskkill|tasklist|tcmsetup|telnet|tftp|time|timeout|title|tlntadmn|tpmvscmgr|tpmvscmgr|tacerpt|tracert|tree|tscon|tsdiscon|tsecimp|tskill|tsprof|type|typeperf|tzutil|uddiconfig|umount|unlodctr|ver|verifier|verif|vol|vssadmin|w32tm|waitfor|wbadmin|wdsutil|wecutil|wevtutil|where|whoami|winnt|winnt32|winpop|winrm|winrs|winsat|wlbs|mic|wscript|xcopy)(?=$|\\s)",
"name": "keyword.command.batchfile"
},
{
"begin": "(?<=^|[\\s@])(?i:echo)(?=$|\\s|\\.)",
"beginCaptures": {
"0": {
"name": "keyword.command.batchfile"
}
},
"end": "(?=$\\n|[&|><)])",
"patterns": [
{
"include": "#escaped_characters"
},
{
"include": "#variables"
},
{
"include": "#numbers"
},
{
"include": "#strings"
}
]
},
{
"include": "#command_set"
}
]
},
"command_set": {
"patterns": [
{
"begin": "(?<=^|[\\s@])(?i:SET)(?=$|\\s)",
"beginCaptures": {
"0": {
"name": "keyword.command.batchfile"
}
},
"end": "(?=$\\n|[&|><)])",
"patterns": [
{
"include": "#command_set_inside"
}
]
}
]
},
"command_set_inside": {
"patterns": [
{
"include": "#escaped_characters"
},
{
"include": "#variables"
},
{
"include": "#numbers"
},
{
"include": "#parens"
},
{
"begin": "(\")\\s*([^ ][^=]*)(=)\"?",
"beginCaptures": {
"1": {
"name": "punctuation.definition.string.begin.batchfile"
},
"2": {
"name": "variable.other.readwrite.batchfile"
},
"3": {
"name": "keyword.operator.assignment.batchfile"
}
},
"end": "\"",
"endCaptures": {
"0": {
"name": "string.quoted.double.batchfile"
}
},
"patterns": [
{
"include": "#variables"
},
{
"include": "#numbers"
},
{
"include": "#parens"
}
]
},
{
"include": "#strings"
},
{
"begin": "([^ ][^=]*)(=)",
"beginCaptures": {
"1": {
"name": "variable.other.readwrite.batchfile"
},
"2": {
"name": "keyword.operator.assignment.batchfile"
}
},
"end": "(?=$\\n|[&|><)])",
"patterns": [
{
"include": "#escaped_characters"
},
{
"include": "#variables"
},
{
"include": "#numbers"
},
{
"include": "#parens"
},
{
"include": "#strings"
}
]
},
{
"begin": "\\s+/[aA]\\s+",
"end": "(?=$\\n|[&|><)])",
"name": "meta.expression.set.batchfile",
"patterns": [
{
"include": "#command_set_inside_arithmetic"
},
{
"include": "#command_set_group"
},
{
"begin": "\"",
"beginCaptures": {
"0": {
"name": "punctuation.definition.string.begin.batchfile"
}
},
"end": "\"",
"endCaptures": {
"0": {
"name": "punctuation.definition.string.end.batchfile"
}
},
"name": "string.quoted.double.batchfile",
"patterns": [
{
"include": "#command_set_inside_arithmetic"
},
{
"include": "#command_set_group"
},
{
"include": "#variables"
}
]
}
]
},
{
"begin": "\\s+/[pP]\\s+",
"end": "(?=$\\n|[&|><)])",
"patterns": [
{
"begin": "([^ ][^=]*)(=)",
"beginCaptures": {
"1": {
"name": "variable.other.readwrite.batchfile"
},
"2": {
"name": "keyword.operator.assignment.batchfile"
}
},
"end": "(?=$\\n|[&|><)])",
"name": "meta.prompt.set.batchfile",
"patterns": [
{
"include": "#strings"
}
]
}
]
}
]
},
"command_set_group": {
"patterns": [
{
"begin": "\\(",
"beginCaptures": {
"0": {
"name": "punctuation.section.group.begin.batchfile"
}
},
"end": "\\)",
"endCaptures": {
"0": {
"name": "punctuation.section.group.end.batchfile"
}
},
"patterns": [
{
"include": "#command_set_inside_arithmetic"
}
]
}
]
},
"command_set_inside_arithmetic": {
"patterns": [
{
"include": "#command_set_operators"
},
{
"include": "#numbers"
},
{
"match": ",",
"name": "punctuation.separator.batchfile"
}
]
},
"command_set_operators": {
"patterns": [
{
"match": "\\+\\=|\\-\\=|\\*\\=|/\\=|%%\\=|&\\=|\\|\\=|\\^\\=|<<\\=|>>\\=",
"name": "keyword.operator.assignment.augmented.batchfile"
},
{
"match": "\\+|\\-|/|\\*|%%|\\||&|\\^|<<|>>|~",
"name": "keyword.operator.arithmetic.batchfile"
},
{
"match": "!",
"name": "keyword.operator.logical.batchfile"
},
{
"match": "=",
"name": "keyword.operator.assignment.batchfile"
}
]
},
"comments": {
"patterns": [
{
"begin": "(?:^|(&))\\s*(?=((?::[+=,;: ])))",
"beginCaptures": {
"1": {
"name": "keyword.operator.conditional.batchfile"
}
},
"end": "\\n",
"patterns": [
{
"begin": "((?::[+=,;: ]))",
"beginCaptures": {
"1": {
"name": "punctuation.definition.comment.batchfile"
}
},
"end": "(?=\\n)",
"name": "comment.line.colon.batchfile"
}
]
},
{
"begin": "(?<=^|[\\s@])(?i)(REM)(\\.)",
"beginCaptures": {
"1": {
"name": "keyword.command.rem.batchfile"
},
"2": {
"name": "punctuation.separator.batchfile"
}
},
"end": "(?=$\\n|[&|><)])",
"name": "comment.line.rem.batchfile"
},
{
"begin": "(?<=^|[\\s@])(?i:rem)\\b",
"beginCaptures": {
"0": {
"name": "keyword.command.rem.batchfile"
}
},
"end": "\\n",
"name": "comment.line.rem.batchfile",
"patterns": [
{
"match": "[><|]",
"name": "invalid.illegal.unexpected-character.batchfile"
}
]
}
]
},
"constants": {
"patterns": [
{
"match": "\\b(?i:NUL)\\b",
"name": "constant.language.batchfile"
}
]
},
"controls": {
"patterns": [
{
"match": "(?<=^|\\s)(?i)(?:goto|call|exit)(?=$|\\s)",
"name": "keyword.control.statement.batchfile"
},
{
"match": "(?<=^|\\s)(?i)(if)\\s+(?:(not)\\s+)?(exist|defined|errorlevel|cmdextversion)(?=\\s)",
"captures": {
"1": {
"name": "keyword.control.conditional.batchfile"
},
"2": {
"name": "keyword.operator.logical.batchfile"
},
"3": {
"name": "keyword.other.special-method.batchfile"
}
}
},
{
"match": "(?<=^|\\s)(?i)(?:if|else)(?=$|\\s)",
"name": "keyword.control.conditional.batchfile"
},
{
"match": "(?<=^|\\s)(?i)for(?=\\s)",
"name": "keyword.control.repeat.batchfile"
}
]
},
"escaped_characters": {
"patterns": [
{
"match": "%%|\\^\\^!|\\^.|\\^\\n",
"name": "constant.character.escape.batchfile"
}
]
},
"labels": {
"patterns": [
{
"match": "^\\s*(:)([^+=,;:\\s].*)$",
"captures": {
"1": {
"name": "punctuation.separator.batchfile"
},
"2": {
"name": "keyword.other.special-method.batchfile"
}
}
}
]
},
"numbers": {
"patterns": [
{
"match": "(?<=^|\\s|=)(0[xX][0-9A-Fa-f]*|[+-]?\\d+)(?=$|\\s|<|>)",
"name": "constant.numeric.batchfile"
}
]
},
"operators": {
"patterns": [
{
"match": "@(?=\\S)",
"name": "keyword.operator.at.batchfile"
},
{
"match": "(?<=\\s)(?i:EQU|NEQ|LSS|LEQ|GTR|GEQ)(?=\\s)|==",
"name": "keyword.operator.comparison.batchfile"
},
{
"match": "(?<=\\s)(?i)(NOT)(?=\\s)",
"name": "keyword.operator.logical.batchfile"
},
{
"match": "&&?|\\|\\|",
"name": "keyword.operator.conditional.batchfile"
},
{
"match": "\\|",
"name": "keyword.operator.pipe.batchfile"
},
{
"match": "<&?|>[&>]?",
"name": "keyword.operator.redirection.batchfile"
}
]
},
"parens": {
"patterns": [
{
"begin": "\\(",
"beginCaptures": {
"0": "punctuation.section.group.begin.batchfile"
},
"end": "\\)",
"endCaptures": {
"0": "punctuation.section.group.end.batchfile"
},
"name": "meta.group.batchfile",
"patterns": [
{
"match": ",|;",
"name": "punctuation.separator.batchfile"
},
{
"include": "$self"
}
]
}
]
},
"strings": {
"patterns": [
{
"begin": "\"",
"beginCaptures": {
"0": {
"name": "punctuation.definition.string.begin.batchfile"
}
},
"end": "(\")|(\\n)",
"endCaptures": {
"1": {
"name": "punctuation.definition.string.end.batchfile"
},
"2": {
"name": "invalid.illegal.newline.batchfile"
}
},
"name": "string.quoted.double.batchfile",
"patterns": [
{
"include": "#variables"
}
]
}
]
},
"variables": {
"patterns": [
{
"match": "(%)((~([fdpnxsatz]|\\$PATH:)*)?\\d|\\*)",
"captures": {
"1": {
"name": "punctuation.definition.variable.batchfile"
}
},
"name": "variable.parameter.batchfile"
},
{
"include": "#variable"
},
{
"include": "#variable_delayed_expansion"
}
]
},
"variable": {
"patterns": [
{
"begin": "%(?=[^%]+%)",
"beginCaptures": {
"0": {
"name": "punctuation.definition.variable.begin.batchfile"
}
},
"end": "(%)|\\n",
"endCaptures": {
"1": {
"name": "punctuation.definition.variable.end.batchfile"
}
},
"name": "variable.other.readwrite.batchfile",
"patterns": [
{
"begin": ":~",
"beginCaptures": {
"0": {
"name": "punctuation.separator.batchfile"
}
},
"end": "(?=%|\\n)",
"name": "meta.variable.substring.batchfile",
"patterns": [
{
"include": "#variable_substring"
}
]
},
{
"begin": ":",
"beginCaptures": {
"0": {
"name": "punctuation.separator.batchfile"
}
},
"end": "(?=%|\\n)",
"name": "meta.variable.substitution.batchfile",
"patterns": [
{
"include": "#variable_replace"
},
{
"begin": "=",
"beginCaptures": {
"0": {
"name": "punctuation.separator.batchfile"
}
},
"end": "(?=%|\\n)",
"patterns": [
{
"include": "#variable_delayed_expansion"
},
{
"match": "[^%]+",
"name": "string.unquoted.batchfile"
}
]
}
]
}
]
}
]
},
"variable_delayed_expansion": {
"patterns": [
{
"begin": "!(?=[^!]+!)",
"beginCaptures": {
"0": {
"name": "punctuation.definition.variable.begin.batchfile"
}
},
"end": "(!)|\\n",
"endCaptures": {
"1": {
"name": "punctuation.definition.variable.end.batchfile"
}
},
"name": "variable.other.readwrite.batchfile",
"patterns": [
{
"begin": ":~",
"beginCaptures": {
"0": {
"name": "punctuation.separator.batchfile"
}
},
"end": "(?=!|\\n)",
"name": "meta.variable.substring.batchfile",
"patterns": [
{
"include": "#variable_substring"
}
]
},
{
"begin": ":",
"beginCaptures": {
"0": {
"name": "punctuation.separator.batchfile"
}
},
"end": "(?=!|\\n)",
"name": "meta.variable.substitution.batchfile",
"patterns": [
{
"include": "#escaped_characters"
},
{
"include": "#variable_replace"
},
{
"include": "#variable"
},
{
"begin": "=",
"beginCaptures": {
"0": {
"name": "punctuation.separator.batchfile"
}
},
"end": "(?=!|\\n)",
"patterns": [
{
"include": "#variable"
},
{
"match": "[^!]+",
"name": "string.unquoted.batchfile"
}
]
}
]
}
]
}
]
},
"variable_replace": {
"patterns": [
{
"match": "[^=%!\\n]+",
"name": "string.unquoted.batchfile"
}
]
},
"variable_substring": {
"patterns": [
{
"match": "([+-]?\\d+)(?:(,)([+-]?\\d+))?",
"captures": {
"1": {
"name": "constant.numeric.batchfile"
},
"2": {
"name": "punctuation.separator.batchfile"
},
"3": {
"name": "constant.numeric.batchfile"
}
}
}
]
}
}
}

View File

@@ -1,18 +1,18 @@
[ [
{ {
"c": "@", "c": "@",
"t": "source.dosbatch", "t": "source.batchfile keyword.operator.at.batchfile",
"r": { "r": {
"dark_plus": "default: #D4D4D4", "dark_plus": "keyword.operator: #D4D4D4",
"light_plus": "default: #000000", "light_plus": "keyword.operator: #000000",
"dark_vs": "default: #D4D4D4", "dark_vs": "keyword.operator: #D4D4D4",
"light_vs": "default: #000000", "light_vs": "keyword.operator: #000000",
"hc_black": "default: #FFFFFF" "hc_black": "keyword.operator: #D4D4D4"
} }
}, },
{ {
"c": "echo", "c": "echo",
"t": "source.dosbatch keyword.command.dosbatch", "t": "source.batchfile keyword.command.batchfile",
"r": { "r": {
"dark_plus": "keyword: #569CD6", "dark_plus": "keyword: #569CD6",
"light_plus": "keyword: #0000FF", "light_plus": "keyword: #0000FF",
@@ -23,7 +23,7 @@
}, },
{ {
"c": " off", "c": " off",
"t": "source.dosbatch", "t": "source.batchfile",
"r": { "r": {
"dark_plus": "default: #D4D4D4", "dark_plus": "default: #D4D4D4",
"light_plus": "default: #000000", "light_plus": "default: #000000",
@@ -34,7 +34,7 @@
}, },
{ {
"c": "setlocal", "c": "setlocal",
"t": "source.dosbatch keyword.command.dosbatch", "t": "source.batchfile keyword.command.batchfile",
"r": { "r": {
"dark_plus": "keyword: #569CD6", "dark_plus": "keyword: #569CD6",
"light_plus": "keyword: #0000FF", "light_plus": "keyword: #0000FF",
@@ -45,7 +45,7 @@
}, },
{ {
"c": "title", "c": "title",
"t": "source.dosbatch keyword.command.dosbatch", "t": "source.batchfile keyword.command.batchfile",
"r": { "r": {
"dark_plus": "keyword: #569CD6", "dark_plus": "keyword: #569CD6",
"light_plus": "keyword: #0000FF", "light_plus": "keyword: #0000FF",
@@ -56,7 +56,7 @@
}, },
{ {
"c": " VSCode Dev", "c": " VSCode Dev",
"t": "source.dosbatch", "t": "source.batchfile",
"r": { "r": {
"dark_plus": "default: #D4D4D4", "dark_plus": "default: #D4D4D4",
"light_plus": "default: #000000", "light_plus": "default: #000000",
@@ -67,7 +67,7 @@
}, },
{ {
"c": "pushd", "c": "pushd",
"t": "source.dosbatch keyword.command.dosbatch", "t": "source.batchfile keyword.command.batchfile",
"r": { "r": {
"dark_plus": "keyword: #569CD6", "dark_plus": "keyword: #569CD6",
"light_plus": "keyword: #0000FF", "light_plus": "keyword: #0000FF",
@@ -78,7 +78,7 @@
}, },
{ {
"c": " ", "c": " ",
"t": "source.dosbatch", "t": "source.batchfile",
"r": { "r": {
"dark_plus": "default: #D4D4D4", "dark_plus": "default: #D4D4D4",
"light_plus": "default: #000000", "light_plus": "default: #000000",
@@ -89,7 +89,7 @@
}, },
{ {
"c": "%", "c": "%",
"t": "source.dosbatch variable.parameter.function.dosbatch variable.parameter.function.begin.shell", "t": "source.batchfile variable.parameter.batchfile punctuation.definition.variable.batchfile",
"r": { "r": {
"dark_plus": "variable: #9CDCFE", "dark_plus": "variable: #9CDCFE",
"light_plus": "variable: #001080", "light_plus": "variable: #001080",
@@ -100,7 +100,7 @@
}, },
{ {
"c": "~dp0", "c": "~dp0",
"t": "source.dosbatch variable.parameter.function.dosbatch", "t": "source.batchfile variable.parameter.batchfile",
"r": { "r": {
"dark_plus": "variable: #9CDCFE", "dark_plus": "variable: #9CDCFE",
"light_plus": "variable: #001080", "light_plus": "variable: #001080",
@@ -111,7 +111,7 @@
}, },
{ {
"c": "\\..", "c": "\\..",
"t": "source.dosbatch", "t": "source.batchfile",
"r": { "r": {
"dark_plus": "default: #D4D4D4", "dark_plus": "default: #D4D4D4",
"light_plus": "default: #000000", "light_plus": "default: #000000",
@@ -121,8 +121,8 @@
} }
}, },
{ {
"c": ":: Node modules", "c": "::",
"t": "source.dosbatch comment.line.colons.dosbatch", "t": "source.batchfile comment.line.colon.batchfile punctuation.definition.comment.batchfile",
"r": { "r": {
"dark_plus": "comment: #608B4E", "dark_plus": "comment: #608B4E",
"light_plus": "comment: #008000", "light_plus": "comment: #008000",
@@ -132,8 +132,19 @@
} }
}, },
{ {
"c": "if not exist", "c": " Node modules",
"t": "source.dosbatch keyword.control.conditional.if.dosbatch", "t": "source.batchfile comment.line.colon.batchfile",
"r": {
"dark_plus": "comment: #608B4E",
"light_plus": "comment: #008000",
"dark_vs": "comment: #608B4E",
"light_vs": "comment: #008000",
"hc_black": "comment: #7CA668"
}
},
{
"c": "if",
"t": "source.batchfile keyword.control.conditional.batchfile",
"r": { "r": {
"dark_plus": "keyword.control: #C586C0", "dark_plus": "keyword.control: #C586C0",
"light_plus": "keyword.control: #AF00DB", "light_plus": "keyword.control: #AF00DB",
@@ -142,9 +153,53 @@
"hc_black": "keyword.control: #C586C0" "hc_black": "keyword.control: #C586C0"
} }
}, },
{
"c": " ",
"t": "source.batchfile",
"r": {
"dark_plus": "default: #D4D4D4",
"light_plus": "default: #000000",
"dark_vs": "default: #D4D4D4",
"light_vs": "default: #000000",
"hc_black": "default: #FFFFFF"
}
},
{
"c": "not",
"t": "source.batchfile keyword.operator.logical.batchfile",
"r": {
"dark_plus": "keyword.operator: #D4D4D4",
"light_plus": "keyword.operator: #000000",
"dark_vs": "keyword.operator: #D4D4D4",
"light_vs": "keyword.operator: #000000",
"hc_black": "keyword.operator: #D4D4D4"
}
},
{
"c": " ",
"t": "source.batchfile",
"r": {
"dark_plus": "default: #D4D4D4",
"light_plus": "default: #000000",
"dark_vs": "default: #D4D4D4",
"light_vs": "default: #000000",
"hc_black": "default: #FFFFFF"
}
},
{
"c": "exist",
"t": "source.batchfile keyword.other.special-method.batchfile",
"r": {
"dark_plus": "keyword: #569CD6",
"light_plus": "keyword: #0000FF",
"dark_vs": "keyword: #569CD6",
"light_vs": "keyword: #0000FF",
"hc_black": "keyword: #569CD6"
}
},
{ {
"c": " node_modules ", "c": " node_modules ",
"t": "source.dosbatch", "t": "source.batchfile",
"r": { "r": {
"dark_plus": "default: #D4D4D4", "dark_plus": "default: #D4D4D4",
"light_plus": "default: #000000", "light_plus": "default: #000000",
@@ -155,7 +210,7 @@
}, },
{ {
"c": "call", "c": "call",
"t": "source.dosbatch keyword.control.statement.dosbatch", "t": "source.batchfile keyword.control.statement.batchfile",
"r": { "r": {
"dark_plus": "keyword.control: #C586C0", "dark_plus": "keyword.control: #C586C0",
"light_plus": "keyword.control: #AF00DB", "light_plus": "keyword.control: #AF00DB",
@@ -166,7 +221,7 @@
}, },
{ {
"c": " .\\scripts\\npm.bat install", "c": " .\\scripts\\npm.bat install",
"t": "source.dosbatch", "t": "source.batchfile",
"r": { "r": {
"dark_plus": "default: #D4D4D4", "dark_plus": "default: #D4D4D4",
"light_plus": "default: #000000", "light_plus": "default: #000000",
@@ -176,8 +231,19 @@
} }
}, },
{ {
"c": ":: Get electron", "c": "::",
"t": "source.dosbatch comment.line.colons.dosbatch", "t": "source.batchfile comment.line.colon.batchfile punctuation.definition.comment.batchfile",
"r": {
"dark_plus": "comment: #608B4E",
"light_plus": "comment: #008000",
"dark_vs": "comment: #608B4E",
"light_vs": "comment: #008000",
"hc_black": "comment: #7CA668"
}
},
{
"c": " Get electron",
"t": "source.batchfile comment.line.colon.batchfile",
"r": { "r": {
"dark_plus": "comment: #608B4E", "dark_plus": "comment: #608B4E",
"light_plus": "comment: #008000", "light_plus": "comment: #008000",
@@ -188,7 +254,7 @@
}, },
{ {
"c": "node .\\node_modules\\gulp\\bin\\gulp.js electron", "c": "node .\\node_modules\\gulp\\bin\\gulp.js electron",
"t": "source.dosbatch", "t": "source.batchfile",
"r": { "r": {
"dark_plus": "default: #D4D4D4", "dark_plus": "default: #D4D4D4",
"light_plus": "default: #000000", "light_plus": "default: #000000",
@@ -198,8 +264,8 @@
} }
}, },
{ {
"c": ":: Build", "c": "::",
"t": "source.dosbatch comment.line.colons.dosbatch", "t": "source.batchfile comment.line.colon.batchfile punctuation.definition.comment.batchfile",
"r": { "r": {
"dark_plus": "comment: #608B4E", "dark_plus": "comment: #608B4E",
"light_plus": "comment: #008000", "light_plus": "comment: #008000",
@@ -209,8 +275,19 @@
} }
}, },
{ {
"c": "if not exist", "c": " Build",
"t": "source.dosbatch keyword.control.conditional.if.dosbatch", "t": "source.batchfile comment.line.colon.batchfile",
"r": {
"dark_plus": "comment: #608B4E",
"light_plus": "comment: #008000",
"dark_vs": "comment: #608B4E",
"light_vs": "comment: #008000",
"hc_black": "comment: #7CA668"
}
},
{
"c": "if",
"t": "source.batchfile keyword.control.conditional.batchfile",
"r": { "r": {
"dark_plus": "keyword.control: #C586C0", "dark_plus": "keyword.control: #C586C0",
"light_plus": "keyword.control: #AF00DB", "light_plus": "keyword.control: #AF00DB",
@@ -220,8 +297,8 @@
} }
}, },
{ {
"c": " out node .\\node_modules\\gulp\\bin\\gulp.js compile", "c": " ",
"t": "source.dosbatch", "t": "source.batchfile",
"r": { "r": {
"dark_plus": "default: #D4D4D4", "dark_plus": "default: #D4D4D4",
"light_plus": "default: #000000", "light_plus": "default: #000000",
@@ -231,8 +308,63 @@
} }
}, },
{ {
"c": ":: Configuration", "c": "not",
"t": "source.dosbatch comment.line.colons.dosbatch", "t": "source.batchfile keyword.operator.logical.batchfile",
"r": {
"dark_plus": "keyword.operator: #D4D4D4",
"light_plus": "keyword.operator: #000000",
"dark_vs": "keyword.operator: #D4D4D4",
"light_vs": "keyword.operator: #000000",
"hc_black": "keyword.operator: #D4D4D4"
}
},
{
"c": " ",
"t": "source.batchfile",
"r": {
"dark_plus": "default: #D4D4D4",
"light_plus": "default: #000000",
"dark_vs": "default: #D4D4D4",
"light_vs": "default: #000000",
"hc_black": "default: #FFFFFF"
}
},
{
"c": "exist",
"t": "source.batchfile keyword.other.special-method.batchfile",
"r": {
"dark_plus": "keyword: #569CD6",
"light_plus": "keyword: #0000FF",
"dark_vs": "keyword: #569CD6",
"light_vs": "keyword: #0000FF",
"hc_black": "keyword: #569CD6"
}
},
{
"c": " out node .\\node_modules\\gulp\\bin\\gulp.js compile",
"t": "source.batchfile",
"r": {
"dark_plus": "default: #D4D4D4",
"light_plus": "default: #000000",
"dark_vs": "default: #D4D4D4",
"light_vs": "default: #000000",
"hc_black": "default: #FFFFFF"
}
},
{
"c": "::",
"t": "source.batchfile comment.line.colon.batchfile punctuation.definition.comment.batchfile",
"r": {
"dark_plus": "comment: #608B4E",
"light_plus": "comment: #008000",
"dark_vs": "comment: #608B4E",
"light_vs": "comment: #008000",
"hc_black": "comment: #7CA668"
}
},
{
"c": " Configuration",
"t": "source.batchfile comment.line.colon.batchfile",
"r": { "r": {
"dark_plus": "comment: #608B4E", "dark_plus": "comment: #608B4E",
"light_plus": "comment: #008000", "light_plus": "comment: #008000",
@@ -243,7 +375,7 @@
}, },
{ {
"c": "set", "c": "set",
"t": "source.dosbatch keyword.command.dosbatch", "t": "source.batchfile keyword.command.batchfile",
"r": { "r": {
"dark_plus": "keyword: #569CD6", "dark_plus": "keyword: #569CD6",
"light_plus": "keyword: #0000FF", "light_plus": "keyword: #0000FF",
@@ -253,8 +385,41 @@
} }
}, },
{ {
"c": " NODE_ENV=development", "c": " ",
"t": "source.dosbatch", "t": "source.batchfile",
"r": {
"dark_plus": "default: #D4D4D4",
"light_plus": "default: #000000",
"dark_vs": "default: #D4D4D4",
"light_vs": "default: #000000",
"hc_black": "default: #FFFFFF"
}
},
{
"c": "NODE_ENV",
"t": "source.batchfile variable.other.readwrite.batchfile",
"r": {
"dark_plus": "variable: #9CDCFE",
"light_plus": "variable: #001080",
"dark_vs": "default: #D4D4D4",
"light_vs": "default: #000000",
"hc_black": "variable: #9CDCFE"
}
},
{
"c": "=",
"t": "source.batchfile keyword.operator.assignment.batchfile",
"r": {
"dark_plus": "keyword.operator: #D4D4D4",
"light_plus": "keyword.operator: #000000",
"dark_vs": "keyword.operator: #D4D4D4",
"light_vs": "keyword.operator: #000000",
"hc_black": "keyword.operator: #D4D4D4"
}
},
{
"c": "development",
"t": "source.batchfile",
"r": { "r": {
"dark_plus": "default: #D4D4D4", "dark_plus": "default: #D4D4D4",
"light_plus": "default: #000000", "light_plus": "default: #000000",
@@ -265,7 +430,7 @@
}, },
{ {
"c": "call", "c": "call",
"t": "source.dosbatch keyword.control.statement.dosbatch", "t": "source.batchfile keyword.control.statement.batchfile",
"r": { "r": {
"dark_plus": "keyword.control: #C586C0", "dark_plus": "keyword.control: #C586C0",
"light_plus": "keyword.control: #AF00DB", "light_plus": "keyword.control: #AF00DB",
@@ -276,7 +441,7 @@
}, },
{ {
"c": " ", "c": " ",
"t": "source.dosbatch", "t": "source.batchfile",
"r": { "r": {
"dark_plus": "default: #D4D4D4", "dark_plus": "default: #D4D4D4",
"light_plus": "default: #000000", "light_plus": "default: #000000",
@@ -287,7 +452,7 @@
}, },
{ {
"c": "echo", "c": "echo",
"t": "source.dosbatch keyword.command.dosbatch", "t": "source.batchfile keyword.command.batchfile",
"r": { "r": {
"dark_plus": "keyword: #569CD6", "dark_plus": "keyword: #569CD6",
"light_plus": "keyword: #0000FF", "light_plus": "keyword: #0000FF",
@@ -298,7 +463,7 @@
}, },
{ {
"c": " ", "c": " ",
"t": "source.dosbatch", "t": "source.batchfile",
"r": { "r": {
"dark_plus": "default: #D4D4D4", "dark_plus": "default: #D4D4D4",
"light_plus": "default: #000000", "light_plus": "default: #000000",
@@ -308,19 +473,41 @@
} }
}, },
{ {
"c": "%%LINE:rem +=%%", "c": "%%",
"t": "source.dosbatch variable.other.parsetime.dosbatch", "t": "source.batchfile constant.character.escape.batchfile",
"r": { "r": {
"dark_plus": "variable: #9CDCFE", "dark_plus": "constant.character.escape: #D7BA7D",
"light_plus": "variable: #001080", "light_plus": "constant.character.escape: #A31515",
"dark_vs": "default: #D4D4D4", "dark_vs": "default: #D4D4D4",
"light_vs": "default: #000000", "light_vs": "default: #000000",
"hc_black": "variable: #9CDCFE" "hc_black": "constant.character: #569CD6"
}
},
{
"c": "LINE:rem +=",
"t": "source.batchfile",
"r": {
"dark_plus": "default: #D4D4D4",
"light_plus": "default: #000000",
"dark_vs": "default: #D4D4D4",
"light_vs": "default: #000000",
"hc_black": "default: #FFFFFF"
}
},
{
"c": "%%",
"t": "source.batchfile constant.character.escape.batchfile",
"r": {
"dark_plus": "constant.character.escape: #D7BA7D",
"light_plus": "constant.character.escape: #A31515",
"dark_vs": "default: #D4D4D4",
"light_vs": "default: #000000",
"hc_black": "constant.character: #569CD6"
} }
}, },
{ {
"c": "popd", "c": "popd",
"t": "source.dosbatch keyword.command.dosbatch", "t": "source.batchfile keyword.command.batchfile",
"r": { "r": {
"dark_plus": "keyword: #569CD6", "dark_plus": "keyword: #569CD6",
"light_plus": "keyword: #0000FF", "light_plus": "keyword: #0000FF",
@@ -331,7 +518,7 @@
}, },
{ {
"c": "endlocal", "c": "endlocal",
"t": "source.dosbatch keyword.command.dosbatch", "t": "source.batchfile keyword.command.batchfile",
"r": { "r": {
"dark_plus": "keyword: #569CD6", "dark_plus": "keyword: #569CD6",
"light_plus": "keyword: #0000FF", "light_plus": "keyword: #0000FF",

View File

@@ -1,4 +1,3 @@
test/** test/**
src/** src/**
tsconfig.json tsconfig.json
npm-shrinkwrap.json

View File

@@ -10,7 +10,7 @@
"Other" "Other"
], ],
"activationEvents": [ "activationEvents": [
"onLanguage:json" "onLanguage:json", "onLanguage:jsonc"
], ],
"main": "./out/extension", "main": "./out/extension",
"scripts": { "scripts": {

View File

@@ -14,12 +14,12 @@ import * as nls from 'vscode-nls';
const localize = nls.loadMessageBundle(); const localize = nls.loadMessageBundle();
const decoration = vscode.window.createTextEditorDecorationType({ const decoration = vscode.window.createTextEditorDecorationType({
color: '#b1b1b1' color: '#9e9e9e'
}); });
let pendingLaunchJsonDecoration: NodeJS.Timer; let pendingLaunchJsonDecoration: NodeJS.Timer;
export function activate(context): void { export function activate(context: vscode.ExtensionContext): void {
//keybindings.json command-suggestions //keybindings.json command-suggestions
context.subscriptions.push(registerKeybindingsCompletions()); context.subscriptions.push(registerKeybindingsCompletions());
@@ -60,7 +60,7 @@ function registerKeybindingsCompletions(): vscode.Disposable {
} }
function registerSettingsCompletions(): vscode.Disposable { function registerSettingsCompletions(): vscode.Disposable {
return vscode.languages.registerCompletionItemProvider({ language: 'json', pattern: '**/settings.json' }, { return vscode.languages.registerCompletionItemProvider({ language: 'jsonc', pattern: '**/settings.json' }, {
provideCompletionItems(document, position, token) { provideCompletionItems(document, position, token) {
return new SettingsDocument(document).provideCompletionItems(position, token); return new SettingsDocument(document).provideCompletionItems(position, token);
} }
@@ -173,7 +173,7 @@ function updateLaunchJsonDecorations(editor: vscode.TextEditor | undefined): voi
editor.setDecorations(decoration, ranges); editor.setDecorations(decoration, ranges);
} }
vscode.languages.registerDocumentSymbolProvider({ pattern: '**/launch.json', language: 'json' }, { vscode.languages.registerDocumentSymbolProvider({ pattern: '**/launch.json', language: 'jsonc' }, {
provideDocumentSymbols(document: vscode.TextDocument, token: vscode.CancellationToken): vscode.ProviderResult<vscode.SymbolInformation[]> { provideDocumentSymbols(document: vscode.TextDocument, token: vscode.CancellationToken): vscode.ProviderResult<vscode.SymbolInformation[]> {
const result: vscode.SymbolInformation[] = []; const result: vscode.SymbolInformation[] = [];
let name: string = ''; let name: string = '';

View File

@@ -149,20 +149,36 @@ export class SettingsDocument {
return Promise.resolve(completions); return Promise.resolve(completions);
} }
private provideLanguageCompletionItems(location: Location, range: vscode.Range, formatFunc: (string) => string = (l) => JSON.stringify(l)): vscode.ProviderResult<vscode.CompletionItem[]> { private provideLanguageCompletionItems(location: Location, range: vscode.Range, formatFunc: (string: string) => string = (l) => JSON.stringify(l)): vscode.ProviderResult<vscode.CompletionItem[]> {
return vscode.languages.getLanguages().then(languages => { return vscode.languages.getLanguages().then(languages => {
return languages.map(l => { const completionItems = [];
return this.newSimpleCompletionItem(formatFunc(l), range); const configuration = vscode.workspace.getConfiguration();
}); for (const language of languages) {
const inspect = configuration.inspect(`[${language}]`);
if (!inspect || !inspect.defaultValue) {
const item = new vscode.CompletionItem(formatFunc(language));
item.kind = vscode.CompletionItemKind.Property;
item.range = range;
completionItems.push(item);
}
}
return completionItems;
}); });
} }
private provideLanguageOverridesCompletionItems(location: Location, position: vscode.Position): vscode.ProviderResult<vscode.CompletionItem[]> { private provideLanguageOverridesCompletionItems(location: Location, position: vscode.Position): vscode.ProviderResult<vscode.CompletionItem[]> {
let range = this.document.getWordRangeAtPosition(position) || new vscode.Range(position, position);
const text = this.document.getText(range);
if (location.path.length === 0) { if (location.path.length === 0) {
let range = this.document.getWordRangeAtPosition(position, /^\s*\[.*]?/) || new vscode.Range(position, position);
let text = this.document.getText(range);
if (text && text.trim().startsWith('[')) {
range = new vscode.Range(new vscode.Position(range.start.line, range.start.character + text.indexOf('[')), range.end);
return this.provideLanguageCompletionItems(location, range, language => `"[${language}]"`);
}
range = this.document.getWordRangeAtPosition(position) || new vscode.Range(position, position);
text = this.document.getText(range);
let snippet = '"[${1:language}]": {\n\t"$0"\n}'; let snippet = '"[${1:language}]": {\n\t"$0"\n}';
// Suggestion model word matching includes quotes, // Suggestion model word matching includes quotes,
@@ -184,6 +200,7 @@ export class SettingsDocument {
if (location.path.length === 1 && location.previousNode && typeof location.previousNode.value === 'string' && location.previousNode.value.startsWith('[')) { if (location.path.length === 1 && location.previousNode && typeof location.previousNode.value === 'string' && location.previousNode.value.startsWith('[')) {
// Suggestion model word matching includes closed sqaure bracket and ending quote // Suggestion model word matching includes closed sqaure bracket and ending quote
// Hence include them in the proposal to replace // Hence include them in the proposal to replace
let range = this.document.getWordRangeAtPosition(position) || new vscode.Range(position, position);
return this.provideLanguageCompletionItems(location, range, language => `"[${language}]"`); return this.provideLanguageCompletionItems(location, range, language => `"[${language}]"`);
} }
return Promise.resolve([]); return Promise.resolve([]);

View File

@@ -6,7 +6,7 @@
"lib": [ "lib": [
"es2015" "es2015"
], ],
"strictNullChecks": true "strict": true
}, },
"include": [ "include": [
"src/**/*" "src/**/*"

View File

@@ -0,0 +1,17 @@
# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY.
# yarn lockfile v1
"@types/node@7.0.4":
version "7.0.4"
resolved "https://registry.yarnpkg.com/@types/node/-/node-7.0.4.tgz#9aabc135979ded383325749f508894c662948c8b"
jsonc-parser@^0.3.1:
version "0.3.1"
resolved "https://registry.yarnpkg.com/jsonc-parser/-/jsonc-parser-0.3.1.tgz#6ebf5c75224368d4b07ef4c26f9434e657472e95"
dependencies:
vscode-nls "^2.0.2"
vscode-nls@^2.0.1, vscode-nls@^2.0.2:
version "2.0.2"
resolved "https://registry.yarnpkg.com/vscode-nls/-/vscode-nls-2.0.2.tgz#808522380844b8ad153499af5c3b03921aea02da"

View File

@@ -1,4 +1,3 @@
test/** test/**
src/** src/**
tsconfig.json tsconfig.json
npm-shrinkwrap.json

View File

@@ -47,6 +47,6 @@
}, },
"devDependencies": { "devDependencies": {
"@types/markdown-it": "0.0.2", "@types/markdown-it": "0.0.2",
"@types/node": "7.0.43" "@types/node": "6.0.78"
} }
} }

View File

@@ -17,7 +17,7 @@ export function activate(context: vscode.ExtensionContext) {
//package.json suggestions //package.json suggestions
context.subscriptions.push(registerPackageDocumentCompletions()); context.subscriptions.push(registerPackageDocumentCompletions());
context.subscriptions.push(new ExtensionLinter(context)); context.subscriptions.push(new ExtensionLinter());
} }
const _linkProvider = new class implements vscode.DocumentLinkProvider { const _linkProvider = new class implements vscode.DocumentLinkProvider {

View File

@@ -10,7 +10,7 @@ import { parseTree, findNodeAtLocation, Node as JsonNode } from 'jsonc-parser';
import * as nls from 'vscode-nls'; import * as nls from 'vscode-nls';
import * as MarkdownItType from 'markdown-it'; import * as MarkdownItType from 'markdown-it';
import { languages, workspace, Disposable, ExtensionContext, TextDocument, Uri, Diagnostic, Range, DiagnosticSeverity, Position } from 'vscode'; import { languages, workspace, Disposable, TextDocument, Uri, Diagnostic, Range, DiagnosticSeverity, Position } from 'vscode';
const product = require('../../../product.json'); const product = require('../../../product.json');
const allowedBadgeProviders: string[] = (product.extensionAllowedBadgeProviders || []).map(s => s.toLowerCase()); const allowedBadgeProviders: string[] = (product.extensionAllowedBadgeProviders || []).map(s => s.toLowerCase());
@@ -54,7 +54,7 @@ export class ExtensionLinter {
private timer: NodeJS.Timer; private timer: NodeJS.Timer;
private markdownIt: MarkdownItType.MarkdownIt; private markdownIt: MarkdownItType.MarkdownIt;
constructor(private context: ExtensionContext) { constructor() {
this.disposables.push( this.disposables.push(
workspace.onDidOpenTextDocument(document => this.queue(document)), workspace.onDidOpenTextDocument(document => this.queue(document)),
workspace.onDidChangeTextDocument(event => this.queue(event.document)), workspace.onDidChangeTextDocument(event => this.queue(event.document)),
@@ -227,7 +227,7 @@ export class ExtensionLinter {
} }
this.diagnosticsCollection.set(document.uri, diagnostics); this.diagnosticsCollection.set(document.uri, diagnostics);
}; }
} }
private locateToken(text: string, begin: number, end: number, token: MarkdownItType.Token, content: string) { private locateToken(text: string, begin: number, end: number, token: MarkdownItType.Token, content: string) {

View File

@@ -5,6 +5,7 @@
"es2015" "es2015"
], ],
"module": "commonjs", "module": "commonjs",
"noUnusedLocals": true,
"outDir": "./out" "outDir": "./out"
}, },
"include": [ "include": [

View File

@@ -0,0 +1,65 @@
# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY.
# yarn lockfile v1
"@types/markdown-it@0.0.2":
version "0.0.2"
resolved "https://registry.yarnpkg.com/@types/markdown-it/-/markdown-it-0.0.2.tgz#5d9ad19e6e6508cdd2f2596df86fd0aade598660"
"@types/node@6.0.78", "@types/node@^6.0.46":
version "6.0.78"
resolved "https://registry.yarnpkg.com/@types/node/-/node-6.0.78.tgz#5d4a3f579c1524e01ee21bf474e6fba09198f470"
argparse@^1.0.7:
version "1.0.9"
resolved "https://registry.yarnpkg.com/argparse/-/argparse-1.0.9.tgz#73d83bc263f86e97f8cc4f6bae1b0e90a7d22c86"
dependencies:
sprintf-js "~1.0.2"
entities@~1.1.1:
version "1.1.1"
resolved "https://registry.yarnpkg.com/entities/-/entities-1.1.1.tgz#6e5c2d0a5621b5dadaecef80b90edfb5cd7772f0"
jsonc-parser@^0.3.1:
version "0.3.1"
resolved "https://registry.yarnpkg.com/jsonc-parser/-/jsonc-parser-0.3.1.tgz#6ebf5c75224368d4b07ef4c26f9434e657472e95"
dependencies:
vscode-nls "^2.0.2"
linkify-it@^2.0.0:
version "2.0.3"
resolved "https://registry.yarnpkg.com/linkify-it/-/linkify-it-2.0.3.tgz#d94a4648f9b1c179d64fa97291268bdb6ce9434f"
dependencies:
uc.micro "^1.0.1"
markdown-it@^8.3.1:
version "8.3.1"
resolved "https://registry.yarnpkg.com/markdown-it/-/markdown-it-8.3.1.tgz#2f4b622948ccdc193d66f3ca2d43125ac4ac7323"
dependencies:
argparse "^1.0.7"
entities "~1.1.1"
linkify-it "^2.0.0"
mdurl "^1.0.1"
uc.micro "^1.0.3"
mdurl@^1.0.1:
version "1.0.1"
resolved "https://registry.yarnpkg.com/mdurl/-/mdurl-1.0.1.tgz#fe85b2ec75a59037f2adfec100fd6c601761152e"
parse5@^3.0.2:
version "3.0.2"
resolved "https://registry.yarnpkg.com/parse5/-/parse5-3.0.2.tgz#05eff57f0ef4577fb144a79f8b9a967a6cc44510"
dependencies:
"@types/node" "^6.0.46"
sprintf-js@~1.0.2:
version "1.0.3"
resolved "https://registry.yarnpkg.com/sprintf-js/-/sprintf-js-1.0.3.tgz#04e6926f662895354f3dd015203633b857297e2c"
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@^2.0.1, vscode-nls@^2.0.2:
version "2.0.2"
resolved "https://registry.yarnpkg.com/vscode-nls/-/vscode-nls-2.0.2.tgz#808522380844b8ad153499af5c3b03921aea02da"

View File

@@ -1,5 +1,4 @@
src/** src/**
test/** test/**
out/test/** out/test/**
tsconfig.json tsconfig.json
npm-shrinkwrap.json

View File

@@ -219,6 +219,11 @@
"title": "%command.deleteBranch%", "title": "%command.deleteBranch%",
"category": "Git" "category": "Git"
}, },
{
"command": "git.renameBranch",
"title": "%command.renameBranch%",
"category": "Git"
},
{ {
"command": "git.merge", "command": "git.merge",
"title": "%command.merge%", "title": "%command.merge%",
@@ -229,6 +234,11 @@
"title": "%command.createTag%", "title": "%command.createTag%",
"category": "Git" "category": "Git"
}, },
{
"command": "git.fetch",
"title": "%command.fetch%",
"category": "Git"
},
{ {
"command": "git.pull", "command": "git.pull",
"title": "%command.pull%", "title": "%command.pull%",
@@ -264,6 +274,11 @@
"title": "%command.sync%", "title": "%command.sync%",
"category": "Git" "category": "Git"
}, },
{
"command": "git.syncRebase",
"title": "%command.syncRebase%",
"category": "Git"
},
{ {
"command": "git.publish", "command": "git.publish",
"title": "%command.publish%", "title": "%command.publish%",
@@ -279,6 +294,11 @@
"title": "%command.ignore%", "title": "%command.ignore%",
"category": "Git" "category": "Git"
}, },
{
"command": "git.stashIncludeUntracked",
"title": "%command.stashIncludeUntracked%",
"category": "Git"
},
{ {
"command": "git.stash", "command": "git.stash",
"title": "%command.stash%", "title": "%command.stash%",
@@ -305,33 +325,37 @@
"command": "git.init", "command": "git.init",
"when": "config.git.enabled" "when": "config.git.enabled"
}, },
{
"command": "git.close",
"when": "gitOpenRepositoryCount != 0"
},
{ {
"command": "git.refresh", "command": "git.refresh",
"when": "config.git.enabled && gitOpenRepositoryCount != 0" "when": "gitOpenRepositoryCount != 0"
}, },
{ {
"command": "git.openFile", "command": "git.openFile",
"when": "config.git.enabled && gitOpenRepositoryCount != 0" "when": "gitOpenRepositoryCount != 0"
}, },
{ {
"command": "git.openHEADFile", "command": "git.openHEADFile",
"when": "config.git.enabled && gitOpenRepositoryCount != 0" "when": "gitOpenRepositoryCount != 0"
}, },
{ {
"command": "git.openChange", "command": "git.openChange",
"when": "config.git.enabled && gitOpenRepositoryCount != 0" "when": "gitOpenRepositoryCount != 0"
}, },
{ {
"command": "git.stage", "command": "git.stage",
"when": "config.git.enabled && gitOpenRepositoryCount != 0" "when": "gitOpenRepositoryCount != 0"
}, },
{ {
"command": "git.stageAll", "command": "git.stageAll",
"when": "config.git.enabled && gitOpenRepositoryCount != 0" "when": "gitOpenRepositoryCount != 0"
}, },
{ {
"command": "git.stageSelectedRanges", "command": "git.stageSelectedRanges",
"when": "config.git.enabled && gitOpenRepositoryCount != 0" "when": "gitOpenRepositoryCount != 0"
}, },
{ {
"command": "git.stageChange", "command": "git.stageChange",
@@ -339,7 +363,7 @@
}, },
{ {
"command": "git.revertSelectedRanges", "command": "git.revertSelectedRanges",
"when": "config.git.enabled && gitOpenRepositoryCount != 0" "when": "gitOpenRepositoryCount != 0"
}, },
{ {
"command": "git.revertChange", "command": "git.revertChange",
@@ -347,378 +371,404 @@
}, },
{ {
"command": "git.unstage", "command": "git.unstage",
"when": "config.git.enabled && gitOpenRepositoryCount != 0" "when": "gitOpenRepositoryCount != 0"
}, },
{ {
"command": "git.unstageAll", "command": "git.unstageAll",
"when": "config.git.enabled && gitOpenRepositoryCount != 0" "when": "gitOpenRepositoryCount != 0"
}, },
{ {
"command": "git.unstageSelectedRanges", "command": "git.unstageSelectedRanges",
"when": "config.git.enabled && gitOpenRepositoryCount != 0" "when": "gitOpenRepositoryCount != 0"
}, },
{ {
"command": "git.clean", "command": "git.clean",
"when": "config.git.enabled && gitOpenRepositoryCount != 0" "when": "gitOpenRepositoryCount != 0"
}, },
{ {
"command": "git.cleanAll", "command": "git.cleanAll",
"when": "config.git.enabled && gitOpenRepositoryCount != 0" "when": "gitOpenRepositoryCount != 0"
}, },
{ {
"command": "git.commit", "command": "git.commit",
"when": "config.git.enabled && gitOpenRepositoryCount != 0" "when": "gitOpenRepositoryCount != 0"
}, },
{ {
"command": "git.commitStaged", "command": "git.commitStaged",
"when": "config.git.enabled && gitOpenRepositoryCount != 0" "when": "gitOpenRepositoryCount != 0"
}, },
{ {
"command": "git.commitStagedSigned", "command": "git.commitStagedSigned",
"when": "config.git.enabled && gitOpenRepositoryCount != 0" "when": "gitOpenRepositoryCount != 0"
}, },
{ {
"command": "git.commitStagedAmend", "command": "git.commitStagedAmend",
"when": "config.git.enabled && gitOpenRepositoryCount != 0" "when": "gitOpenRepositoryCount != 0"
}, },
{ {
"command": "git.commitAll", "command": "git.commitAll",
"when": "config.git.enabled && gitOpenRepositoryCount != 0" "when": "gitOpenRepositoryCount != 0"
}, },
{ {
"command": "git.commitAllSigned", "command": "git.commitAllSigned",
"when": "config.git.enabled && gitOpenRepositoryCount != 0" "when": "gitOpenRepositoryCount != 0"
}, },
{ {
"command": "git.commitAllAmend", "command": "git.commitAllAmend",
"when": "config.git.enabled && gitOpenRepositoryCount != 0" "when": "gitOpenRepositoryCount != 0"
}, },
{ {
"command": "git.undoCommit", "command": "git.undoCommit",
"when": "config.git.enabled && gitOpenRepositoryCount != 0" "when": "gitOpenRepositoryCount != 0"
}, },
{ {
"command": "git.checkout", "command": "git.checkout",
"when": "config.git.enabled && gitOpenRepositoryCount != 0" "when": "gitOpenRepositoryCount != 0"
}, },
{ {
"command": "git.branch", "command": "git.branch",
"when": "config.git.enabled && gitOpenRepositoryCount != 0" "when": "gitOpenRepositoryCount != 0"
}, },
{ {
"command": "git.deleteBranch", "command": "git.deleteBranch",
"when": "config.git.enabled && gitOpenRepositoryCount != 0" "when": "gitOpenRepositoryCount != 0"
},
{
"command": "git.renameBranch",
"when": "gitOpenRepositoryCount != 0"
}, },
{ {
"command": "git.pull", "command": "git.pull",
"when": "config.git.enabled && gitOpenRepositoryCount != 0" "when": "gitOpenRepositoryCount != 0"
}, },
{ {
"command": "git.pullFrom", "command": "git.pullFrom",
"when": "config.git.enabled && gitOpenRepositoryCount != 0" "when": "gitOpenRepositoryCount != 0"
}, },
{ {
"command": "git.pullRebase", "command": "git.pullRebase",
"when": "config.git.enabled && gitOpenRepositoryCount != 0" "when": "gitOpenRepositoryCount != 0"
}, },
{ {
"command": "git.pullFrom", "command": "git.pullFrom",
"when": "config.git.enabled && gitOpenRepositoryCount != 0" "when": "gitOpenRepositoryCount != 0"
}, },
{ {
"command": "git.merge", "command": "git.merge",
"when": "config.git.enabled && gitOpenRepositoryCount != 0" "when": "gitOpenRepositoryCount != 0"
}, },
{ {
"command": "git.createTag", "command": "git.createTag",
"when": "config.git.enabled && gitOpenRepositoryCount != 0" "when": "gitOpenRepositoryCount != 0"
},
{
"command": "git.fetch",
"when": "gitOpenRepositoryCount != 0"
}, },
{ {
"command": "git.push", "command": "git.push",
"when": "config.git.enabled && gitOpenRepositoryCount != 0" "when": "gitOpenRepositoryCount != 0"
}, },
{ {
"command": "git.pushTo", "command": "git.pushTo",
"when": "config.git.enabled && gitOpenRepositoryCount != 0" "when": "gitOpenRepositoryCount != 0"
}, },
{ {
"command": "git.pushWithTags", "command": "git.pushWithTags",
"when": "config.git.enabled && gitOpenRepositoryCount != 0" "when": "gitOpenRepositoryCount != 0"
}, },
{ {
"command": "git.sync", "command": "git.sync",
"when": "config.git.enabled && gitOpenRepositoryCount != 0" "when": "gitOpenRepositoryCount != 0"
},
{
"command": "git.syncRebase",
"when": "gitOpenRepositoryCount != 0"
}, },
{ {
"command": "git.publish", "command": "git.publish",
"when": "config.git.enabled && gitOpenRepositoryCount != 0" "when": "gitOpenRepositoryCount != 0"
}, },
{ {
"command": "git.showOutput", "command": "git.showOutput",
"when": "config.git.enabled && gitOpenRepositoryCount != 0" "when": "gitOpenRepositoryCount != 0"
}, },
{ {
"command": "git.ignore", "command": "git.ignore",
"when": "config.git.enabled && gitOpenRepositoryCount != 0" "when": "gitOpenRepositoryCount != 0"
},
{
"command": "git.stashIncludeUntracked",
"when": "gitOpenRepositoryCount != 0"
}, },
{ {
"command": "git.stash", "command": "git.stash",
"when": "config.git.enabled && gitOpenRepositoryCount != 0" "when": "gitOpenRepositoryCount != 0"
}, },
{ {
"command": "git.stashPop", "command": "git.stashPop",
"when": "config.git.enabled && gitOpenRepositoryCount != 0" "when": "gitOpenRepositoryCount != 0"
}, },
{ {
"command": "git.stashPopLatest", "command": "git.stashPopLatest",
"when": "config.git.enabled && gitOpenRepositoryCount != 0" "when": "gitOpenRepositoryCount != 0"
} }
], ],
"scm/title": [ "scm/title": [
{ {
"command": "git.init", "command": "git.init",
"group": "navigation", "group": "navigation",
"when": "config.git.enabled && !scmProvider && gitOpenRepositoryCount == 0" "when": "config.git.enabled && !scmProvider && gitOpenRepositoryCount == 0 && workspaceFolderCount != 0"
}, },
{ {
"command": "git.commit", "command": "git.commit",
"group": "navigation", "group": "navigation",
"when": "config.git.enabled && scmProvider == git" "when": "scmProvider == git"
}, },
{ {
"command": "git.refresh", "command": "git.refresh",
"group": "navigation", "group": "navigation",
"when": "config.git.enabled && scmProvider == git" "when": "scmProvider == git"
}, },
{ {
"command": "git.sync", "command": "git.sync",
"group": "1_sync", "group": "1_sync",
"when": "config.git.enabled && scmProvider == git" "when": "scmProvider == git"
},
{
"command": "git.syncRebase",
"group": "1_sync",
"when": "scmProvider == git && gitState == idle"
}, },
{ {
"command": "git.pull", "command": "git.pull",
"group": "1_sync", "group": "1_sync",
"when": "config.git.enabled && scmProvider == git" "when": "scmProvider == git"
}, },
{ {
"command": "git.pullRebase", "command": "git.pullRebase",
"group": "1_sync", "group": "1_sync",
"when": "config.git.enabled && scmProvider == git" "when": "scmProvider == git"
}, },
{ {
"command": "git.pullFrom", "command": "git.pullFrom",
"group": "1_sync", "group": "1_sync",
"when": "config.git.enabled && scmProvider == git" "when": "scmProvider == git"
}, },
{ {
"command": "git.push", "command": "git.push",
"group": "1_sync", "group": "1_sync",
"when": "config.git.enabled && scmProvider == git" "when": "scmProvider == git"
}, },
{ {
"command": "git.pushTo", "command": "git.pushTo",
"group": "1_sync", "group": "1_sync",
"when": "config.git.enabled && scmProvider == git" "when": "scmProvider == git"
}, },
{ {
"command": "git.publish", "command": "git.publish",
"group": "2_publish", "group": "2_publish",
"when": "config.git.enabled && scmProvider == git" "when": "scmProvider == git"
}, },
{ {
"command": "git.commitStaged", "command": "git.commitStaged",
"group": "3_commit", "group": "3_commit",
"when": "config.git.enabled && scmProvider == git" "when": "scmProvider == git"
}, },
{ {
"command": "git.commitStagedSigned", "command": "git.commitStagedSigned",
"group": "3_commit", "group": "3_commit",
"when": "config.git.enabled && scmProvider == git" "when": "scmProvider == git"
}, },
{ {
"command": "git.commitStagedAmend", "command": "git.commitStagedAmend",
"group": "3_commit", "group": "3_commit",
"when": "config.git.enabled && scmProvider == git" "when": "scmProvider == git"
}, },
{ {
"command": "git.commitAll", "command": "git.commitAll",
"group": "3_commit", "group": "3_commit",
"when": "config.git.enabled && scmProvider == git" "when": "scmProvider == git"
}, },
{ {
"command": "git.commitAllSigned", "command": "git.commitAllSigned",
"group": "3_commit", "group": "3_commit",
"when": "config.git.enabled && scmProvider == git" "when": "scmProvider == git"
}, },
{ {
"command": "git.commitAllAmend", "command": "git.commitAllAmend",
"group": "3_commit", "group": "3_commit",
"when": "config.git.enabled && scmProvider == git" "when": "scmProvider == git"
}, },
{ {
"command": "git.undoCommit", "command": "git.undoCommit",
"group": "3_commit", "group": "3_commit",
"when": "config.git.enabled && scmProvider == git" "when": "scmProvider == git"
}, },
{ {
"command": "git.stageAll", "command": "git.stageAll",
"group": "4_stage", "group": "4_stage",
"when": "config.git.enabled && scmProvider == git" "when": "scmProvider == git"
}, },
{ {
"command": "git.unstageAll", "command": "git.unstageAll",
"group": "4_stage", "group": "4_stage",
"when": "config.git.enabled && scmProvider == git" "when": "scmProvider == git"
}, },
{ {
"command": "git.cleanAll", "command": "git.cleanAll",
"group": "4_stage", "group": "4_stage",
"when": "config.git.enabled && scmProvider == git" "when": "scmProvider == git"
},
{
"command": "git.stashIncludeUntracked",
"group": "5_stash",
"when": "scmProvider == git"
}, },
{ {
"command": "git.stash", "command": "git.stash",
"group": "5_stash", "group": "5_stash",
"when": "config.git.enabled && scmProvider == git" "when": "scmProvider == git"
}, },
{ {
"command": "git.stashPop", "command": "git.stashPop",
"group": "5_stash", "group": "5_stash",
"when": "config.git.enabled && scmProvider == git" "when": "scmProvider == git"
}, },
{ {
"command": "git.stashPopLatest", "command": "git.stashPopLatest",
"group": "5_stash", "group": "5_stash",
"when": "config.git.enabled && scmProvider == git" "when": "scmProvider == git"
}, },
{ {
"command": "git.showOutput", "command": "git.showOutput",
"group": "7_repository", "group": "7_repository",
"when": "config.git.enabled && scmProvider == git" "when": "scmProvider == git"
} }
], ],
"scm/sourceControl": [ "scm/sourceControl": [
{ {
"command": "git.close", "command": "git.close",
"group": "navigation", "group": "navigation",
"when": "config.git.enabled && scmProvider == git" "when": "scmProvider == git"
} }
], ],
"scm/resourceGroup/context": [ "scm/resourceGroup/context": [
{ {
"command": "git.stageAll", "command": "git.stageAll",
"when": "config.git.enabled && scmProvider == git && scmResourceGroup == merge", "when": "scmProvider == git && scmResourceGroup == merge",
"group": "1_modification" "group": "1_modification"
}, },
{ {
"command": "git.stageAll", "command": "git.stageAll",
"when": "config.git.enabled && scmProvider == git && scmResourceGroup == merge", "when": "scmProvider == git && scmResourceGroup == merge",
"group": "inline" "group": "inline"
}, },
{ {
"command": "git.unstageAll", "command": "git.unstageAll",
"when": "config.git.enabled && scmProvider == git && scmResourceGroup == index", "when": "scmProvider == git && scmResourceGroup == index",
"group": "1_modification" "group": "1_modification"
}, },
{ {
"command": "git.unstageAll", "command": "git.unstageAll",
"when": "config.git.enabled && scmProvider == git && scmResourceGroup == index", "when": "scmProvider == git && scmResourceGroup == index",
"group": "inline" "group": "inline"
}, },
{ {
"command": "git.cleanAll", "command": "git.cleanAll",
"when": "config.git.enabled && scmProvider == git && scmResourceGroup == workingTree", "when": "scmProvider == git && scmResourceGroup == workingTree",
"group": "1_modification" "group": "1_modification"
}, },
{ {
"command": "git.stageAll", "command": "git.stageAll",
"when": "config.git.enabled && scmProvider == git && scmResourceGroup == workingTree", "when": "scmProvider == git && scmResourceGroup == workingTree",
"group": "1_modification" "group": "1_modification"
}, },
{ {
"command": "git.cleanAll", "command": "git.cleanAll",
"when": "config.git.enabled && scmProvider == git && scmResourceGroup == workingTree", "when": "scmProvider == git && scmResourceGroup == workingTree",
"group": "inline" "group": "inline"
}, },
{ {
"command": "git.stageAll", "command": "git.stageAll",
"when": "config.git.enabled && scmProvider == git && scmResourceGroup == workingTree", "when": "scmProvider == git && scmResourceGroup == workingTree",
"group": "inline" "group": "inline"
} }
], ],
"scm/resourceState/context": [ "scm/resourceState/context": [
{ {
"command": "git.stage", "command": "git.stage",
"when": "config.git.enabled && scmProvider == git && scmResourceGroup == merge", "when": "scmProvider == git && scmResourceGroup == merge",
"group": "1_modification" "group": "1_modification"
}, },
{ {
"command": "git.stage", "command": "git.stage",
"when": "config.git.enabled && scmProvider == git && scmResourceGroup == merge", "when": "scmProvider == git && scmResourceGroup == merge",
"group": "inline" "group": "inline"
}, },
{ {
"command": "git.openChange", "command": "git.openChange",
"when": "config.git.enabled && scmProvider == git && scmResourceGroup == index", "when": "scmProvider == git && scmResourceGroup == index",
"group": "navigation" "group": "navigation"
}, },
{ {
"command": "git.openFile", "command": "git.openFile",
"when": "config.git.enabled && scmProvider == git && scmResourceGroup == index", "when": "scmProvider == git && scmResourceGroup == index",
"group": "navigation" "group": "navigation"
}, },
{ {
"command": "git.openHEADFile", "command": "git.openHEADFile",
"when": "config.git.enabled && scmProvider == git && scmResourceGroup == index", "when": "scmProvider == git && scmResourceGroup == index",
"group": "navigation" "group": "navigation"
}, },
{ {
"command": "git.unstage", "command": "git.unstage",
"when": "config.git.enabled && scmProvider == git && scmResourceGroup == index", "when": "scmProvider == git && scmResourceGroup == index",
"group": "1_modification" "group": "1_modification"
}, },
{ {
"command": "git.unstage", "command": "git.unstage",
"when": "config.git.enabled && scmProvider == git && scmResourceGroup == index", "when": "scmProvider == git && scmResourceGroup == index",
"group": "inline" "group": "inline"
}, },
{ {
"command": "git.openChange", "command": "git.openChange",
"when": "config.git.enabled && scmProvider == git && scmResourceGroup == workingTree", "when": "scmProvider == git && scmResourceGroup == workingTree",
"group": "navigation" "group": "navigation"
}, },
{ {
"command": "git.openHEADFile", "command": "git.openHEADFile",
"when": "config.git.enabled && scmProvider == git && scmResourceGroup == workingTree", "when": "scmProvider == git && scmResourceGroup == workingTree",
"group": "navigation" "group": "navigation"
}, },
{ {
"command": "git.openFile", "command": "git.openFile",
"when": "config.git.enabled && scmProvider == git && scmResourceGroup == workingTree", "when": "scmProvider == git && scmResourceGroup == workingTree",
"group": "navigation" "group": "navigation"
}, },
{ {
"command": "git.stage", "command": "git.stage",
"when": "config.git.enabled && scmProvider == git && scmResourceGroup == workingTree", "when": "scmProvider == git && scmResourceGroup == workingTree",
"group": "1_modification" "group": "1_modification"
}, },
{ {
"command": "git.clean", "command": "git.clean",
"when": "config.git.enabled && scmProvider == git && scmResourceGroup == workingTree", "when": "scmProvider == git && scmResourceGroup == workingTree",
"group": "1_modification" "group": "1_modification"
}, },
{ {
"command": "git.clean", "command": "git.clean",
"when": "config.git.enabled && scmProvider == git && scmResourceGroup == workingTree", "when": "scmProvider == git && scmResourceGroup == workingTree",
"group": "inline" "group": "inline"
}, },
{ {
"command": "git.stage", "command": "git.stage",
"when": "config.git.enabled && scmProvider == git && scmResourceGroup == workingTree", "when": "scmProvider == git && scmResourceGroup == workingTree",
"group": "inline" "group": "inline"
}, },
{ {
"command": "git.ignore", "command": "git.ignore",
"when": "config.git.enabled && scmProvider == git && scmResourceGroup == workingTree", "when": "scmProvider == git && scmResourceGroup == workingTree",
"group": "1_modification@3" "group": "1_modification@3"
} }
], ],
@@ -726,37 +776,37 @@
{ {
"command": "git.openFile", "command": "git.openFile",
"group": "navigation", "group": "navigation",
"when": "config.git.enabled && gitOpenRepositoryCount != 0 && isInDiffEditor && resourceScheme != extension && resourceScheme != merge-conflict.conflict-diff" "when": "gitOpenRepositoryCount != 0 && isInDiffEditor && resourceScheme != extension && resourceScheme != merge-conflict.conflict-diff"
}, },
{ {
"command": "git.openChange", "command": "git.openChange",
"group": "navigation", "group": "navigation",
"when": "config.git.enabled && gitOpenRepositoryCount != 0 && !isInDiffEditor && resourceScheme == file" "when": "gitOpenRepositoryCount != 0 && !isInDiffEditor && resourceScheme == file"
}, },
{ {
"command": "git.stageSelectedRanges", "command": "git.stageSelectedRanges",
"group": "2_git@1", "group": "2_git@1",
"when": "config.git.enabled && gitOpenRepositoryCount != 0 && isInDiffEditor && resourceScheme != merge-conflict.conflict-diff" "when": "gitOpenRepositoryCount != 0 && isInDiffEditor && resourceScheme != merge-conflict.conflict-diff"
}, },
{ {
"command": "git.unstageSelectedRanges", "command": "git.unstageSelectedRanges",
"group": "2_git@2", "group": "2_git@2",
"when": "config.git.enabled && gitOpenRepositoryCount != 0 && isInDiffEditor && resourceScheme != merge-conflict.conflict-diff" "when": "gitOpenRepositoryCount != 0 && isInDiffEditor && resourceScheme != merge-conflict.conflict-diff"
}, },
{ {
"command": "git.revertSelectedRanges", "command": "git.revertSelectedRanges",
"group": "2_git@3", "group": "2_git@3",
"when": "config.git.enabled && gitOpenRepositoryCount != 0 && isInDiffEditor && resourceScheme != merge-conflict.conflict-diff" "when": "gitOpenRepositoryCount != 0 && isInDiffEditor && resourceScheme != merge-conflict.conflict-diff"
} }
], ],
"scm/change/title": [ "scm/change/title": [
{ {
"command": "git.stageChange", "command": "git.stageChange",
"when": "config.git.enabled && originalResourceScheme == git" "when": "originalResourceScheme == git"
}, },
{ {
"command": "git.revertChange", "command": "git.revertChange",
"when": "config.git.enabled && originalResourceScheme == git" "when": "originalResourceScheme == git"
} }
] ]
}, },
@@ -765,6 +815,7 @@
"properties": { "properties": {
"git.enabled": { "git.enabled": {
"type": "boolean", "type": "boolean",
"scope": "resource",
"description": "%config.enabled%", "description": "%config.enabled%",
"default": true "default": true
}, },
@@ -785,7 +836,7 @@
"git.autofetch": { "git.autofetch": {
"type": "boolean", "type": "boolean",
"description": "%config.autofetch%", "description": "%config.autofetch%",
"default": true "default": false
}, },
"git.confirmSync": { "git.confirmSync": {
"type": "boolean", "type": "boolean",
@@ -818,6 +869,11 @@
"description": "%config.ignoreLegacyWarning%", "description": "%config.ignoreLegacyWarning%",
"default": false "default": false
}, },
"git.ignoreMissingGitWarning": {
"type": "boolean",
"description": "%config.ignoreMissingGitWarning%",
"default": false
},
"git.ignoreLimitWarning": { "git.ignoreLimitWarning": {
"type": "boolean", "type": "boolean",
"description": "%config.ignoreLimitWarning%", "description": "%config.ignoreLimitWarning%",
@@ -895,13 +951,18 @@
}, },
"dependencies": { "dependencies": {
"byline": "^5.0.0", "byline": "^5.0.0",
"iconv-lite": "0.4.15", "file-type": "^7.2.0",
"iconv-lite": "0.4.19",
"vscode-extension-telemetry": "0.0.8", "vscode-extension-telemetry": "0.0.8",
"vscode-nls": "2.0.2" "vscode-nls": "2.0.2",
"which": "^1.3.0"
}, },
"devDependencies": { "devDependencies": {
"@types/byline": "4.2.31",
"@types/file-type": "^5.2.1",
"@types/mocha": "2.2.43", "@types/mocha": "2.2.43",
"@types/node": "7.0.43", "@types/node": "7.0.43",
"@types/which": "^1.0.28",
"mocha": "^3.2.0" "mocha": "^3.2.0"
} }
} }

View File

@@ -28,8 +28,10 @@
"command.checkout": "Checkout to...", "command.checkout": "Checkout to...",
"command.branch": "Create Branch...", "command.branch": "Create Branch...",
"command.deleteBranch": "Delete Branch...", "command.deleteBranch": "Delete Branch...",
"command.renameBranch": "Rename Branch...",
"command.merge": "Merge Branch...", "command.merge": "Merge Branch...",
"command.createTag": "Create Tag", "command.createTag": "Create Tag",
"command.fetch": "Fetch",
"command.pull": "Pull", "command.pull": "Pull",
"command.pullRebase": "Pull (Rebase)", "command.pullRebase": "Pull (Rebase)",
"command.pullFrom": "Pull from...", "command.pullFrom": "Pull from...",
@@ -37,9 +39,11 @@
"command.pushTo": "Push to...", "command.pushTo": "Push to...",
"command.pushWithTags": "Push With Tags", "command.pushWithTags": "Push With Tags",
"command.sync": "Sync", "command.sync": "Sync",
"command.syncRebase": "Sync (Rebase)",
"command.publish": "Publish Branch", "command.publish": "Publish Branch",
"command.showOutput": "Show Git Output", "command.showOutput": "Show Git Output",
"command.ignore": "Add File to .gitignore", "command.ignore": "Add File to .gitignore",
"command.stashIncludeUntracked": "Stash (Include Untracked)",
"command.stash": "Stash", "command.stash": "Stash",
"command.stashPop": "Pop Stash...", "command.stashPop": "Pop Stash...",
"command.stashPopLatest": "Pop Latest Stash", "command.stashPopLatest": "Pop Latest Stash",
@@ -52,6 +56,7 @@
"config.countBadge": "Controls the git badge counter. `all` counts all changes. `tracked` counts only the tracked changes. `off` turns it off.", "config.countBadge": "Controls the git badge counter. `all` counts all changes. `tracked` counts only the tracked changes. `off` turns it off.",
"config.checkoutType": "Controls what type of branches are listed when running `Checkout to...`. `all` shows all refs, `local` shows only the local branchs, `tags` shows only tags and `remote` shows only remote branches.", "config.checkoutType": "Controls what type of branches are listed when running `Checkout to...`. `all` shows all refs, `local` shows only the local branchs, `tags` shows only tags and `remote` shows only remote branches.",
"config.ignoreLegacyWarning": "Ignores the legacy Git warning", "config.ignoreLegacyWarning": "Ignores the legacy Git warning",
"config.ignoreMissingGitWarning": "Ignores the warning when Git is missing",
"config.ignoreLimitWarning": "Ignores the warning when there are too many changes in a repository", "config.ignoreLimitWarning": "Ignores the warning when there are too many changes in a repository",
"config.defaultCloneDirectory": "The default location where to clone a git repository", "config.defaultCloneDirectory": "The default location where to clone a git repository",
"config.enableSmartCommit": "Commit all changes when there are no staged changes.", "config.enableSmartCommit": "Commit all changes when there are no staged changes.",
@@ -63,4 +68,4 @@
"colors.untracked": "Color for untracked resources.", "colors.untracked": "Color for untracked resources.",
"colors.ignored": "Color for ignored resources.", "colors.ignored": "Color for ignored resources.",
"colors.conflict": "Color for resources with conflicts." "colors.conflict": "Color for resources with conflicts."
} }

View File

@@ -1 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="-0.994 0 16 16" enable-background="new -0.994 0 16 16"><path fill="#C5C5C5" d="M13 6c0 1.461-.636 2.846-1.746 3.797l-5.584 4.951-1.324-1.496 5.595-4.962c.678-.582 1.061-1.413 1.061-2.29 0-1.654-1.345-3-2.997-3-.71 0-1.399.253-1.938.713l-1.521 1.287h2.448l-1.998 2h-3.996v-4l1.998-2v2.692l1.775-1.504c.899-.766 2.047-1.188 3.232-1.188 2.754 0 4.995 2.243 4.995 5z"/></svg> <svg xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="-0.994 0 16 16" enable-background="new -0.994 0 16 16"><path fill="#C5C5C5" d="M13 6c0 1.461-.636 2.846-1.746 3.797l-5.584 4.951-1.324-1.496 5.595-4.962c.678-.582 1.061-1.413 1.061-2.29 0-1.654-1.345-3-2.997-3-.71 0-1.399.253-1.938.713l-1.521 1.287h2.448l-1.998 2h-3.996v-4l1.998-2v2.692l1.775-1.504c.899-.766 2.047-1.188 3.232-1.188 2.754 0 4.995 2.243 4.995 5z"/></svg>

Before

Width:  |  Height:  |  Size: 443 B

After

Width:  |  Height:  |  Size: 443 B

View File

@@ -1 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="-0.994 0 16 16" enable-background="new -0.994 0 16 16"><path fill="#424242" d="M13 6c0 1.461-.636 2.846-1.746 3.797l-5.584 4.951-1.324-1.496 5.595-4.962c.678-.582 1.061-1.413 1.061-2.29 0-1.654-1.345-3-2.997-3-.71 0-1.399.253-1.938.713l-1.521 1.287h2.448l-1.998 2h-3.996v-4l1.998-2v2.692l1.775-1.504c.899-.766 2.047-1.188 3.232-1.188 2.754 0 4.995 2.243 4.995 5z"/></svg> <svg xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="-0.994 0 16 16" enable-background="new -0.994 0 16 16"><path fill="#424242" d="M13 6c0 1.461-.636 2.846-1.746 3.797l-5.584 4.951-1.324-1.496 5.595-4.962c.678-.582 1.061-1.413 1.061-2.29 0-1.654-1.345-3-2.997-3-.71 0-1.399.253-1.938.713l-1.521 1.287h2.448l-1.998 2h-3.996v-4l1.998-2v2.692l1.775-1.504c.899-.766 2.047-1.188 3.232-1.188 2.754 0 4.995 2.243 4.995 5z"/></svg>

Before

Width:  |  Height:  |  Size: 443 B

After

Width:  |  Height:  |  Size: 443 B

42
extensions/git/src/api.ts Normal file
View File

@@ -0,0 +1,42 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the Source EULA. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
'use strict';
import { Model } from './model';
import { SourceControlInputBox, Uri } from 'vscode';
export interface InputBox {
value: string;
}
export interface Repository {
readonly rootUri: Uri;
readonly inputBox: InputBox;
}
export interface API {
getRepositories(): Promise<Repository[]>;
}
export function createApi(modelPromise: Promise<Model>) {
return {
async getRepositories(): Promise<Repository[]> {
const model = await modelPromise;
return model.repositories.map(repository => ({
rootUri: Uri.file(repository.root),
inputBox: {
set value(value: string) {
repository.inputBox.value = value;
},
get value(): string {
return repository.inputBox.value;
}
}
}));
}
};
}

View File

@@ -34,8 +34,8 @@ function main(argv: string[]): void {
return fatal('Skip fetch commands'); return fatal('Skip fetch commands');
} }
const output = process.env['VSCODE_GIT_ASKPASS_PIPE']; const output = process.env['VSCODE_GIT_ASKPASS_PIPE'] as string;
const socketPath = process.env['VSCODE_GIT_ASKPASS_HANDLE']; const socketPath = process.env['VSCODE_GIT_ASKPASS_HANDLE'] as string;
const request = argv[2]; const request = argv[2];
const host = argv[4].substring(1, argv[4].length - 2); const host = argv[4].substring(1, argv[4].length - 2);
const opts: http.RequestOptions = { const opts: http.RequestOptions = {

View File

@@ -28,7 +28,7 @@ function getIPCHandlePath(nonce: string): string {
} }
if (process.env['XDG_RUNTIME_DIR']) { if (process.env['XDG_RUNTIME_DIR']) {
return path.join(process.env['XDG_RUNTIME_DIR'], `vscode-git-askpass-${nonce}.sock`); return path.join(process.env['XDG_RUNTIME_DIR'] as string, `vscode-git-askpass-${nonce}.sock`);
} }
return path.join(os.tmpdir(), `vscode-git-askpass-${nonce}.sock`); return path.join(os.tmpdir(), `vscode-git-askpass-${nonce}.sock`);

View File

@@ -5,14 +5,22 @@
'use strict'; 'use strict';
import { workspace, Disposable, EventEmitter } from 'vscode'; import { workspace, Disposable, EventEmitter, Memento, window, MessageItem, ConfigurationTarget, commands, Uri } from 'vscode';
import { GitErrorCodes } from './git'; import { GitErrorCodes } from './git';
import { Repository } from './repository'; import { Repository, Operation } from './repository';
import { eventToPromise, filterEvent } from './util'; import { eventToPromise, filterEvent, onceEvent } from './util';
import * as nls from 'vscode-nls';
const localize = nls.loadMessageBundle();
function isRemoteOperation(operation: Operation): boolean {
return operation === Operation.Pull || operation === Operation.Push || operation === Operation.Sync || operation === Operation.Fetch;
}
export class AutoFetcher { export class AutoFetcher {
private static Period = 3 * 60 * 1000 /* three minutes */; private static readonly Period = 3 * 60 * 1000 /* three minutes */;
private static DidInformUser = 'autofetch.didInformUser';
private _onDidChange = new EventEmitter<boolean>(); private _onDidChange = new EventEmitter<boolean>();
private onDidChange = this._onDidChange.event; private onDidChange = this._onDidChange.event;
@@ -23,9 +31,49 @@ export class AutoFetcher {
private disposables: Disposable[] = []; private disposables: Disposable[] = [];
constructor(private repository: Repository) { constructor(private repository: Repository, private globalState: Memento) {
workspace.onDidChangeConfiguration(this.onConfiguration, this, this.disposables); workspace.onDidChangeConfiguration(this.onConfiguration, this, this.disposables);
this.onConfiguration(); this.onConfiguration();
const onGoodRemoteOperation = filterEvent(repository.onDidRunOperation, ({ operation, error }) => !error && isRemoteOperation(operation));
const onFirstGoodRemoteOperation = onceEvent(onGoodRemoteOperation);
onFirstGoodRemoteOperation(this.onFirstGoodRemoteOperation, this, this.disposables);
}
private async onFirstGoodRemoteOperation(): Promise<void> {
const didInformUser = !this.globalState.get<boolean>(AutoFetcher.DidInformUser);
if (this.enabled && !didInformUser) {
this.globalState.update(AutoFetcher.DidInformUser, true);
}
const shouldInformUser = !this.enabled && didInformUser;
if (!shouldInformUser) {
return;
}
const yes: MessageItem = { title: localize('yes', "Yes") };
const readMore: MessageItem = { title: localize('read more', "Read More") };
const no: MessageItem = { isCloseAffordance: true, title: localize('no', "No") };
const askLater: MessageItem = { title: localize('not now', "Ask Me Later") };
const result = await window.showInformationMessage(localize('suggest auto fetch', "Would you like Code to periodically run `git fetch`?"), yes, readMore, no, askLater);
if (result === askLater) {
return;
}
if (result === readMore) {
commands.executeCommand('vscode.open', Uri.parse('https://go.microsoft.com/fwlink/?linkid=865294'));
return this.onFirstGoodRemoteOperation();
}
if (result === yes) {
const gitConfig = workspace.getConfiguration('git');
gitConfig.update('autofetch', true, ConfigurationTarget.Global);
}
this.globalState.update(AutoFetcher.DidInformUser, true);
} }
private onConfiguration(): void { private onConfiguration(): void {

View File

@@ -5,7 +5,7 @@
'use strict'; 'use strict';
import { Uri, commands, Disposable, window, workspace, QuickPickItem, OutputChannel, Range, WorkspaceEdit, Position, LineChange, SourceControlResourceState, TextDocumentShowOptions, ViewColumn, ProgressLocation, TextEditor } from 'vscode'; import { Uri, commands, Disposable, window, workspace, QuickPickItem, OutputChannel, Range, WorkspaceEdit, Position, LineChange, SourceControlResourceState, TextDocumentShowOptions, ViewColumn, ProgressLocation, TextEditor, CancellationTokenSource, StatusBarAlignment } from 'vscode';
import { Ref, RefType, Git, GitErrorCodes, Branch } from './git'; import { Ref, RefType, Git, GitErrorCodes, Branch } from './git';
import { Repository, Resource, Status, CommitOptions, ResourceGroupType } from './repository'; import { Repository, Resource, Status, CommitOptions, ResourceGroupType } from './repository';
import { Model } from './model'; import { Model } from './model';
@@ -127,6 +127,15 @@ function command(commandId: string, options: CommandOptions = {}): Function {
}; };
} }
const ImageMimetypes = [
'image/png',
'image/gif',
'image/jpeg',
'image/webp',
'image/tiff',
'image/bmp'
];
export class CommandCenter { export class CommandCenter {
private disposables: Disposable[]; private disposables: Disposable[];
@@ -159,8 +168,8 @@ export class CommandCenter {
} }
private async _openResource(resource: Resource, preview?: boolean, preserveFocus?: boolean, preserveSelection?: boolean): Promise<void> { private async _openResource(resource: Resource, preview?: boolean, preserveFocus?: boolean, preserveSelection?: boolean): Promise<void> {
const left = this.getLeftResource(resource); const left = await this.getLeftResource(resource);
const right = this.getRightResource(resource); const right = await this.getRightResource(resource);
const title = this.getTitle(resource); const title = this.getTitle(resource);
if (!right) { if (!right) {
@@ -184,40 +193,77 @@ export class CommandCenter {
} }
if (!left) { if (!left) {
const document = await workspace.openTextDocument(right); await commands.executeCommand<void>('vscode.open', right, opts);
await window.showTextDocument(document, opts); } else {
return; await commands.executeCommand<void>('vscode.diff', left, right, title, opts);
} }
return await commands.executeCommand<void>('vscode.diff', left, right, title, opts);
} }
private getLeftResource(resource: Resource): Uri | undefined { private async getURI(uri: Uri, ref: string): Promise<Uri | undefined> {
const repository = this.model.getRepository(uri);
if (!repository) {
return toGitUri(uri, ref);
}
try {
let gitRef = ref;
if (gitRef === '~') {
const uriString = uri.toString();
const [indexStatus] = repository.indexGroup.resourceStates.filter(r => r.resourceUri.toString() === uriString);
gitRef = indexStatus ? '' : 'HEAD';
}
const { size, object } = await repository.lstree(gitRef, uri.fsPath);
const { mimetype, encoding } = await repository.detectObjectType(object);
if (mimetype === 'text/plain') {
return toGitUri(uri, ref);
}
if (size > 1000000) { // 1 MB
return Uri.parse(`data:;label:${path.basename(uri.fsPath)};description:${gitRef},`);
}
if (ImageMimetypes.indexOf(mimetype) > -1) {
const contents = await repository.buffer(gitRef, uri.fsPath);
return Uri.parse(`data:${mimetype};label:${path.basename(uri.fsPath)};description:${gitRef};size:${size};base64,${contents.toString('base64')}`);
}
return Uri.parse(`data:;label:${path.basename(uri.fsPath)};description:${gitRef},`);
} catch (err) {
return toGitUri(uri, ref);
}
}
private async getLeftResource(resource: Resource): Promise<Uri | undefined> {
switch (resource.type) { switch (resource.type) {
case Status.INDEX_MODIFIED: case Status.INDEX_MODIFIED:
case Status.INDEX_RENAMED: case Status.INDEX_RENAMED:
return toGitUri(resource.original, 'HEAD'); return this.getURI(resource.original, 'HEAD');
case Status.MODIFIED: case Status.MODIFIED:
return toGitUri(resource.resourceUri, '~'); return this.getURI(resource.resourceUri, '~');
case Status.DELETED_BY_THEM: case Status.DELETED_BY_THEM:
return toGitUri(resource.resourceUri, ''); return this.getURI(resource.resourceUri, '');
} }
} }
private getRightResource(resource: Resource): Uri | undefined { private async getRightResource(resource: Resource): Promise<Uri | undefined> {
switch (resource.type) { switch (resource.type) {
case Status.INDEX_MODIFIED: case Status.INDEX_MODIFIED:
case Status.INDEX_ADDED: case Status.INDEX_ADDED:
case Status.INDEX_COPIED: case Status.INDEX_COPIED:
case Status.INDEX_RENAMED: case Status.INDEX_RENAMED:
return toGitUri(resource.resourceUri, ''); return this.getURI(resource.resourceUri, '');
case Status.INDEX_DELETED: case Status.INDEX_DELETED:
case Status.DELETED_BY_THEM: case Status.DELETED_BY_THEM:
case Status.DELETED: case Status.DELETED:
return toGitUri(resource.resourceUri, 'HEAD'); return this.getURI(resource.resourceUri, 'HEAD');
case Status.MODIFIED: case Status.MODIFIED:
case Status.UNTRACKED: case Status.UNTRACKED:
@@ -261,6 +307,8 @@ export class CommandCenter {
return ''; return '';
} }
private static cloneId = 0;
@command('git.clone') @command('git.clone')
async clone(url?: string): Promise<void> { async clone(url?: string): Promise<void> {
if (!url) { if (!url) {
@@ -281,7 +329,8 @@ export class CommandCenter {
} }
const config = workspace.getConfiguration('git'); const config = workspace.getConfiguration('git');
const value = config.get<string>('defaultCloneDirectory') || os.homedir(); let value = config.get<string>('defaultCloneDirectory') || os.homedir();
value = value.replace(/^~/, os.homedir());
const parentPath = await window.showInputBox({ const parentPath = await window.showInputBox({
prompt: localize('parent', "Parent Directory"), prompt: localize('parent', "Parent Directory"),
@@ -299,12 +348,21 @@ export class CommandCenter {
return; return;
} }
const clonePromise = this.git.clone(url, parentPath); const tokenSource = new CancellationTokenSource();
const cancelCommandId = `cancelClone${CommandCenter.cloneId++}`;
const commandDisposable = commands.registerCommand(cancelCommandId, () => tokenSource.cancel());
const statusBarItem = window.createStatusBarItem(StatusBarAlignment.Left);
statusBarItem.text = localize('cancel', "$(sync~spin) Cloning repository... Click to cancel");
statusBarItem.tooltip = localize('cancel tooltip', "Cancel clone");
statusBarItem.command = cancelCommandId;
statusBarItem.show();
const clonePromise = this.git.clone(url, parentPath, tokenSource.token);
try { try {
window.withProgress({ location: ProgressLocation.SourceControl, title: localize('cloning', "Cloning git repository...") }, () => clonePromise); window.withProgress({ location: ProgressLocation.SourceControl, title: localize('cloning', "Cloning git repository...") }, () => clonePromise);
window.withProgress({ location: ProgressLocation.Window, title: localize('cloning', "Cloning git repository...") }, () => clonePromise); // window.withProgress({ location: ProgressLocation.Window, title: localize('cloning', "Cloning git repository...") }, () => clonePromise);
const repositoryPath = await clonePromise; const repositoryPath = await clonePromise;
@@ -330,6 +388,8 @@ export class CommandCenter {
} }
*/ */
this.telemetryReporter.sendTelemetryEvent('clone', { outcome: 'directory_not_empty' }); this.telemetryReporter.sendTelemetryEvent('clone', { outcome: 'directory_not_empty' });
} else if (/Cancelled/i.test(err && (err.message || err.stderr || ''))) {
return;
} else { } else {
/* __GDPR__ /* __GDPR__
"clone" : { "clone" : {
@@ -338,41 +398,62 @@ export class CommandCenter {
*/ */
this.telemetryReporter.sendTelemetryEvent('clone', { outcome: 'error' }); this.telemetryReporter.sendTelemetryEvent('clone', { outcome: 'error' });
} }
throw err; throw err;
} finally {
commandDisposable.dispose();
statusBarItem.dispose();
} }
} }
@command('git.init') @command('git.init')
async init(): Promise<void> { async init(): Promise<void> {
const homeUri = Uri.file(os.homedir()); let path: string | undefined;
const defaultUri = workspace.workspaceFolders && workspace.workspaceFolders.length > 0
? Uri.file(workspace.workspaceFolders[0].uri.fsPath)
: homeUri;
const result = await window.showOpenDialog({ if (workspace.workspaceFolders && workspace.workspaceFolders.length > 1) {
canSelectFiles: false, const placeHolder = localize('init', "Pick workspace folder to initialize git repo in");
canSelectFolders: true, const items = workspace.workspaceFolders.map(folder => ({ label: folder.name, description: folder.uri.fsPath, folder }));
canSelectMany: false, const item = await window.showQuickPick(items, { placeHolder, ignoreFocusOut: true });
defaultUri,
openLabel: localize('init repo', "Initialize Repository")
});
if (!result || result.length === 0) { if (!item) {
return;
}
const uri = result[0];
if (homeUri.toString().startsWith(uri.toString())) {
const yes = localize('create repo', "Initialize Repository");
const answer = await window.showWarningMessage(localize('are you sure', "This will create a Git repository in '{0}'. Are you sure you want to continue?", uri.fsPath), yes);
if (answer !== yes) {
return; return;
} }
path = item.folder.uri.fsPath;
}
if (!path) {
const homeUri = Uri.file(os.homedir());
const defaultUri = workspace.workspaceFolders && workspace.workspaceFolders.length > 0
? Uri.file(workspace.workspaceFolders[0].uri.fsPath)
: homeUri;
const result = await window.showOpenDialog({
canSelectFiles: false,
canSelectFolders: true,
canSelectMany: false,
defaultUri,
openLabel: localize('init repo', "Initialize Repository")
});
if (!result || result.length === 0) {
return;
}
const uri = result[0];
if (homeUri.toString().startsWith(uri.toString())) {
const yes = localize('create repo', "Initialize Repository");
const answer = await window.showWarningMessage(localize('are you sure', "This will create a Git repository in '{0}'. Are you sure you want to continue?", uri.fsPath), yes);
if (answer !== yes) {
return;
}
}
path = uri.fsPath;
} }
const path = uri.fsPath;
await this.git.init(path); await this.git.init(path);
await this.model.tryOpenRepository(path); await this.model.tryOpenRepository(path);
} }
@@ -426,8 +507,7 @@ export class CommandCenter {
opts.selection = activeTextEditor.selection; opts.selection = activeTextEditor.selection;
} }
const document = await workspace.openTextDocument(uri); await commands.executeCommand<void>('vscode.open', uri, opts);
await window.showTextDocument(document, opts);
} }
} }
@@ -447,7 +527,7 @@ export class CommandCenter {
return; return;
} }
const HEAD = this.getLeftResource(resource); const HEAD = await this.getLeftResource(resource);
if (!HEAD) { if (!HEAD) {
window.showWarningMessage(localize('HEAD not available', "HEAD version of '{0}' is not available.", path.basename(resource.resourceUri.fsPath))); window.showWarningMessage(localize('HEAD not available', "HEAD version of '{0}' is not available.", path.basename(resource.resourceUri.fsPath)));
@@ -494,7 +574,7 @@ export class CommandCenter {
@command('git.stage') @command('git.stage')
async stage(...resourceStates: SourceControlResourceState[]): Promise<void> { async stage(...resourceStates: SourceControlResourceState[]): Promise<void> {
if (resourceStates.length === 0 || !(resourceStates[0].resourceUri instanceof Uri)) { if (resourceStates.length === 0 || (resourceStates[0] && !(resourceStates[0].resourceUri instanceof Uri))) {
const resource = this.getSCMResource(); const resource = this.getSCMResource();
if (!resource) { if (!resource) {
@@ -671,7 +751,7 @@ export class CommandCenter {
@command('git.unstage') @command('git.unstage')
async unstage(...resourceStates: SourceControlResourceState[]): Promise<void> { async unstage(...resourceStates: SourceControlResourceState[]): Promise<void> {
if (resourceStates.length === 0 || !(resourceStates[0].resourceUri instanceof Uri)) { if (resourceStates.length === 0 || (resourceStates[0] && !(resourceStates[0].resourceUri instanceof Uri))) {
const resource = this.getSCMResource(); const resource = this.getSCMResource();
if (!resource) { if (!resource) {
@@ -737,7 +817,7 @@ export class CommandCenter {
@command('git.clean') @command('git.clean')
async clean(...resourceStates: SourceControlResourceState[]): Promise<void> { async clean(...resourceStates: SourceControlResourceState[]): Promise<void> {
if (resourceStates.length === 0 || !(resourceStates[0].resourceUri instanceof Uri)) { if (resourceStates.length === 0 || (resourceStates[0] && !(resourceStates[0].resourceUri instanceof Uri))) {
const resource = this.getSCMResource(); const resource = this.getSCMResource();
if (!resource) { if (!resource) {
@@ -917,6 +997,7 @@ export class CommandCenter {
} }
return await window.showInputBox({ return await window.showInputBox({
value: opts && opts.defaultMsg,
placeHolder: localize('commit message', "Commit message"), placeHolder: localize('commit message', "Commit message"),
prompt: localize('provide commit message', "Please provide a commit message"), prompt: localize('provide commit message', "Please provide a commit message"),
ignoreFocusOut: true ignoreFocusOut: true
@@ -960,7 +1041,15 @@ export class CommandCenter {
@command('git.commitStagedAmend', { repository: true }) @command('git.commitStagedAmend', { repository: true })
async commitStagedAmend(repository: Repository): Promise<void> { async commitStagedAmend(repository: Repository): Promise<void> {
await this.commitWithAnyInput(repository, { all: false, amend: true }); let msg;
if (repository.HEAD) {
if (repository.HEAD.commit) {
let id = repository.HEAD.commit;
let commit = await repository.getCommit(id);
msg = commit.message;
}
}
await this.commitWithAnyInput(repository, { all: false, amend: true, defaultMsg: msg });
} }
@command('git.commitAll', { repository: true }) @command('git.commitAll', { repository: true })
@@ -1077,6 +1166,31 @@ export class CommandCenter {
} }
} }
@command('git.renameBranch', { repository: true })
async renameBranch(repository: Repository): Promise<void> {
const placeHolder = localize('provide branch name', "Please provide a branch name");
const name = await window.showInputBox({ placeHolder });
if (!name || name.trim().length === 0) {
return;
}
try {
await repository.renameBranch(name);
} catch (err) {
switch (err.gitErrorCode) {
case GitErrorCodes.InvalidBranchName:
window.showErrorMessage(localize('invalid branch name', 'Invalid branch name'));
return;
case GitErrorCodes.BranchAlreadyExists:
window.showErrorMessage(localize('branch already exists', "A branch named '{0}' already exists", name));
return;
default:
throw err;
}
}
}
@command('git.merge', { repository: true }) @command('git.merge', { repository: true })
async merge(repository: Repository): Promise<void> { async merge(repository: Repository): Promise<void> {
const config = workspace.getConfiguration('git'); const config = workspace.getConfiguration('git');
@@ -1134,6 +1248,16 @@ export class CommandCenter {
await repository.tag(name, message); await repository.tag(name, message);
} }
@command('git.fetch', { repository: true })
async fetch(repository: Repository): Promise<void> {
if (repository.remotes.length === 0) {
window.showWarningMessage(localize('no remotes to fetch', "This repository has no remotes configured to fetch from."));
return;
}
await repository.fetch();
}
@command('git.pullFrom', { repository: true }) @command('git.pullFrom', { repository: true })
async pullFrom(repository: Repository): Promise<void> { async pullFrom(repository: Repository): Promise<void> {
const remotes = repository.remotes; const remotes = repository.remotes;
@@ -1240,8 +1364,7 @@ export class CommandCenter {
repository.pushTo(pick.label, branchName); repository.pushTo(pick.label, branchName);
} }
@command('git.sync', { repository: true }) private async _sync(repository: Repository, rebase: boolean): Promise<void> {
async sync(repository: Repository): Promise<void> {
const HEAD = repository.HEAD; const HEAD = repository.HEAD;
if (!HEAD || !HEAD.upstream) { if (!HEAD || !HEAD.upstream) {
@@ -1264,7 +1387,16 @@ export class CommandCenter {
} }
} }
await repository.sync(); if (rebase) {
await repository.syncRebase();
} else {
await repository.sync();
}
}
@command('git.sync', { repository: true })
sync(repository: Repository): Promise<void> {
return this._sync(repository, false);
} }
@command('git._syncAll') @command('git._syncAll')
@@ -1280,6 +1412,11 @@ export class CommandCenter {
})); }));
} }
@command('git.syncRebase', { repository: true })
syncRebase(repository: Repository): Promise<void> {
return this._sync(repository, true);
}
@command('git.publish', { repository: true }) @command('git.publish', { repository: true })
async publish(repository: Repository): Promise<void> { async publish(repository: Repository): Promise<void> {
const remotes = repository.remotes; const remotes = repository.remotes;
@@ -1304,14 +1441,9 @@ export class CommandCenter {
await repository.pushTo(choice, branchName, true); await repository.pushTo(choice, branchName, true);
} }
@command('git.showOutput')
showOutput(): void {
this.outputChannel.show();
}
@command('git.ignore') @command('git.ignore')
async ignore(...resourceStates: SourceControlResourceState[]): Promise<void> { async ignore(...resourceStates: SourceControlResourceState[]): Promise<void> {
if (resourceStates.length === 0 || !(resourceStates[0].resourceUri instanceof Uri)) { if (resourceStates.length === 0 || (resourceStates[0] && !(resourceStates[0].resourceUri instanceof Uri))) {
const resource = this.getSCMResource(); const resource = this.getSCMResource();
if (!resource) { if (!resource) {
@@ -1332,23 +1464,36 @@ export class CommandCenter {
await this.runByRepository(resources, async (repository, resources) => repository.ignore(resources)); await this.runByRepository(resources, async (repository, resources) => repository.ignore(resources));
} }
@command('git.stash', { repository: true }) private async _stash(repository: Repository, includeUntracked = false): Promise<void> {
async stash(repository: Repository): Promise<void> {
if (repository.workingTreeGroup.resourceStates.length === 0) { if (repository.workingTreeGroup.resourceStates.length === 0) {
window.showInformationMessage(localize('no changes stash', "There are no changes to stash.")); window.showInformationMessage(localize('no changes stash', "There are no changes to stash."));
return; return;
} }
const message = await window.showInputBox({ const message = await this.getStashMessage();
prompt: localize('provide stash message', "Optionally provide a stash message"),
placeHolder: localize('stash message', "Stash message")
});
if (typeof message === 'undefined') { if (typeof message === 'undefined') {
return; return;
} }
await repository.createStash(message); await repository.createStash(message, includeUntracked);
}
private async getStashMessage(): Promise<string | undefined> {
return await window.showInputBox({
prompt: localize('provide stash message', "Optionally provide a stash message"),
placeHolder: localize('stash message', "Stash message")
});
}
@command('git.stash', { repository: true })
stash(repository: Repository): Promise<void> {
return this._stash(repository);
}
@command('git.stashIncludeUntracked', { repository: true })
stashIncludeUntracked(repository: Repository): Promise<void> {
return this._stash(repository, true);
} }
@command('git.stashPop', { repository: true }) @command('git.stashPop', { repository: true })
@@ -1384,7 +1529,7 @@ export class CommandCenter {
} }
private createCommand(id: string, key: string, method: Function, options: CommandOptions): (...args: any[]) => any { private createCommand(id: string, key: string, method: Function, options: CommandOptions): (...args: any[]) => any {
const result = (...args) => { const result = (...args: any[]) => {
let result: Promise<any>; let result: Promise<any>;
if (!options.repository) { if (!options.repository) {
@@ -1426,14 +1571,14 @@ export class CommandCenter {
message = localize('clean repo', "Please clean your repository working tree before checkout."); message = localize('clean repo', "Please clean your repository working tree before checkout.");
break; break;
case GitErrorCodes.PushRejected: case GitErrorCodes.PushRejected:
message = localize('cant push', "Can't push refs to remote. Run 'Pull' first to integrate your changes."); message = localize('cant push', "Can't push refs to remote. Try running 'Pull' first to integrate your changes.");
break; break;
default: default:
const hint = (err.stderr || err.message || String(err)) const hint = (err.stderr || err.message || String(err))
.replace(/^error: /mi, '') .replace(/^error: /mi, '')
.replace(/^> husky.*$/mi, '') .replace(/^> husky.*$/mi, '')
.split(/[\r\n]/) .split(/[\r\n]/)
.filter(line => !!line) .filter((line: string) => !!line)
[0]; [0];
message = hint message = hint
@@ -1459,7 +1604,7 @@ export class CommandCenter {
}; };
// patch this object, so people can call methods directly // patch this object, so people can call methods directly
this[key] = result; (this as any)[key] = result;
return result; return result;
} }
@@ -1523,4 +1668,4 @@ export class CommandCenter {
dispose(): void { dispose(): void {
this.disposables.forEach(d => d.dispose()); this.disposables.forEach(d => d.dispose());
} }
} }

View File

@@ -9,7 +9,7 @@ import { workspace, Uri, Disposable, Event, EventEmitter, window } from 'vscode'
import { debounce, throttle } from './decorators'; import { debounce, throttle } from './decorators';
import { fromGitUri, toGitUri } from './uri'; import { fromGitUri, toGitUri } from './uri';
import { Model, ModelChangeEvent, OriginalResourceChangeEvent } from './model'; import { Model, ModelChangeEvent, OriginalResourceChangeEvent } from './model';
import { filterEvent, eventToPromise } from './util'; import { filterEvent, eventToPromise, isDescendant } from './util';
interface CacheRow { interface CacheRow {
uri: Uri; uri: Uri;
@@ -72,7 +72,7 @@ export class GitContentProvider {
const fsPath = uri.fsPath; const fsPath = uri.fsPath;
for (const root of this.changedRepositoryRoots) { for (const root of this.changedRepositoryRoots) {
if (fsPath.startsWith(root)) { if (isDescendant(root, fsPath)) {
this._onDidChange.fire(uri); this._onDidChange.fire(uri);
return; return;
} }
@@ -100,7 +100,7 @@ export class GitContentProvider {
if (ref === '~') { if (ref === '~') {
const fileUri = Uri.file(path); const fileUri = Uri.file(path);
const uriString = fileUri.toString(); const uriString = fileUri.toString();
const [indexStatus] = repository.indexGroup.resourceStates.filter(r => r.original.toString() === uriString); const [indexStatus] = repository.indexGroup.resourceStates.filter(r => r.resourceUri.toString() === uriString);
ref = indexStatus ? '' : 'HEAD'; ref = indexStatus ? '' : 'HEAD';
} }

View File

@@ -6,7 +6,7 @@
'use strict'; 'use strict';
import { window, workspace, Uri, Disposable, Event, EventEmitter, DecorationData, DecorationProvider, ThemeColor } from 'vscode'; import { window, workspace, Uri, Disposable, Event, EventEmitter, DecorationData, DecorationProvider, ThemeColor } from 'vscode';
import { Repository, GitResourceGroup } from './repository'; import { Repository, GitResourceGroup, Status } from './repository';
import { Model } from './model'; import { Model } from './model';
import { debounce } from './decorators'; import { debounce } from './decorators';
import { filterEvent } from './util'; import { filterEvent } from './util';
@@ -74,34 +74,28 @@ class GitDecorationProvider implements DecorationProvider {
constructor(private repository: Repository) { constructor(private repository: Repository) {
this.disposables.push( this.disposables.push(
window.registerDecorationProvider(this), window.registerDecorationProvider(this),
repository.onDidRunOperation(this.onDidRunOperation, this) repository.onDidRunGitStatus(this.onDidRunGitStatus, this)
); );
} }
private onDidRunOperation(): void { private onDidRunGitStatus(): void {
let newDecorations = new Map<string, DecorationData>(); let newDecorations = new Map<string, DecorationData>();
this.collectDecorationData(this.repository.indexGroup, newDecorations); this.collectDecorationData(this.repository.indexGroup, newDecorations);
this.collectDecorationData(this.repository.workingTreeGroup, newDecorations); this.collectDecorationData(this.repository.workingTreeGroup, newDecorations);
this.collectDecorationData(this.repository.mergeGroup, newDecorations); this.collectDecorationData(this.repository.mergeGroup, newDecorations);
let uris: Uri[] = []; const uris = new Set([...this.decorations.keys()].concat([...newDecorations.keys()]));
newDecorations.forEach((value, uriString) => {
if (this.decorations.has(uriString)) {
this.decorations.delete(uriString);
} else {
uris.push(Uri.parse(uriString));
}
});
this.decorations.forEach((value, uriString) => {
uris.push(Uri.parse(uriString));
});
this.decorations = newDecorations; this.decorations = newDecorations;
this._onDidChangeDecorations.fire(uris); this._onDidChangeDecorations.fire([...uris.values()].map(Uri.parse));
} }
private collectDecorationData(group: GitResourceGroup, bucket: Map<string, DecorationData>): void { private collectDecorationData(group: GitResourceGroup, bucket: Map<string, DecorationData>): void {
group.resourceStates.forEach(r => { group.resourceStates.forEach(r => {
if (r.resourceDecoration) { if (r.resourceDecoration
&& r.type !== Status.DELETED
&& r.type !== Status.INDEX_DELETED
) {
// not deleted and has a decoration
bucket.set(r.original.toString(), r.resourceDecoration); bucket.set(r.original.toString(), r.resourceDecoration);
} }
}); });

View File

@@ -31,7 +31,7 @@ function decorate(decorator: (fn: Function, key: string) => Function): Function
function _memoize(fn: Function, key: string): Function { function _memoize(fn: Function, key: string): Function {
const memoizeKey = `$memoize$${key}`; const memoizeKey = `$memoize$${key}`;
return function (...args: any[]) { return function (this: any, ...args: any[]) {
if (!this.hasOwnProperty(memoizeKey)) { if (!this.hasOwnProperty(memoizeKey)) {
Object.defineProperty(this, memoizeKey, { Object.defineProperty(this, memoizeKey, {
configurable: false, configurable: false,
@@ -51,7 +51,7 @@ function _throttle<T>(fn: Function, key: string): Function {
const currentKey = `$throttle$current$${key}`; const currentKey = `$throttle$current$${key}`;
const nextKey = `$throttle$next$${key}`; const nextKey = `$throttle$next$${key}`;
const trigger = function (...args: any[]) { const trigger = function (this: any, ...args: any[]) {
if (this[nextKey]) { if (this[nextKey]) {
return this[nextKey]; return this[nextKey];
} }
@@ -81,7 +81,7 @@ export const throttle = decorate(_throttle);
function _sequentialize<T>(fn: Function, key: string): Function { function _sequentialize<T>(fn: Function, key: string): Function {
const currentKey = `__$sequence$${key}`; const currentKey = `__$sequence$${key}`;
return function (...args: any[]) { return function (this: any, ...args: any[]) {
const currentPromise = this[currentKey] as Promise<any> || Promise.resolve(null); const currentPromise = this[currentKey] as Promise<any> || Promise.resolve(null);
const run = async () => await fn.apply(this, args); const run = async () => await fn.apply(this, args);
this[currentKey] = currentPromise.then(run, run); this[currentKey] = currentPromise.then(run, run);
@@ -95,7 +95,7 @@ export function debounce(delay: number): Function {
return decorate((fn, key) => { return decorate((fn, key) => {
const timerKey = `$debounce$${key}`; const timerKey = `$debounce$${key}`;
return function (...args: any[]) { return function (this: any, ...args: any[]) {
clearTimeout(this[timerKey]); clearTimeout(this[timerKey]);
this[timerKey] = setTimeout(() => fn.apply(this, args), delay); this[timerKey] = setTimeout(() => fn.apply(this, args), delay);
}; };

View File

@@ -9,9 +9,12 @@ import * as fs from 'fs';
import * as path from 'path'; import * as path from 'path';
import * as os from 'os'; import * as os from 'os';
import * as cp from 'child_process'; import * as cp from 'child_process';
import * as which from 'which';
import { EventEmitter } from 'events'; import { EventEmitter } from 'events';
import iconv = require('iconv-lite'); import iconv = require('iconv-lite');
import { assign, uniqBy, groupBy, denodeify, IDisposable, toDisposable, dispose, mkdirp } from './util'; import * as filetype from 'file-type';
import { assign, uniqBy, groupBy, denodeify, IDisposable, toDisposable, dispose, mkdirp, readBytes, detectUnicodeEncoding, Encoding, onceEvent } from './util';
import { CancellationToken } from 'vscode';
const readfile = denodeify<string>(fs.readFile); const readfile = denodeify<string>(fs.readFile);
@@ -60,8 +63,10 @@ function parseVersion(raw: string): string {
return raw.replace(/^git version /, ''); return raw.replace(/^git version /, '');
} }
function findSpecificGit(path: string): Promise<IGit> { function findSpecificGit(path: string, onLookup: (path: string) => void): Promise<IGit> {
return new Promise<IGit>((c, e) => { return new Promise<IGit>((c, e) => {
onLookup(path);
const buffers: Buffer[] = []; const buffers: Buffer[] = [];
const child = cp.spawn(path, ['--version']); const child = cp.spawn(path, ['--version']);
child.stdout.on('data', (b: Buffer) => buffers.push(b)); child.stdout.on('data', (b: Buffer) => buffers.push(b));
@@ -70,7 +75,7 @@ function findSpecificGit(path: string): Promise<IGit> {
}); });
} }
function findGitDarwin(): Promise<IGit> { function findGitDarwin(onLookup: (path: string) => void): Promise<IGit> {
return new Promise<IGit>((c, e) => { return new Promise<IGit>((c, e) => {
cp.exec('which git', (err, gitPathBuffer) => { cp.exec('which git', (err, gitPathBuffer) => {
if (err) { if (err) {
@@ -80,8 +85,11 @@ function findGitDarwin(): Promise<IGit> {
const path = gitPathBuffer.toString().replace(/^\s+|\s+$/g, ''); const path = gitPathBuffer.toString().replace(/^\s+|\s+$/g, '');
function getVersion(path: string) { function getVersion(path: string) {
onLookup(path);
// make sure git executes // make sure git executes
cp.exec('git --version', (err, stdout) => { cp.exec('git --version', (err, stdout) => {
if (err) { if (err) {
return e('git not found'); return e('git not found');
} }
@@ -109,38 +117,44 @@ function findGitDarwin(): Promise<IGit> {
}); });
} }
function findSystemGitWin32(base: string): Promise<IGit> { function findSystemGitWin32(base: string, onLookup: (path: string) => void): Promise<IGit> {
if (!base) { if (!base) {
return Promise.reject<IGit>('Not found'); return Promise.reject<IGit>('Not found');
} }
return findSpecificGit(path.join(base, 'Git', 'cmd', 'git.exe')); return findSpecificGit(path.join(base, 'Git', 'cmd', 'git.exe'), onLookup);
} }
function findGitWin32(): Promise<IGit> { function findGitWin32InPath(onLookup: (path: string) => void): Promise<IGit> {
return findSystemGitWin32(process.env['ProgramW6432']) const whichPromise = new Promise<string>((c, e) => which('git.exe', (err, path) => err ? e(err) : c(path)));
.then(void 0, () => findSystemGitWin32(process.env['ProgramFiles(x86)'])) return whichPromise.then(path => findSpecificGit(path, onLookup));
.then(void 0, () => findSystemGitWin32(process.env['ProgramFiles']))
.then(void 0, () => findSpecificGit('git'));
} }
export function findGit(hint: string | undefined): Promise<IGit> { function findGitWin32(onLookup: (path: string) => void): Promise<IGit> {
var first = hint ? findSpecificGit(hint) : Promise.reject<IGit>(null); return findSystemGitWin32(process.env['ProgramW6432'] as string, onLookup)
.then(void 0, () => findSystemGitWin32(process.env['ProgramFiles(x86)'] as string, onLookup))
.then(void 0, () => findSystemGitWin32(process.env['ProgramFiles'] as string, onLookup))
.then(void 0, () => findSystemGitWin32(path.join(process.env['LocalAppData'] as string, 'Programs'), onLookup))
.then(void 0, () => findGitWin32InPath(onLookup));
}
export function findGit(hint: string | undefined, onLookup: (path: string) => void): Promise<IGit> {
const first = hint ? findSpecificGit(hint, onLookup) : Promise.reject<IGit>(null);
return first return first
.then(void 0, () => { .then(void 0, () => {
switch (process.platform) { switch (process.platform) {
case 'darwin': return findGitDarwin(); case 'darwin': return findGitDarwin(onLookup);
case 'win32': return findGitWin32(); case 'win32': return findGitWin32(onLookup);
default: return findSpecificGit('git'); default: return findSpecificGit('git', onLookup);
} }
}) })
.then(null, () => Promise.reject(new Error('Git installation not found.'))); .then(null, () => Promise.reject(new Error('Git installation not found.')));
} }
export interface IExecutionResult { export interface IExecutionResult<T extends string | Buffer> {
exitCode: number; exitCode: number;
stdout: string; stdout: T;
stderr: string; stderr: string;
} }
@@ -162,50 +176,69 @@ export interface SpawnOptions extends cp.SpawnOptions {
input?: string; input?: string;
encoding?: string; encoding?: string;
log?: boolean; log?: boolean;
cancellationToken?: CancellationToken;
} }
async function exec(child: cp.ChildProcess, options: SpawnOptions = {}): Promise<IExecutionResult> { async function exec(child: cp.ChildProcess, cancellationToken?: CancellationToken): Promise<IExecutionResult<Buffer>> {
if (!child.stdout || !child.stderr) { if (!child.stdout || !child.stderr) {
throw new GitError({ throw new GitError({ message: 'Failed to get stdout or stderr from git process.' });
message: 'Failed to get stdout or stderr from git process.' }
});
if (cancellationToken && cancellationToken.isCancellationRequested) {
throw new GitError({ message: 'Cancelled' });
} }
const disposables: IDisposable[] = []; const disposables: IDisposable[] = [];
const once = (ee: NodeJS.EventEmitter, name: string, fn: Function) => { const once = (ee: NodeJS.EventEmitter, name: string, fn: (...args: any[]) => void) => {
ee.once(name, fn); ee.once(name, fn);
disposables.push(toDisposable(() => ee.removeListener(name, fn))); disposables.push(toDisposable(() => ee.removeListener(name, fn)));
}; };
const on = (ee: NodeJS.EventEmitter, name: string, fn: Function) => { const on = (ee: NodeJS.EventEmitter, name: string, fn: (...args: any[]) => void) => {
ee.on(name, fn); ee.on(name, fn);
disposables.push(toDisposable(() => ee.removeListener(name, fn))); disposables.push(toDisposable(() => ee.removeListener(name, fn)));
}; };
let encoding = options.encoding || 'utf8'; let result = Promise.all<any>([
encoding = iconv.encodingExists(encoding) ? encoding : 'utf8';
const [exitCode, stdout, stderr] = await Promise.all<any>([
new Promise<number>((c, e) => { new Promise<number>((c, e) => {
once(child, 'error', cpErrorHandler(e)); once(child, 'error', cpErrorHandler(e));
once(child, 'exit', c); once(child, 'exit', c);
}), }),
new Promise<string>(c => { new Promise<Buffer>(c => {
const buffers: Buffer[] = []; const buffers: Buffer[] = [];
on(child.stdout, 'data', b => buffers.push(b)); on(child.stdout, 'data', (b: Buffer) => buffers.push(b));
once(child.stdout, 'close', () => c(iconv.decode(Buffer.concat(buffers), encoding))); once(child.stdout, 'close', () => c(Buffer.concat(buffers)));
}), }),
new Promise<string>(c => { new Promise<string>(c => {
const buffers: Buffer[] = []; const buffers: Buffer[] = [];
on(child.stderr, 'data', b => buffers.push(b)); on(child.stderr, 'data', (b: Buffer) => buffers.push(b));
once(child.stderr, 'close', () => c(Buffer.concat(buffers).toString('utf8'))); once(child.stderr, 'close', () => c(Buffer.concat(buffers).toString('utf8')));
}) })
]); ]) as Promise<[number, Buffer, string]>;
dispose(disposables); if (cancellationToken) {
const cancellationPromise = new Promise<[number, Buffer, string]>((_, e) => {
onceEvent(cancellationToken.onCancellationRequested)(() => {
try {
child.kill();
} catch (err) {
// noop
}
return { exitCode, stdout, stderr }; e(new GitError({ message: 'Cancelled' }));
});
});
result = Promise.race([result, cancellationPromise]);
}
try {
const [exitCode, stdout, stderr] = await result;
return { exitCode, stdout, stderr };
} finally {
dispose(disposables);
}
} }
export interface IGitErrorData { export interface IGitErrorData {
@@ -288,6 +321,8 @@ export const GitErrorCodes = {
RepositoryIsLocked: 'RepositoryIsLocked', RepositoryIsLocked: 'RepositoryIsLocked',
BranchNotFullyMerged: 'BranchNotFullyMerged', BranchNotFullyMerged: 'BranchNotFullyMerged',
NoRemoteReference: 'NoRemoteReference', NoRemoteReference: 'NoRemoteReference',
InvalidBranchName: 'InvalidBranchName',
BranchAlreadyExists: 'BranchAlreadyExists',
NoLocalChanges: 'NoLocalChanges', NoLocalChanges: 'NoLocalChanges',
NoStashFound: 'NoStashFound', NoStashFound: 'NoStashFound',
LocalChangesOverwritten: 'LocalChangesOverwritten' LocalChangesOverwritten: 'LocalChangesOverwritten'
@@ -312,6 +347,10 @@ function getGitErrorCode(stderr: string): string | undefined {
return GitErrorCodes.BranchNotFullyMerged; return GitErrorCodes.BranchNotFullyMerged;
} else if (/Couldn\'t find remote ref/.test(stderr)) { } else if (/Couldn\'t find remote ref/.test(stderr)) {
return GitErrorCodes.NoRemoteReference; return GitErrorCodes.NoRemoteReference;
} else if (/A branch named '.+' already exists/.test(stderr)) {
return GitErrorCodes.BranchAlreadyExists;
} else if (/'.+' is not a valid branch name/.test(stderr)) {
return GitErrorCodes.InvalidBranchName;
} }
return void 0; return void 0;
@@ -341,12 +380,12 @@ export class Git {
return; return;
} }
async clone(url: string, parentPath: string): Promise<string> { async clone(url: string, parentPath: string, cancellationToken?: CancellationToken): Promise<string> {
const folderName = decodeURI(url).replace(/^.*\//, '').replace(/\.git$/, '') || 'repository'; const folderName = decodeURI(url).replace(/^.*\//, '').replace(/\.git$/, '') || 'repository';
const folderPath = path.join(parentPath, folderName); const folderPath = path.join(parentPath, folderName);
await mkdirp(parentPath); await mkdirp(parentPath);
await this.exec(parentPath, ['clone', url, folderPath]); await this.exec(parentPath, ['clone', url, folderPath], { cancellationToken });
return folderPath; return folderPath;
} }
@@ -355,7 +394,7 @@ export class Git {
return path.normalize(result.stdout.trim()); return path.normalize(result.stdout.trim());
} }
async exec(cwd: string, args: string[], options: SpawnOptions = {}): Promise<IExecutionResult> { async exec(cwd: string, args: string[], options: SpawnOptions = {}): Promise<IExecutionResult<string>> {
options = assign({ cwd }, options || {}); options = assign({ cwd }, options || {});
return await this._exec(args, options); return await this._exec(args, options);
} }
@@ -365,21 +404,30 @@ export class Git {
return this.spawn(args, options); return this.spawn(args, options);
} }
private async _exec(args: string[], options: SpawnOptions = {}): Promise<IExecutionResult> { private async _exec(args: string[], options: SpawnOptions = {}): Promise<IExecutionResult<string>> {
const child = this.spawn(args, options); const child = this.spawn(args, options);
if (options.input) { if (options.input) {
child.stdin.end(options.input, 'utf8'); child.stdin.end(options.input, 'utf8');
} }
const result = await exec(child, options); const bufferResult = await exec(child, options.cancellationToken);
if (options.log !== false && result.stderr.length > 0) { if (options.log !== false && bufferResult.stderr.length > 0) {
this.log(`${result.stderr}\n`); this.log(`${bufferResult.stderr}\n`);
} }
if (result.exitCode) { let encoding = options.encoding || 'utf8';
return Promise.reject<IExecutionResult>(new GitError({ encoding = iconv.encodingExists(encoding) ? encoding : 'utf8';
const result: IExecutionResult<string> = {
exitCode: bufferResult.exitCode,
stdout: iconv.decode(bufferResult.stdout, encoding),
stderr: bufferResult.stderr
};
if (bufferResult.exitCode) {
return Promise.reject<IExecutionResult<string>>(new GitError({
message: 'Failed to execute git', message: 'Failed to execute git',
stdout: result.stdout, stdout: result.stdout,
stderr: result.stderr, stderr: result.stderr,
@@ -510,7 +558,7 @@ export class Repository {
} }
// TODO@Joao: rename to exec // TODO@Joao: rename to exec
async run(args: string[], options: SpawnOptions = {}): Promise<IExecutionResult> { async run(args: string[], options: SpawnOptions = {}): Promise<IExecutionResult<string>> {
return await this.git.exec(this.repositoryRoot, args, options); return await this.git.exec(this.repositoryRoot, args, options);
} }
@@ -539,39 +587,97 @@ export class Repository {
return result.stdout; return result.stdout;
} }
async buffer(object: string, encoding: string = 'utf8'): Promise<string> { async bufferString(object: string, encoding: string = 'utf8'): Promise<string> {
const stdout = await this.buffer(object);
return iconv.decode(stdout, iconv.encodingExists(encoding) ? encoding : 'utf8');
}
async buffer(object: string): Promise<Buffer> {
const child = this.stream(['show', object]); const child = this.stream(['show', object]);
if (!child.stdout) { if (!child.stdout) {
return Promise.reject<string>('Can\'t open file from git'); return Promise.reject<Buffer>('Can\'t open file from git');
} }
const { exitCode, stdout } = await exec(child, { encoding }); const { exitCode, stdout } = await exec(child);
if (exitCode) { if (exitCode) {
return Promise.reject<string>(new GitError({ return Promise.reject<Buffer>(new GitError({
message: 'Could not show object.', message: 'Could not show object.',
exitCode exitCode
})); }));
} }
return stdout; return stdout;
}
// TODO@joao async lstree(treeish: string, path: string): Promise<{ mode: number, object: string, size: number }> {
// return new Promise((c, e) => { if (!treeish) { // index
// detectMimesFromStream(child.stdout, null, (err, result) => { const { stdout } = await this.run(['ls-files', '--stage', '--', path]);
// if (err) {
// e(err); const match = /^(\d+)\s+([0-9a-f]{40})\s+(\d+)/.exec(stdout);
// } else if (isBinaryMime(result.mimes)) {
// e(<IFileOperationResult>{ if (!match) {
// message: localize('fileBinaryError', "File seems to be binary and cannot be opened as text"), throw new GitError({ message: 'Error running ls-files' });
// fileOperationResult: FileOperationResult.FILE_IS_BINARY }
// });
// } else { const [, mode, object] = match;
// c(this.doBuffer(object)); const catFile = await this.run(['cat-file', '-s', object]);
// } const size = parseInt(catFile.stdout);
// });
// }); return { mode: parseInt(mode), object, size };
}
const { stdout } = await this.run(['ls-tree', '-l', treeish, '--', path]);
const match = /^(\d+)\s+(\w+)\s+([0-9a-f]{40})\s+(\d+)/.exec(stdout);
if (!match) {
throw new GitError({ message: 'Error running ls-tree' });
}
const [, mode, , object, size] = match;
return { mode: parseInt(mode), object, size: parseInt(size) };
}
async detectObjectType(object: string): Promise<{ mimetype: string, encoding?: string }> {
const child = await this.stream(['show', object]);
const buffer = await readBytes(child.stdout, 4100);
try {
child.kill();
} catch (err) {
// noop
}
const encoding = detectUnicodeEncoding(buffer);
let isText = true;
if (encoding !== Encoding.UTF16be && encoding !== Encoding.UTF16le) {
for (let i = 0; i < buffer.length; i++) {
if (buffer.readInt8(i) === 0) {
isText = false;
break;
}
}
}
if (!isText) {
const result = filetype(buffer);
if (!result) {
return { mimetype: 'application/octet-stream' };
} else {
return { mimetype: result.mime };
}
}
if (encoding) {
return { mimetype: 'text/plain', encoding };
} else {
// TODO@JOAO: read the setting OUTSIDE!
return { mimetype: 'text/plain' };
}
} }
async add(paths: string[]): Promise<void> { async add(paths: string[]): Promise<void> {
@@ -591,6 +697,7 @@ export class Repository {
child.stdin.end(data, 'utf8'); child.stdin.end(data, 'utf8');
const { exitCode, stdout } = await exec(child); const { exitCode, stdout } = await exec(child);
const hash = stdout.toString('utf8');
if (exitCode) { if (exitCode) {
throw new GitError({ throw new GitError({
@@ -599,7 +706,7 @@ export class Repository {
}); });
} }
await this.run(['update-index', '--cacheinfo', '100644', stdout, path]); await this.run(['update-index', '--cacheinfo', '100644', hash, path]);
} }
async checkout(treeish: string, paths: string[]): Promise<void> { async checkout(treeish: string, paths: string[]): Promise<void> {
@@ -680,6 +787,11 @@ export class Repository {
await this.run(args); await this.run(args);
} }
async renameBranch(name: string): Promise<void> {
const args = ['branch', '-m', name];
await this.run(args);
}
async merge(ref: string): Promise<void> { async merge(ref: string): Promise<void> {
const args = ['merge', ref]; const args = ['merge', ref];
@@ -847,10 +959,14 @@ export class Repository {
} }
} }
async createStash(message?: string): Promise<void> { async createStash(message?: string, includeUntracked?: boolean): Promise<void> {
try { try {
const args = ['stash', 'save']; const args = ['stash', 'save'];
if (includeUntracked) {
args.push('-u');
}
if (message) { if (message) {
args.push('--', message); args.push('--', message);
} }
@@ -869,7 +985,7 @@ export class Repository {
try { try {
const args = ['stash', 'pop']; const args = ['stash', 'pop'];
if (typeof index === 'string') { if (typeof index === 'number') {
args.push(`stash@{${index}}`); args.push(`stash@{${index}}`);
} }
@@ -891,7 +1007,7 @@ export class Repository {
const env = { GIT_OPTIONAL_LOCKS: '0' }; const env = { GIT_OPTIONAL_LOCKS: '0' };
const child = this.stream(['status', '-z', '-u'], { env }); const child = this.stream(['status', '-z', '-u'], { env });
const onExit = exitCode => { const onExit = (exitCode: number) => {
if (exitCode !== 0) { if (exitCode !== 0) {
const stderr = stderrData.join(''); const stderr = stderrData.join('');
return e(new GitError({ return e(new GitError({
@@ -909,12 +1025,12 @@ export class Repository {
const onStdoutData = (raw: string) => { const onStdoutData = (raw: string) => {
parser.update(raw); parser.update(raw);
if (parser.status.length > 5000) { if (parser.status.length > limit) {
child.removeListener('exit', onExit); child.removeListener('exit', onExit);
child.stdout.removeListener('data', onStdoutData); child.stdout.removeListener('data', onStdoutData);
child.kill(); child.kill();
c({ status: parser.status.slice(0, 5000), didHitLimit: true }); c({ status: parser.status.slice(0, limit), didHitLimit: true });
} }
}; };
@@ -953,7 +1069,7 @@ export class Repository {
async getRefs(): Promise<Ref[]> { async getRefs(): Promise<Ref[]> {
const result = await this.run(['for-each-ref', '--format', '%(refname) %(objectname)']); const result = await this.run(['for-each-ref', '--format', '%(refname) %(objectname)']);
const fn = (line): Ref | null => { const fn = (line: string): Ref | null => {
let match: RegExpExecArray | null; let match: RegExpExecArray | null;
if (match = /^refs\/heads\/([^ ]+) ([0-9a-f]{40})$/.exec(line)) { if (match = /^refs\/heads\/([^ ]+) ([0-9a-f]{40})$/.exec(line)) {
@@ -978,7 +1094,7 @@ export class Repository {
const regex = /^stash@{(\d+)}:(.+)$/; const regex = /^stash@{(\d+)}:(.+)$/;
const rawStashes = result.stdout.trim().split('\n') const rawStashes = result.stdout.trim().split('\n')
.filter(b => !!b) .filter(b => !!b)
.map(line => regex.exec(line)) .map(line => regex.exec(line) as RegExpExecArray)
.filter(g => !!g) .filter(g => !!g)
.map(([, index, description]: RegExpExecArray) => ({ index: parseInt(index), description })); .map(([, index, description]: RegExpExecArray) => ({ index: parseInt(index), description }));
@@ -990,7 +1106,7 @@ export class Repository {
const regex = /^([^\s]+)\s+([^\s]+)\s/; const regex = /^([^\s]+)\s+([^\s]+)\s/;
const rawRemotes = result.stdout.trim().split('\n') const rawRemotes = result.stdout.trim().split('\n')
.filter(b => !!b) .filter(b => !!b)
.map(line => regex.exec(line)) .map(line => regex.exec(line) as RegExpExecArray)
.filter(g => !!g) .filter(g => !!g)
.map((groups: RegExpExecArray) => ({ name: groups[1], url: groups[2] })); .map((groups: RegExpExecArray) => ({ name: groups[1], url: groups[2] }));

View File

@@ -7,7 +7,7 @@
import * as nls from 'vscode-nls'; import * as nls from 'vscode-nls';
const localize = nls.config(process.env.VSCODE_NLS_CONFIG)(); const localize = nls.config(process.env.VSCODE_NLS_CONFIG)();
import { ExtensionContext, workspace, window, Disposable, commands, Uri } from 'vscode'; import { ExtensionContext, workspace, window, Disposable, commands, Uri, OutputChannel } from 'vscode';
import { findGit, Git, IGit } from './git'; import { findGit, Git, IGit } from './git';
import { Model } from './model'; import { Model } from './model';
import { CommandCenter } from './commands'; import { CommandCenter } from './commands';
@@ -16,23 +16,19 @@ import { GitDecorations } from './decorationProvider';
import { Askpass } from './askpass'; import { Askpass } from './askpass';
import { toDisposable } from './util'; import { toDisposable } from './util';
import TelemetryReporter from 'vscode-extension-telemetry'; import TelemetryReporter from 'vscode-extension-telemetry';
import { API, createApi } from './api';
async function init(context: ExtensionContext, disposables: Disposable[]): Promise<void> { async function init(context: ExtensionContext, outputChannel: OutputChannel, disposables: Disposable[]): Promise<Model> {
const { name, version, aiKey } = require(context.asAbsolutePath('./package.json')) as { name: string, version: string, aiKey: string }; const { name, version, aiKey } = require(context.asAbsolutePath('./package.json')) as { name: string, version: string, aiKey: string };
const telemetryReporter: TelemetryReporter = new TelemetryReporter(name, version, aiKey); const telemetryReporter: TelemetryReporter = new TelemetryReporter(name, version, aiKey);
disposables.push(telemetryReporter); disposables.push(telemetryReporter);
const outputChannel = window.createOutputChannel('Git');
disposables.push(outputChannel);
const config = workspace.getConfiguration('git');
const enabled = config.get<boolean>('enabled') === true;
const pathHint = workspace.getConfiguration('git').get<string>('path'); const pathHint = workspace.getConfiguration('git').get<string>('path');
const info = await findGit(pathHint); const info = await findGit(pathHint, path => outputChannel.appendLine(localize('looking', "Looking for git in: {0}", path)));
const askpass = new Askpass(); const askpass = new Askpass();
const env = await askpass.getEnv(); const env = await askpass.getEnv();
const git = new Git({ gitPath: info.path, version: info.version, env }); const git = new Git({ gitPath: info.path, version: info.version, env });
const model = new Model(git); const model = new Model(git, context.globalState);
disposables.push(model); disposables.push(model);
const onRepository = () => commands.executeCommand('setContext', 'gitOpenRepositoryCount', `${model.repositories.length}`); const onRepository = () => commands.executeCommand('setContext', 'gitOpenRepositoryCount', `${model.repositories.length}`);
@@ -40,15 +36,9 @@ async function init(context: ExtensionContext, disposables: Disposable[]): Promi
model.onDidCloseRepository(onRepository, null, disposables); model.onDidCloseRepository(onRepository, null, disposables);
onRepository(); onRepository();
if (!enabled) {
const commandCenter = new CommandCenter(git, model, outputChannel, telemetryReporter);
disposables.push(commandCenter);
return;
}
outputChannel.appendLine(localize('using git', "Using git {0} from {1}", info.version, info.path)); outputChannel.appendLine(localize('using git', "Using git {0} from {1}", info.version, info.path));
const onOutput = str => outputChannel.append(str); const onOutput = (str: string) => outputChannel.append(str);
git.onOutput.addListener('log', onOutput); git.onOutput.addListener('log', onOutput);
disposables.push(toDisposable(() => git.onOutput.removeListener('log', onOutput))); disposables.push(toDisposable(() => git.onOutput.removeListener('log', onOutput)));
@@ -59,14 +49,58 @@ async function init(context: ExtensionContext, disposables: Disposable[]): Promi
); );
await checkGitVersion(info); await checkGitVersion(info);
return model;
} }
export function activate(context: ExtensionContext): any { async function _activate(context: ExtensionContext, disposables: Disposable[]): Promise<Model | undefined> {
const outputChannel = window.createOutputChannel('Git');
commands.registerCommand('git.showOutput', () => outputChannel.show());
disposables.push(outputChannel);
try {
return await init(context, outputChannel, disposables);
} catch (err) {
if (!/Git installation not found/.test(err.message || '')) {
throw err;
}
const config = workspace.getConfiguration('git');
const shouldIgnore = config.get<boolean>('ignoreMissingGitWarning') === true;
if (shouldIgnore) {
return;
}
console.warn(err.message);
outputChannel.appendLine(err.message);
outputChannel.show();
const download = localize('downloadgit', "Download Git");
const neverShowAgain = localize('neverShowAgain', "Don't show again");
const choice = await window.showWarningMessage(
localize('notfound', "Git not found. Install it or configure it using the 'git.path' setting."),
download,
neverShowAgain
);
if (choice === download) {
commands.executeCommand('vscode.open', Uri.parse('https://git-scm.com/'));
} else if (choice === neverShowAgain) {
await config.update('ignoreMissingGitWarning', true, true);
}
}
}
export function activate(context: ExtensionContext): API {
const disposables: Disposable[] = []; const disposables: Disposable[] = [];
context.subscriptions.push(new Disposable(() => Disposable.from(...disposables).dispose())); context.subscriptions.push(new Disposable(() => Disposable.from(...disposables).dispose()));
init(context, disposables) const activatePromise = _activate(context, disposables);
.catch(err => console.error(err)); const modelPromise = activatePromise.then(model => model || Promise.reject<Model>('Git model not found'));
activatePromise.catch(err => console.error(err));
return createApi(modelPromise);
} }
async function checkGitVersion(info: IGit): Promise<void> { async function checkGitVersion(info: IGit): Promise<void> {
@@ -102,5 +136,6 @@ async function checkGitVersion(info: IGit): Promise<void> {
} else if (choice === neverShowAgain) { } else if (choice === neverShowAgain) {
await config.update('ignoreLegacyWarning', true, true); await config.update('ignoreLegacyWarning', true, true);
} }
// {{SQL CARBON EDIT}}
*/ */
} }

View File

@@ -5,14 +5,15 @@
'use strict'; 'use strict';
import { workspace, WorkspaceFoldersChangeEvent, Uri, window, Event, EventEmitter, QuickPickItem, Disposable, SourceControl, SourceControlResourceGroup, TextEditor } from 'vscode'; import { workspace, WorkspaceFoldersChangeEvent, Uri, window, Event, EventEmitter, QuickPickItem, Disposable, SourceControl, SourceControlResourceGroup, TextEditor, Memento, ConfigurationChangeEvent } from 'vscode';
import { Repository, RepositoryState } from './repository'; import { Repository, RepositoryState } from './repository';
import { memoize, sequentialize, debounce } from './decorators'; import { memoize, sequentialize, debounce } from './decorators';
import { dispose, anyEvent, filterEvent } from './util'; import { dispose, anyEvent, filterEvent, IDisposable, isDescendant } from './util';
import { Git, GitErrorCodes } from './git'; import { Git, GitErrorCodes } from './git';
import * as path from 'path'; import * as path from 'path';
import * as fs from 'fs'; import * as fs from 'fs';
import * as nls from 'vscode-nls'; import * as nls from 'vscode-nls';
import { fromGitUri } from './uri';
const localize = nls.loadMessageBundle(); const localize = nls.loadMessageBundle();
@@ -44,10 +45,6 @@ interface OpenRepository extends Disposable {
repository: Repository; repository: Repository;
} }
function isParent(parent: string, child: string): boolean {
return child.startsWith(parent);
}
export class Model { export class Model {
private _onDidOpenRepository = new EventEmitter<Repository>(); private _onDidOpenRepository = new EventEmitter<Repository>();
@@ -67,45 +64,17 @@ export class Model {
private possibleGitRepositoryPaths = new Set<string>(); private possibleGitRepositoryPaths = new Set<string>();
private enabled = false;
private configurationChangeDisposable: Disposable;
private disposables: Disposable[] = []; private disposables: Disposable[] = [];
constructor(private git: Git) { constructor(private git: Git, private globalState: Memento) {
const config = workspace.getConfiguration('git');
this.enabled = config.get<boolean>('enabled') === true;
this.configurationChangeDisposable = workspace.onDidChangeConfiguration(this.onDidChangeConfiguration, this);
if (this.enabled) {
this.enable();
}
}
private onDidChangeConfiguration(): void {
const config = workspace.getConfiguration('git');
const enabled = config.get<boolean>('enabled') === true;
if (enabled === this.enabled) {
return;
}
this.enabled = enabled;
if (enabled) {
this.enable();
} else {
this.disable();
}
}
private enable(): void {
workspace.onDidChangeWorkspaceFolders(this.onDidChangeWorkspaceFolders, this, this.disposables); workspace.onDidChangeWorkspaceFolders(this.onDidChangeWorkspaceFolders, this, this.disposables);
this.onDidChangeWorkspaceFolders({ added: workspace.workspaceFolders || [], removed: [] }); this.onDidChangeWorkspaceFolders({ added: workspace.workspaceFolders || [], removed: [] });
window.onDidChangeVisibleTextEditors(this.onDidChangeVisibleTextEditors, this, this.disposables); window.onDidChangeVisibleTextEditors(this.onDidChangeVisibleTextEditors, this, this.disposables);
this.onDidChangeVisibleTextEditors(window.visibleTextEditors); this.onDidChangeVisibleTextEditors(window.visibleTextEditors);
workspace.onDidChangeConfiguration(this.onDidChangeConfiguration, this, this.disposables);
const fsWatcher = workspace.createFileSystemWatcher('**'); const fsWatcher = workspace.createFileSystemWatcher('**');
this.disposables.push(fsWatcher); this.disposables.push(fsWatcher);
@@ -117,15 +86,6 @@ export class Model {
this.scanWorkspaceFolders(); this.scanWorkspaceFolders();
} }
private disable(): void {
const openRepositories = [...this.openRepositories];
openRepositories.forEach(r => r.dispose());
this.openRepositories = [];
this.possibleGitRepositoryPaths.clear();
this.disposables = dispose(this.disposables);
}
/** /**
* Scans the first level of each workspace folder, looking * Scans the first level of each workspace folder, looking
* for git repositories. * for git repositories.
@@ -169,7 +129,21 @@ export class Model {
.map(folder => this.getOpenRepository(folder.uri)) .map(folder => this.getOpenRepository(folder.uri))
.filter(r => !!r) .filter(r => !!r)
.filter(r => !activeRepositories.has(r!.repository)) .filter(r => !activeRepositories.has(r!.repository))
.filter(r => !(workspace.workspaceFolders || []).some(f => isParent(f.uri.fsPath, r!.repository.root))) as OpenRepository[]; .filter(r => !(workspace.workspaceFolders || []).some(f => isDescendant(f.uri.fsPath, r!.repository.root))) as OpenRepository[];
possibleRepositoryFolders.forEach(p => this.tryOpenRepository(p.uri.fsPath));
openRepositoriesToDispose.forEach(r => r.dispose());
}
private onDidChangeConfiguration(): void {
const possibleRepositoryFolders = (workspace.workspaceFolders || [])
.filter(folder => workspace.getConfiguration('git', folder.uri).get<boolean>('enabled') === true)
.filter(folder => !this.getOpenRepository(folder.uri));
const openRepositoriesToDispose = this.openRepositories
.map(repository => ({ repository, root: Uri.file(repository.repository.root) }))
.filter(({ root }) => workspace.getConfiguration('git', root).get<boolean>('enabled') !== true)
.map(({ repository }) => repository);
possibleRepositoryFolders.forEach(p => this.tryOpenRepository(p.uri.fsPath)); possibleRepositoryFolders.forEach(p => this.tryOpenRepository(p.uri.fsPath));
openRepositoriesToDispose.forEach(r => r.dispose()); openRepositoriesToDispose.forEach(r => r.dispose());
@@ -199,6 +173,13 @@ export class Model {
return; return;
} }
const config = workspace.getConfiguration('git', Uri.file(path));
const enabled = config.get<boolean>('enabled') === true;
if (!enabled) {
return;
}
try { try {
const repositoryRoot = await this.git.getRepositoryRoot(path); const repositoryRoot = await this.git.getRepositoryRoot(path);
@@ -209,7 +190,7 @@ export class Model {
return; return;
} }
const repository = new Repository(this.git.open(repositoryRoot)); const repository = new Repository(this.git.open(repositoryRoot), this.globalState);
this.open(repository); this.open(repository);
} catch (err) { } catch (err) {
@@ -292,12 +273,18 @@ export class Model {
} }
if (hint instanceof Uri) { if (hint instanceof Uri) {
const resourcePath = hint.fsPath; let resourcePath: string;
if (hint.scheme === 'git') {
resourcePath = fromGitUri(hint).path;
} else {
resourcePath = hint.fsPath;
}
for (const liveRepository of this.openRepositories) { for (const liveRepository of this.openRepositories) {
const relativePath = path.relative(liveRepository.repository.root, resourcePath); const relativePath = path.relative(liveRepository.repository.root, resourcePath);
if (!/^\.\./.test(relativePath)) { if (isDescendant(liveRepository.repository.root, resourcePath)) {
return liveRepository; return liveRepository;
} }
} }
@@ -321,7 +308,11 @@ export class Model {
} }
dispose(): void { dispose(): void {
this.disable(); const openRepositories = [...this.openRepositories];
this.configurationChangeDisposable.dispose(); openRepositories.forEach(r => r.dispose());
this.openRepositories = [];
this.possibleGitRepositoryPaths.clear();
this.disposables = dispose(this.disposables);
} }
} }

View File

@@ -5,9 +5,9 @@
'use strict'; 'use strict';
import { Uri, Command, EventEmitter, Event, scm, SourceControl, SourceControlInputBox, SourceControlResourceGroup, SourceControlResourceState, SourceControlResourceDecorations, Disposable, ProgressLocation, window, workspace, WorkspaceEdit, ThemeColor, DecorationData } from 'vscode'; import { Uri, Command, EventEmitter, Event, scm, SourceControl, SourceControlInputBox, SourceControlResourceGroup, SourceControlResourceState, SourceControlResourceDecorations, Disposable, ProgressLocation, window, workspace, WorkspaceEdit, ThemeColor, DecorationData, Memento } from 'vscode';
import { Repository as BaseRepository, Ref, Branch, Remote, Commit, GitErrorCodes, Stash, RefType, GitError } from './git'; import { Repository as BaseRepository, Ref, Branch, Remote, Commit, GitErrorCodes, Stash, RefType, GitError } from './git';
import { anyEvent, filterEvent, eventToPromise, dispose, find } from './util'; import { anyEvent, filterEvent, eventToPromise, dispose, find, isDescendant } from './util';
import { memoize, throttle, debounce } from './decorators'; import { memoize, throttle, debounce } from './decorators';
import { toGitUri } from './uri'; import { toGitUri } from './uri';
import { AutoFetcher } from './autofetch'; import { AutoFetcher } from './autofetch';
@@ -82,7 +82,7 @@ export class Resource implements SourceControlResourceState {
get original(): Uri { return this._resourceUri; } get original(): Uri { return this._resourceUri; }
get renameResourceUri(): Uri | undefined { return this._renameResourceUri; } get renameResourceUri(): Uri | undefined { return this._renameResourceUri; }
private static Icons = { private static Icons: any = {
light: { light: {
Modified: getIconUri('status-modified', 'light'), Modified: getIconUri('status-modified', 'light'),
Added: getIconUri('status-added', 'light'), Added: getIconUri('status-added', 'light'),
@@ -171,10 +171,8 @@ export class Resource implements SourceControlResourceState {
} }
get decorations(): SourceControlResourceDecorations { get decorations(): SourceControlResourceDecorations {
// TODO@joh, still requires restart/redraw in the SCM viewlet const light = this._useIcons ? { iconPath: this.getIconPath('light') } : undefined;
const decorations = workspace.getConfiguration().get<boolean>('git.decorations.enabled'); const dark = this._useIcons ? { iconPath: this.getIconPath('dark') } : undefined;
const light = !decorations ? { iconPath: this.getIconPath('light') } : undefined;
const dark = !decorations ? { iconPath: this.getIconPath('dark') } : undefined;
const tooltip = this.tooltip; const tooltip = this.tooltip;
const strikeThrough = this.strikeThrough; const strikeThrough = this.strikeThrough;
const faded = this.faded; const faded = this.faded;
@@ -275,6 +273,7 @@ export class Resource implements SourceControlResourceState {
private _resourceGroupType: ResourceGroupType, private _resourceGroupType: ResourceGroupType,
private _resourceUri: Uri, private _resourceUri: Uri,
private _type: Status, private _type: Status,
private _useIcons: boolean,
private _renameResourceUri?: Uri private _renameResourceUri?: Uri
) { } ) { }
} }
@@ -296,11 +295,13 @@ export enum Operation {
Stage = 'Stage', Stage = 'Stage',
GetCommitTemplate = 'GetCommitTemplate', GetCommitTemplate = 'GetCommitTemplate',
DeleteBranch = 'DeleteBranch', DeleteBranch = 'DeleteBranch',
RenameBranch = 'RenameBranch',
Merge = 'Merge', Merge = 'Merge',
Ignore = 'Ignore', Ignore = 'Ignore',
Tag = 'Tag', Tag = 'Tag',
Stash = 'Stash', Stash = 'Stash',
CheckIgnore = 'CheckIgnore' CheckIgnore = 'CheckIgnore',
LSTree = 'LSTree'
} }
function isReadOnly(operation: Operation): boolean { function isReadOnly(operation: Operation): boolean {
@@ -308,6 +309,7 @@ function isReadOnly(operation: Operation): boolean {
case Operation.Show: case Operation.Show:
case Operation.GetCommitTemplate: case Operation.GetCommitTemplate:
case Operation.CheckIgnore: case Operation.CheckIgnore:
case Operation.LSTree:
return true; return true;
default: default:
return false; return false;
@@ -318,6 +320,8 @@ function shouldShowProgress(operation: Operation): boolean {
switch (operation) { switch (operation) {
case Operation.Fetch: case Operation.Fetch:
case Operation.CheckIgnore: case Operation.CheckIgnore:
case Operation.LSTree:
case Operation.Show:
return false; return false;
default: default:
return true; return true;
@@ -369,12 +373,18 @@ export interface CommitOptions {
amend?: boolean; amend?: boolean;
signoff?: boolean; signoff?: boolean;
signCommit?: boolean; signCommit?: boolean;
defaultMsg?: string;
} }
export interface GitResourceGroup extends SourceControlResourceGroup { export interface GitResourceGroup extends SourceControlResourceGroup {
resourceStates: Resource[]; resourceStates: Resource[];
} }
export interface OperationResult {
operation: Operation;
error: any;
}
export class Repository implements Disposable { export class Repository implements Disposable {
private _onDidChangeRepository = new EventEmitter<Uri>(); private _onDidChangeRepository = new EventEmitter<Uri>();
@@ -384,7 +394,7 @@ export class Repository implements Disposable {
readonly onDidChangeState: Event<RepositoryState> = this._onDidChangeState.event; readonly onDidChangeState: Event<RepositoryState> = this._onDidChangeState.event;
private _onDidChangeStatus = new EventEmitter<void>(); private _onDidChangeStatus = new EventEmitter<void>();
readonly onDidChangeStatus: Event<void> = this._onDidChangeStatus.event; readonly onDidRunGitStatus: Event<void> = this._onDidChangeStatus.event;
private _onDidChangeOriginalResource = new EventEmitter<Uri>(); private _onDidChangeOriginalResource = new EventEmitter<Uri>();
readonly onDidChangeOriginalResource: Event<Uri> = this._onDidChangeOriginalResource.event; readonly onDidChangeOriginalResource: Event<Uri> = this._onDidChangeOriginalResource.event;
@@ -392,8 +402,8 @@ export class Repository implements Disposable {
private _onRunOperation = new EventEmitter<Operation>(); private _onRunOperation = new EventEmitter<Operation>();
readonly onRunOperation: Event<Operation> = this._onRunOperation.event; readonly onRunOperation: Event<Operation> = this._onRunOperation.event;
private _onDidRunOperation = new EventEmitter<Operation>(); private _onDidRunOperation = new EventEmitter<OperationResult>();
readonly onDidRunOperation: Event<Operation> = this._onDidRunOperation.event; readonly onDidRunOperation: Event<OperationResult> = this._onDidRunOperation.event;
@memoize @memoize
get onDidChangeOperations(): Event<void> { get onDidChangeOperations(): Event<void> {
@@ -456,13 +466,14 @@ export class Repository implements Disposable {
private disposables: Disposable[] = []; private disposables: Disposable[] = [];
constructor( constructor(
private readonly repository: BaseRepository private readonly repository: BaseRepository,
globalState: Memento
) { ) {
const fsWatcher = workspace.createFileSystemWatcher('**'); const fsWatcher = workspace.createFileSystemWatcher('**');
this.disposables.push(fsWatcher); this.disposables.push(fsWatcher);
const onWorkspaceChange = anyEvent(fsWatcher.onDidChange, fsWatcher.onDidCreate, fsWatcher.onDidDelete); const onWorkspaceChange = anyEvent(fsWatcher.onDidChange, fsWatcher.onDidCreate, fsWatcher.onDidDelete);
const onRepositoryChange = filterEvent(onWorkspaceChange, uri => !/^\.\./.test(path.relative(repository.root, uri.fsPath))); const onRepositoryChange = filterEvent(onWorkspaceChange, uri => isDescendant(repository.root, uri.fsPath));
const onRelevantRepositoryChange = filterEvent(onRepositoryChange, uri => !/\/\.git\/index\.lock$/.test(uri.path)); const onRelevantRepositoryChange = filterEvent(onRepositoryChange, uri => !/\/\.git\/index\.lock$/.test(uri.path));
onRelevantRepositoryChange(this.onFSChange, this, this.disposables); onRelevantRepositoryChange(this.onFSChange, this, this.disposables);
@@ -470,6 +481,7 @@ export class Repository implements Disposable {
onRelevantGitChange(this._onDidChangeRepository.fire, this._onDidChangeRepository, this.disposables); onRelevantGitChange(this._onDidChangeRepository.fire, this._onDidChangeRepository, this.disposables);
this._sourceControl = scm.createSourceControl('git', 'Git', Uri.file(repository.root)); this._sourceControl = scm.createSourceControl('git', 'Git', Uri.file(repository.root));
this._sourceControl.inputBox.placeholder = localize('commitMessage', "Message (press {0} to commit)");
this._sourceControl.acceptInputCommand = { command: 'git.commitWithInput', title: localize('commit', "Commit"), arguments: [this._sourceControl] }; this._sourceControl.acceptInputCommand = { command: 'git.commitWithInput', title: localize('commit', "Commit"), arguments: [this._sourceControl] };
this._sourceControl.quickDiffProvider = this; this._sourceControl.quickDiffProvider = this;
this.disposables.push(this._sourceControl); this.disposables.push(this._sourceControl);
@@ -485,7 +497,7 @@ export class Repository implements Disposable {
this.disposables.push(this.indexGroup); this.disposables.push(this.indexGroup);
this.disposables.push(this.workingTreeGroup); this.disposables.push(this.workingTreeGroup);
this.disposables.push(new AutoFetcher(this)); this.disposables.push(new AutoFetcher(this, globalState));
const statusBar = new StatusBarCommands(this); const statusBar = new StatusBarCommands(this);
this.disposables.push(statusBar); this.disposables.push(statusBar);
@@ -598,6 +610,10 @@ export class Repository implements Disposable {
await this.run(Operation.DeleteBranch, () => this.repository.deleteBranch(name, force)); await this.run(Operation.DeleteBranch, () => this.repository.deleteBranch(name, force));
} }
async renameBranch(name: string): Promise<void> {
await this.run(Operation.RenameBranch, () => this.repository.renameBranch(name));
}
async merge(ref: string): Promise<void> { async merge(ref: string): Promise<void> {
await this.run(Operation.Merge, () => this.repository.merge(ref)); await this.run(Operation.Merge, () => this.repository.merge(ref));
} }
@@ -650,10 +666,9 @@ export class Repository implements Disposable {
await this.run(Operation.Push, () => this.repository.push(remote, undefined, false, true)); await this.run(Operation.Push, () => this.repository.push(remote, undefined, false, true));
} }
@throttle private async _sync(rebase: boolean): Promise<void> {
async sync(): Promise<void> {
await this.run(Operation.Sync, async () => { await this.run(Operation.Sync, async () => {
await this.repository.pull(); await this.repository.pull(rebase);
const shouldPush = this.HEAD && typeof this.HEAD.ahead === 'number' ? this.HEAD.ahead > 0 : true; const shouldPush = this.HEAD && typeof this.HEAD.ahead === 'number' ? this.HEAD.ahead > 0 : true;
@@ -663,22 +678,52 @@ export class Repository implements Disposable {
}); });
} }
@throttle
sync(): Promise<void> {
return this._sync(false);
}
@throttle
async syncRebase(): Promise<void> {
return this._sync(true);
}
async show(ref: string, filePath: string): Promise<string> { async show(ref: string, filePath: string): Promise<string> {
return await this.run(Operation.Show, async () => { return await this.run(Operation.Show, async () => {
const relativePath = path.relative(this.repository.root, filePath).replace(/\\/g, '/'); const relativePath = path.relative(this.repository.root, filePath).replace(/\\/g, '/');
const configFiles = workspace.getConfiguration('files', Uri.file(filePath)); const configFiles = workspace.getConfiguration('files', Uri.file(filePath));
const encoding = configFiles.get<string>('encoding'); const encoding = configFiles.get<string>('encoding');
return await this.repository.buffer(`${ref}:${relativePath}`, encoding); // TODO@joao: Resource config api
return await this.repository.bufferString(`${ref}:${relativePath}`, encoding);
}); });
} }
async buffer(ref: string, filePath: string): Promise<Buffer> {
return await this.run(Operation.Show, async () => {
const relativePath = path.relative(this.repository.root, filePath).replace(/\\/g, '/');
const configFiles = workspace.getConfiguration('files', Uri.file(filePath));
const encoding = configFiles.get<string>('encoding');
// TODO@joao: REsource config api
return await this.repository.buffer(`${ref}:${relativePath}`);
});
}
lstree(ref: string, filePath: string): Promise<{ mode: number, object: string, size: number }> {
return this.run(Operation.LSTree, () => this.repository.lstree(ref, filePath));
}
detectObjectType(object: string): Promise<{ mimetype: string, encoding?: string }> {
return this.run(Operation.Show, () => this.repository.detectObjectType(object));
}
async getStashes(): Promise<Stash[]> { async getStashes(): Promise<Stash[]> {
return await this.repository.getStashes(); return await this.repository.getStashes();
} }
async createStash(message?: string): Promise<void> { async createStash(message?: string, includeUntracked?: boolean): Promise<void> {
return await this.run(Operation.Stash, () => this.repository.createStash(message)); return await this.run(Operation.Stash, () => this.repository.createStash(message, includeUntracked));
} }
async popStash(index?: number): Promise<void> { async popStash(index?: number): Promise<void> {
@@ -715,7 +760,8 @@ export class Repository implements Disposable {
return this.run(Operation.CheckIgnore, () => { return this.run(Operation.CheckIgnore, () => {
return new Promise<Set<string>>((resolve, reject) => { return new Promise<Set<string>>((resolve, reject) => {
filePaths = filePaths.filter(filePath => !path.relative(this.root, filePath).startsWith('..')); filePaths = filePaths
.filter(filePath => isDescendant(this.root, filePath));
if (filePaths.length === 0) { if (filePaths.length === 0) {
// nothing left // nothing left
@@ -726,7 +772,7 @@ export class Repository implements Disposable {
const child = this.repository.stream(['check-ignore', '-z', '--stdin'], { stdio: [null, null, null] }); const child = this.repository.stream(['check-ignore', '-z', '--stdin'], { stdio: [null, null, null] });
child.stdin.end(filePaths.join('\0'), 'utf8'); child.stdin.end(filePaths.join('\0'), 'utf8');
const onExit = exitCode => { const onExit = (exitCode: number) => {
if (exitCode === 1) { if (exitCode === 1) {
// nothing ignored // nothing ignored
resolve(new Set<string>()); resolve(new Set<string>());
@@ -762,6 +808,8 @@ export class Repository implements Disposable {
} }
const run = async () => { const run = async () => {
let error: any = null;
this._operations.start(operation); this._operations.start(operation);
this._onRunOperation.fire(operation); this._onRunOperation.fire(operation);
@@ -774,6 +822,8 @@ export class Repository implements Disposable {
return result; return result;
} catch (err) { } catch (err) {
error = err;
if (err.gitErrorCode === GitErrorCodes.NotAGitRepository) { if (err.gitErrorCode === GitErrorCodes.NotAGitRepository) {
this.state = RepositoryState.Disposed; this.state = RepositoryState.Disposed;
} }
@@ -781,7 +831,7 @@ export class Repository implements Disposable {
throw err; throw err;
} finally { } finally {
this._operations.end(operation); this._operations.end(operation);
this._onDidRunOperation.fire(operation); this._onDidRunOperation.fire({ operation, error });
} }
}; };
@@ -813,6 +863,7 @@ export class Repository implements Disposable {
const { status, didHitLimit } = await this.repository.getStatus(); const { status, didHitLimit } = await this.repository.getStatus();
const config = workspace.getConfiguration('git'); const config = workspace.getConfiguration('git');
const shouldIgnore = config.get<boolean>('ignoreLimitWarning') === true; const shouldIgnore = config.get<boolean>('ignoreLimitWarning') === true;
const useIcons = !config.get<boolean>('decorations.enabled', true);
this.isRepositoryHuge = didHitLimit; this.isRepositoryHuge = didHitLimit;
@@ -860,30 +911,30 @@ export class Repository implements Disposable {
const renameUri = raw.rename ? Uri.file(path.join(this.repository.root, raw.rename)) : undefined; const renameUri = raw.rename ? Uri.file(path.join(this.repository.root, raw.rename)) : undefined;
switch (raw.x + raw.y) { switch (raw.x + raw.y) {
case '??': return workingTree.push(new Resource(ResourceGroupType.WorkingTree, uri, Status.UNTRACKED)); case '??': return workingTree.push(new Resource(ResourceGroupType.WorkingTree, uri, Status.UNTRACKED, useIcons));
case '!!': return workingTree.push(new Resource(ResourceGroupType.WorkingTree, uri, Status.IGNORED)); case '!!': return workingTree.push(new Resource(ResourceGroupType.WorkingTree, uri, Status.IGNORED, useIcons));
case 'DD': return merge.push(new Resource(ResourceGroupType.Merge, uri, Status.BOTH_DELETED)); case 'DD': return merge.push(new Resource(ResourceGroupType.Merge, uri, Status.BOTH_DELETED, useIcons));
case 'AU': return merge.push(new Resource(ResourceGroupType.Merge, uri, Status.ADDED_BY_US)); case 'AU': return merge.push(new Resource(ResourceGroupType.Merge, uri, Status.ADDED_BY_US, useIcons));
case 'UD': return merge.push(new Resource(ResourceGroupType.Merge, uri, Status.DELETED_BY_THEM)); case 'UD': return merge.push(new Resource(ResourceGroupType.Merge, uri, Status.DELETED_BY_THEM, useIcons));
case 'UA': return merge.push(new Resource(ResourceGroupType.Merge, uri, Status.ADDED_BY_THEM)); case 'UA': return merge.push(new Resource(ResourceGroupType.Merge, uri, Status.ADDED_BY_THEM, useIcons));
case 'DU': return merge.push(new Resource(ResourceGroupType.Merge, uri, Status.DELETED_BY_US)); case 'DU': return merge.push(new Resource(ResourceGroupType.Merge, uri, Status.DELETED_BY_US, useIcons));
case 'AA': return merge.push(new Resource(ResourceGroupType.Merge, uri, Status.BOTH_ADDED)); case 'AA': return merge.push(new Resource(ResourceGroupType.Merge, uri, Status.BOTH_ADDED, useIcons));
case 'UU': return merge.push(new Resource(ResourceGroupType.Merge, uri, Status.BOTH_MODIFIED)); case 'UU': return merge.push(new Resource(ResourceGroupType.Merge, uri, Status.BOTH_MODIFIED, useIcons));
} }
let isModifiedInIndex = false; let isModifiedInIndex = false;
switch (raw.x) { switch (raw.x) {
case 'M': index.push(new Resource(ResourceGroupType.Index, uri, Status.INDEX_MODIFIED)); isModifiedInIndex = true; break; case 'M': index.push(new Resource(ResourceGroupType.Index, uri, Status.INDEX_MODIFIED, useIcons)); isModifiedInIndex = true; break;
case 'A': index.push(new Resource(ResourceGroupType.Index, uri, Status.INDEX_ADDED)); break; case 'A': index.push(new Resource(ResourceGroupType.Index, uri, Status.INDEX_ADDED, useIcons)); break;
case 'D': index.push(new Resource(ResourceGroupType.Index, uri, Status.INDEX_DELETED)); break; case 'D': index.push(new Resource(ResourceGroupType.Index, uri, Status.INDEX_DELETED, useIcons)); break;
case 'R': index.push(new Resource(ResourceGroupType.Index, uri, Status.INDEX_RENAMED, renameUri)); break; case 'R': index.push(new Resource(ResourceGroupType.Index, uri, Status.INDEX_RENAMED, useIcons, renameUri)); break;
case 'C': index.push(new Resource(ResourceGroupType.Index, uri, Status.INDEX_COPIED, renameUri)); break; case 'C': index.push(new Resource(ResourceGroupType.Index, uri, Status.INDEX_COPIED, useIcons, renameUri)); break;
} }
switch (raw.y) { switch (raw.y) {
case 'M': workingTree.push(new Resource(ResourceGroupType.WorkingTree, uri, Status.MODIFIED, renameUri)); break; case 'M': workingTree.push(new Resource(ResourceGroupType.WorkingTree, uri, Status.MODIFIED, useIcons, renameUri)); break;
case 'D': workingTree.push(new Resource(ResourceGroupType.WorkingTree, uri, Status.DELETED, renameUri)); break; case 'D': workingTree.push(new Resource(ResourceGroupType.WorkingTree, uri, Status.DELETED, useIcons, renameUri)); break;
} }
}); });

View File

@@ -20,7 +20,7 @@ class CheckoutStatusBar {
private disposables: Disposable[] = []; private disposables: Disposable[] = [];
constructor(private repository: Repository) { constructor(private repository: Repository) {
repository.onDidChangeStatus(this._onDidChange.fire, this._onDidChange, this.disposables); repository.onDidRunGitStatus(this._onDidChange.fire, this._onDidChange, this.disposables);
} }
get command(): Command | undefined { get command(): Command | undefined {
@@ -65,7 +65,7 @@ class SyncStatusBar {
} }
constructor(private repository: Repository) { constructor(private repository: Repository) {
repository.onDidChangeStatus(this.onModelChange, this, this.disposables); repository.onDidRunGitStatus(this.onModelChange, this, this.disposables);
repository.onDidChangeOperations(this.onOperationsChange, this, this.disposables); repository.onDidChangeOperations(this.onOperationsChange, this, this.disposables);
this._onDidChange.fire(); this._onDidChange.fire();
} }

View File

@@ -5,6 +5,7 @@
'use strict'; 'use strict';
import 'mocha';
import { GitStatusParser } from '../git'; import { GitStatusParser } from '../git';
import * as assert from 'assert'; import * as assert from 'assert';

View File

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

View File

@@ -6,7 +6,8 @@
'use strict'; 'use strict';
import { Event } from 'vscode'; import { Event } from 'vscode';
import { dirname } from 'path'; import { dirname, sep } from 'path';
import { Readable } from 'stream';
import * as fs from 'fs'; import * as fs from 'fs';
import * as byline from 'byline'; import * as byline from 'byline';
@@ -86,7 +87,7 @@ export function once(fn: (...args: any[]) => any): (...args: any[]) => any {
export function assign<T>(destination: T, ...sources: any[]): T { export function assign<T>(destination: T, ...sources: any[]): T {
for (const source of sources) { for (const source of sources) {
Object.keys(source).forEach(key => destination[key] = source[key]); Object.keys(source).forEach(key => (destination as any)[key] = source[key]);
} }
return destination; return destination;
@@ -115,12 +116,12 @@ export function groupBy<T>(arr: T[], fn: (el: T) => string): { [key: string]: T[
}, Object.create(null)); }, Object.create(null));
} }
export function denodeify<R>(fn: Function): (...args) => Promise<R> { export function denodeify<R>(fn: Function): (...args: any[]) => Promise<R> {
return (...args) => new Promise<R>((c, e) => fn(...args, (err, r) => err ? e(err) : c(r))); return (...args) => new Promise<R>((c, e) => fn(...args, (err: any, r: any) => err ? e(err) : c(r)));
} }
export function nfcall<R>(fn: Function, ...args): Promise<R> { export function nfcall<R>(fn: Function, ...args: any[]): Promise<R> {
return new Promise<R>((c, e) => fn(...args, (err, r) => err ? e(err) : c(r))); return new Promise<R>((c, e) => fn(...args, (err: any, r: any) => err ? e(err) : c(r)));
} }
export async function mkdirp(path: string, mode?: number): Promise<boolean> { export async function mkdirp(path: string, mode?: number): Promise<boolean> {
@@ -205,4 +206,83 @@ export async function grep(filename: string, pattern: RegExp): Promise<boolean>
stream.on('error', e); stream.on('error', e);
stream.on('end', () => c(false)); stream.on('end', () => c(false));
}); });
} }
export function readBytes(stream: Readable, bytes: number): Promise<Buffer> {
return new Promise<Buffer>((complete, error) => {
let done = false;
let buffer = new Buffer(bytes);
let bytesRead = 0;
stream.on('data', (data: Buffer) => {
let bytesToRead = Math.min(bytes - bytesRead, data.length);
data.copy(buffer, bytesRead, 0, bytesToRead);
bytesRead += bytesToRead;
if (bytesRead === bytes) {
(stream as any).destroy(); // Will trigger the close event eventually
}
});
stream.on('error', (e: Error) => {
if (!done) {
done = true;
error(e);
}
});
stream.on('close', () => {
if (!done) {
done = true;
complete(buffer.slice(0, bytesRead));
}
});
});
}
export enum Encoding {
UTF8 = 'utf8',
UTF16be = 'utf16be',
UTF16le = 'utf16le'
}
export function detectUnicodeEncoding(buffer: Buffer): Encoding | null {
if (buffer.length < 2) {
return null;
}
const b0 = buffer.readUInt8(0);
const b1 = buffer.readUInt8(1);
if (b0 === 0xFE && b1 === 0xFF) {
return Encoding.UTF16be;
}
if (b0 === 0xFF && b1 === 0xFE) {
return Encoding.UTF16le;
}
if (buffer.length < 3) {
return null;
}
const b2 = buffer.readUInt8(2);
if (b0 === 0xEF && b1 === 0xBB && b2 === 0xBF) {
return Encoding.UTF8;
}
return null;
}
export function isDescendant(parent: string, descendant: string): boolean {
if (parent === descendant) {
return true;
}
if (parent.charAt(parent.length - 1) !== sep) {
parent += sep;
}
return descendant.startsWith(parent);
}

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