Merge branch 'master' into dw-windows-separate-channels

This commit is contained in:
Rafael Oleza 2019-06-25 15:49:34 +02:00
commit b6644dfad8
85 changed files with 2825 additions and 2708 deletions

View File

@ -1,4 +1,4 @@
**/spec/fixtures/**/*.js **/spec/fixtures/**/*.js
node_modules node_modules
/vendor/ /vendor/
/out/ /out/

View File

@ -1,41 +0,0 @@
---
name: Feature request
about: Suggest an idea for this project
---
<!--
Have you read Atom's Code of Conduct? By filing an Issue, you are expected to comply with it, including treating everyone with respect: https://github.com/atom/atom/blob/master/CODE_OF_CONDUCT.md
Do you want to ask a question? Are you looking for support? The Atom message board is the best place for getting support: https://discuss.atom.io
---
Keep in mind that Atom is highly customizable in a number of ways and we strongly prefer that you consider these options before filing this issue:
* https://flight-manual.atom.io/using-atom/sections/basic-customization/: tweak Atom's configuration, styles, and keybindings.
* https://flight-manual.atom.io/using-atom/sections/atom-packages/: install a community package.
* https://flight-manual.atom.io/hacking-atom/: use the Atom API in your init script, to create a package, or to enhance an existing package.
If you're convinced that none of these options are appropriate for the feature you want, please explain why that's the case by completely filling out the issue template below.
Also note that the Atom team has finite resources so it's unlikely that we'll work on feature requests. If we're interested in a particular feature however, we'll follow up and ask you to submit an RFC to talk about it in more detail.
-->
## Summary
One paragraph explanation of the feature.
## Motivation
Why are we doing this? What use cases does it support? What is the expected outcome?
## Describe alternatives you've considered
A clear and concise description of the alternative solutions you've considered. Be sure to explain why Atom's existing customizability isn't suitable for this feature.
## Additional context
Add any other context or screenshots about the feature request here.

View File

@ -1,46 +0,0 @@
---
name: Bug report
about: Create a report to help us improve
---
<!--
Have you read Atom's Code of Conduct? By filing an Issue, you are expected to comply with it, including treating everyone with respect: https://github.com/atom/atom/blob/master/CODE_OF_CONDUCT.md
Do you want to ask a question? Are you looking for support? The Atom message board is the best place for getting support: https://discuss.atom.io
-->
### Prerequisites
* [ ] Put an X between the brackets on this line if you have done all of the following:
* Reproduced the problem in Safe Mode: https://flight-manual.atom.io/hacking-atom/sections/debugging/#using-safe-mode
* Followed all applicable steps in the debugging guide: https://flight-manual.atom.io/hacking-atom/sections/debugging/
* Checked the FAQs on the message board for common solutions: https://discuss.atom.io/c/faq
* Checked that your issue isn't already filed: https://github.com/issues?utf8=✓&q=is%3Aissue+user%3Aatom
* Checked that there is not already an Atom package that provides the described functionality: https://atom.io/packages
### Description
[Description of the issue]
### Steps to Reproduce
1. [First Step]
2. [Second Step]
3. [and so on...]
**Expected behavior:** [What you expect to happen]
**Actual behavior:** [What actually happens]
**Reproduces how often:** [What percentage of the time does it reproduce?]
### Versions
You can get this information from copy and pasting the output of `atom --version` and `apm --version` from the command line. Also, please include the OS and what version of the OS you're running.
### Additional Information
Any additional information, configuration or data that might be necessary to reproduce the issue.

View File

@ -1,59 +0,0 @@
### Requirements for Contributing a Bug Fix
* Fill out the template below. Any pull request that does not include enough information to be reviewed in a timely manner may be closed at the maintainers' discretion.
* The pull request must only fix an existing bug. To contribute other changes, you must use a different template. You can see all templates at https://github.com/atom/atom/tree/master/.github/PULL_REQUEST_TEMPLATE.
* The pull request must update the test suite to demonstrate the changed functionality. For guidance, please see https://flight-manual.atom.io/hacking-atom/sections/writing-specs/.
* After you create the pull request, all status checks must be pass before a maintainer reviews your contribution. For more details, please see https://github.com/atom/atom/tree/master/CONTRIBUTING.md#pull-requests.
### Identify the Bug
<!--
Link to the issue describing the bug that you're fixing.
If there is not yet an issue for your bug, please open a new issue and then link to that issue in your pull request.
Note: In some cases, one person's "bug" is another person's "feature." If the pull request does not address an existing issue with the "bug" label, the maintainers have the final say on whether the current behavior is a bug.
-->
### Description of the Change
<!--
We must be able to understand the design of your change from this description. If we can't get a good idea of what the code will be doing from the description here, the pull request may be closed at the maintainers' discretion. Keep in mind that the maintainer reviewing this PR may not be familiar with or have worked with the code here recently, so please walk us through the concepts.
-->
### Alternate Designs
<!-- Explain what other alternates were considered and why the proposed version was selected -->
### Possible Drawbacks
<!-- What are the possible side-effects or negative impacts of the code change? -->
### Verification Process
<!--
What process did you follow to verify that the change has not introduced any regressions? Describe the actions you performed (including buttons you clicked, text you typed, commands you ran, etc.), and describe the results you observed.
-->
### Release Notes
<!--
Please describe the changes in a single line that explains this improvement in
terms that a user can understand. This text will be used in Atom's release notes.
If this change is not user-facing or notable enough to be included in release notes
you may use the strings "Not applicable" or "N/A" here.
Examples:
- The GitHub package now allows you to add co-authors to commits.
- Fixed an issue where multiple cursors did not work in a file with a single line.
- Increased the performance of searching and replacing across a whole project.
-->

View File

@ -1,30 +0,0 @@
### Requirements for Contributing Documentation
* Fill out the template below. Any pull request that does not include enough information to be reviewed in a timely manner may be closed at the maintainers' discretion.
* The pull request must only contribute documentation (for example, markdown files or API docs). To contribute other changes, you must use a different template. You can see all templates at https://github.com/atom/atom/tree/master/.github/PULL_REQUEST_TEMPLATE.
### Description of the Change
<!--
We must be able to understand the purpose of your change from this description. If we can't get a good idea of the benefits of the change from the description here, the pull request may be closed at the maintainers' discretion.
-->
### Release Notes
<!--
Please describe the changes in a single line that explains this improvement in
terms that a user can understand. This text will be used in Atom's release notes.
If this change is not user-facing or notable enough to be included in release notes
you may use the strings "Not applicable" or "N/A" here.
Examples:
- The GitHub package now allows you to add co-authors to commits.
- Fixed an issue where multiple cursors did not work in a file with a single line.
- Increased the performance of searching and replacing across a whole project.
-->

View File

@ -1,70 +0,0 @@
### Requirements for Adding, Changing, or Removing a Feature
* Fill out the template below. Any pull request that does not include enough information to be reviewed in a timely manner may be closed at the maintainers' discretion.
* The pull request must contribute a change that has been endorsed by the maintainer team. See details in the template below.
* The pull request must update the test suite to exercise the updated functionality. For guidance, please see https://flight-manual.atom.io/hacking-atom/sections/writing-specs/.
* After you create the pull request, all status checks must be pass before a maintainer reviews your contribution. For more details, please see https://github.com/atom/atom/tree/master/CONTRIBUTING.md#pull-requests.
### Issue or RFC Endorsed by Atom's Maintainers
<!--
Link to the issue or RFC that your change relates to. This must be one of the following:
* An open issue with the `help-wanted` label
* An open issue with the `triaged` label
* An RFC with "accepted" status
To contribute an enhancement that isn't covered by one of the items above, please follow our guide for suggesting an enhancement: https://github.com/atom/atom/blob/master/CONTRIBUTING.md#suggesting-enhancements
To contribute other changes, you must use a different template. You can see all templates at https://github.com/atom/atom/tree/master/.github/PULL_REQUEST_TEMPLATE.
-->
### Description of the Change
<!--
We must be able to understand the design of your change from this description. If we can't get a good idea of what the code will be doing from the description here, the pull request may be closed at the maintainers' discretion. Keep in mind that the maintainer reviewing this PR may not be familiar with or have worked with the code here recently, so please walk us through the concepts.
-->
### Alternate Designs
<!-- Explain what other alternates were considered and why the proposed version was selected -->
### Possible Drawbacks
<!-- What are the possible side-effects or negative impacts of the code change? -->
### Verification Process
<!--
What process did you follow to verify that your change has the desired effects?
- How did you verify that all new functionality works as expected?
- How did you verify that all changed functionality works as expected?
- How did you verify that the change has not introduced any regressions?
Describe the actions you performed (including buttons you clicked, text you typed, commands you ran, etc.), and describe the results you observed.
-->
### Release Notes
<!--
Please describe the changes in a single line that explains this improvement in
terms that a user can understand. This text will be used in Atom's release notes.
If this change is not user-facing or notable enough to be included in release notes
you may use the strings "Not applicable" or "N/A" here.
Examples:
- The GitHub package now allows you to add co-authors to commits.
- Fixed an issue where multiple cursors did not work in a file with a single line.
- Increased the performance of searching and replacing across a whole project.
-->

View File

@ -1,55 +0,0 @@
### Requirements for Contributing a Performance Improvement
* Fill out the template below. Any pull request that does not include enough information to be reviewed in a timely manner may be closed at the maintainers' discretion.
* The pull request must only affect performance of existing functionality. To contribute other changes, you must use a different template. You can see all templates at https://github.com/atom/atom/tree/master/.github/PULL_REQUEST_TEMPLATE.
* After you create the pull request, all status checks must be pass before a maintainer reviews your contribution. For more details, please see https://github.com/atom/atom/tree/master/CONTRIBUTING.md#pull-requests.
### Description of the Change
<!--
We must be able to understand the design of your change from this description. If we can't get a good idea of what the code will be doing from the description here, the pull request may be closed at the maintainers' discretion. Keep in mind that the maintainer reviewing this PR may not be familiar with or have worked with the code here recently, so please walk us through the concepts.
-->
### Quantitative Performance Benefits
<!--
Describe the exact performance improvement observed (for example, reduced time to complete an operation, reduced memory use, etc.). Describe how you measured this change. Bonus points for including graphs that demonstrate the improvement or attached dumps from the built-in profiling tools.
-->
### Possible Drawbacks
<!-- What are the possible side-effects or negative impacts of the code change? -->
### Verification Process
<!--
What process did you follow to verify that the change has not introduced any regressions? Describe the actions you performed (including buttons you clicked, text you typed, commands you ran, etc.), and describe the results you observed.
-->
### Applicable Issues
<!-- Enter any applicable Issues here -->
### Release Notes
<!--
Please describe the changes in a single line that explains this improvement in
terms that a user can understand. This text will be used in Atom's release notes.
If this change is not user-facing or notable enough to be included in release notes
you may use the strings "Not applicable" or "N/A" here.
Examples:
- The GitHub package now allows you to add co-authors to commits.
- Fixed an issue where multiple cursors did not work in a file with a single line.
- Increased the performance of searching and replacing across a whole project.
-->

2
.github/lock.yml vendored
View File

@ -8,7 +8,7 @@ lockComment: >
any recent activity after it was closed. If you can still reproduce this issue in any recent activity after it was closed. If you can still reproduce this issue in
[Safe Mode](https://flight-manual.atom.io/hacking-atom/sections/debugging/#using-safe-mode) [Safe Mode](https://flight-manual.atom.io/hacking-atom/sections/debugging/#using-safe-mode)
then please open a new issue and fill out then please open a new issue and fill out
[the entire issue template](https://github.com/atom/atom/blob/master/ISSUE_TEMPLATE.md) [the entire issue template](https://github.com/atom/.github/blob/master/.github/ISSUE_TEMPLATE/bug_report.md)
to ensure that we have enough information to address your issue. Thanks! to ensure that we have enough information to address your issue. Thanks!
# Issues or pull requests with these labels will not be locked # Issues or pull requests with these labels will not be locked
exemptLabels: exemptLabels:

1
.gitignore vendored
View File

@ -6,6 +6,7 @@ Thumbs.db
.project .project
.svn .svn
.nvm-version .nvm-version
.vscode
node_modules node_modules
npm-debug.log npm-debug.log
debug.log debug.log

View File

@ -1,25 +1,25 @@
language: python language: python
python: python:
- "2.7.13" - '2.7.13'
git: git:
depth: 10 depth: 10
branches: branches:
only: only:
- master - master
- /^[0-9.]+-releases$/ - /^[0-9.]+-releases$/
- /.*-test-travis$/ - /.*-test-travis$/
matrix: matrix:
include: include:
- os: linux - os: linux
dist: trusty dist: trusty
env: NODE_VERSION=8.9.3 DISPLAY=:99.0 CC=clang CXX=clang++ npm_config_clang=1 ATOM_JASMINE_REPORTER=list env: NODE_VERSION=10.2.1 DISPLAY=:99.0 CC=clang CXX=clang++ npm_config_clang=1 ATOM_JASMINE_REPORTER=list
before_install: before_install:
- "/sbin/start-stop-daemon --start --quiet --pidfile /tmp/custom_xvfb_99.pid --make-pidfile --background --exec /usr/bin/Xvfb -- :99 -ac -screen 0 1280x1024x16" - '/sbin/start-stop-daemon --start --quiet --pidfile /tmp/custom_xvfb_99.pid --make-pidfile --background --exec /usr/bin/Xvfb -- :99 -ac -screen 0 1280x1024x16'
install: install:
- git clone https://github.com/creationix/nvm.git /tmp/.nvm - git clone https://github.com/creationix/nvm.git /tmp/.nvm
@ -57,11 +57,11 @@ addons:
target_paths: travis-artifacts/$TRAVIS_BUILD_ID target_paths: travis-artifacts/$TRAVIS_BUILD_ID
apt: apt:
packages: packages:
- build-essential - build-essential
- clang-3.3 - clang-3.3
- fakeroot - fakeroot
- git - git
- libsecret-1-dev - libsecret-1-dev
- rpm - rpm
- libx11-dev - libx11-dev
- libxkbfile-dev - libxkbfile-dev

View File

@ -113,7 +113,7 @@ When we make a significant decision in how we maintain the project and what we c
This section guides you through submitting a bug report for Atom. Following these guidelines helps maintainers and the community understand your report :pencil:, reproduce the behavior :computer: :computer:, and find related reports :mag_right:. This section guides you through submitting a bug report for Atom. Following these guidelines helps maintainers and the community understand your report :pencil:, reproduce the behavior :computer: :computer:, and find related reports :mag_right:.
Before creating bug reports, please check [this list](#before-submitting-a-bug-report) as you might find out that you don't need to create one. When you are creating a bug report, please [include as many details as possible](#how-do-i-submit-a-good-bug-report). Fill out [the required template](ISSUE_TEMPLATE.md), the information it asks for helps us resolve issues faster. Before creating bug reports, please check [this list](#before-submitting-a-bug-report) as you might find out that you don't need to create one. When you are creating a bug report, please [include as many details as possible](#how-do-i-submit-a-good-bug-report). Fill out [the required template](https://github.com/atom/.github/blob/master/.github/ISSUE_TEMPLATE/bug_report.md), the information it asks for helps us resolve issues faster.
> **Note:** If you find a **Closed** issue that seems like it is the same thing that you're experiencing, open a new issue and include a link to the original issue in the body of your new one. > **Note:** If you find a **Closed** issue that seems like it is the same thing that you're experiencing, open a new issue and include a link to the original issue in the body of your new one.
@ -126,7 +126,7 @@ Before creating bug reports, please check [this list](#before-submitting-a-bug-r
#### How Do I Submit A (Good) Bug Report? #### How Do I Submit A (Good) Bug Report?
Bugs are tracked as [GitHub issues](https://guides.github.com/features/issues/). After you've determined [which repository](#atom-and-packages) your bug is related to, create an issue on that repository and provide the following information by filling in [the template](ISSUE_TEMPLATE.md). Bugs are tracked as [GitHub issues](https://guides.github.com/features/issues/). After you've determined [which repository](#atom-and-packages) your bug is related to, create an issue on that repository and provide the following information by filling in [the template](https://github.com/atom/.github/blob/master/.github/ISSUE_TEMPLATE/bug_report.md).
Explain the problem and include additional details to help maintainers reproduce the problem: Explain the problem and include additional details to help maintainers reproduce the problem:
@ -163,7 +163,7 @@ Include details about your configuration and environment:
This section guides you through submitting an enhancement suggestion for Atom, including completely new features and minor improvements to existing functionality. Following these guidelines helps maintainers and the community understand your suggestion :pencil: and find related suggestions :mag_right:. This section guides you through submitting an enhancement suggestion for Atom, including completely new features and minor improvements to existing functionality. Following these guidelines helps maintainers and the community understand your suggestion :pencil: and find related suggestions :mag_right:.
Before creating enhancement suggestions, please check [this list](#before-submitting-an-enhancement-suggestion) as you might find out that you don't need to create one. When you are creating an enhancement suggestion, please [include as many details as possible](#how-do-i-submit-a-good-enhancement-suggestion). Fill in [the template](ISSUE_TEMPLATE.md), including the steps that you imagine you would take if the feature you're requesting existed. Before creating enhancement suggestions, please check [this list](#before-submitting-an-enhancement-suggestion) as you might find out that you don't need to create one. When you are creating an enhancement suggestion, please [include as many details as possible](#how-do-i-submit-a-good-enhancement-suggestion). Fill in [the template](https://github.com/atom/.github/blob/master/.github/ISSUE_TEMPLATE/feature_request.md), including the steps that you imagine you would take if the feature you're requesting existed.
#### Before Submitting An Enhancement Suggestion #### Before Submitting An Enhancement Suggestion

View File

@ -1,40 +0,0 @@
<!--
Have you read Atom's Code of Conduct? By filing an Issue, you are expected to comply with it, including treating everyone with respect: https://github.com/atom/atom/blob/master/CODE_OF_CONDUCT.md
Do you want to ask a question? Are you looking for support? The Atom message board is the best place for getting support: https://discuss.atom.io
-->
### Prerequisites
* [ ] Put an X between the brackets on this line if you have done all of the following:
* Reproduced the problem in Safe Mode: https://flight-manual.atom.io/hacking-atom/sections/debugging/#using-safe-mode
* Followed all applicable steps in the debugging guide: https://flight-manual.atom.io/hacking-atom/sections/debugging/
* Checked the FAQs on the message board for common solutions: https://discuss.atom.io/c/faq
* Checked that your issue isn't already filed: https://github.com/issues?utf8=✓&q=is%3Aissue+user%3Aatom
* Checked that there is not already an Atom package that provides the described functionality: https://atom.io/packages
### Description
[Description of the issue]
### Steps to Reproduce
1. [First Step]
2. [Second Step]
3. [and so on...]
**Expected behavior:** [What you expect to happen]
**Actual behavior:** [What actually happens]
**Reproduces how often:** [What percentage of the time does it reproduce?]
### Versions
You can get this information from copy and pasting the output of `atom --version` and `apm --version` from the command line. Also, please include the OS and what version of the OS you're running.
### Additional Information
Any additional information, configuration or data that might be necessary to reproduce the issue.

View File

@ -1,10 +1,10 @@
⚛👋 Hello there! Welcome. Please follow the steps below to tell us about your contribution. ⚛👋 Hello there! Welcome. Please follow the steps below to tell us about your contribution.
1. Copy the correct template for your contribution 1. Copy the correct template for your contribution
- 🐛 Are you fixing a bug? Copy the template from https://bit.ly/atom-bugfix - 🐛 Are you fixing a bug? Copy the template from <https://bit.ly/atom-bugfix-pr>
- 📈 Are you improving performance? Copy the template from https://bit.ly/atom-perf - 📈 Are you improving performance? Copy the template from <https://bit.ly/atom-perf-pr>
- 📝 Are you updating documentation? Copy the template from https://bit.ly/atom-docs - 📝 Are you updating documentation? Copy the template from <https://bit.ly/atom-docs-pr>
- 💻 Are you changing functionality? Copy the template from https://bit.ly/atom-behavior - 💻 Are you changing functionality? Copy the template from <https://bit.ly/atom-behavior-pr>
2. Replace this text with the contents of the template 2. Replace this text with the contents of the template
3. Fill in all sections of the template 3. Fill in all sections of the template
4. Click "Create pull request" 4. Click "Create pull request"

View File

@ -1,6 +1,6 @@
# Atom # Atom
[![Build status](https://dev.azure.com/github/Atom/_apis/build/status/Atom%20Production%20Branches?branchName=master)](https://dev.azure.com/github/Atom/_build/latest?definitionId=32&branchName=master) [![Linux Build Status](https://travis-ci.org/atom/atom.svg?branch=master)](https://travis-ci.org/atom/atom) [![Windows Build Status](https://ci.appveyor.com/api/projects/status/1tkktwh654w07eim?svg=true)](https://ci.appveyor.com/project/Atom/atom) [![Build status](https://dev.azure.com/github/Atom/_apis/build/status/Atom%20Production%20Branches?branchName=master)](https://dev.azure.com/github/Atom/_build/latest?definitionId=32&branchName=master) [![Linux Build Status](https://travis-ci.org/atom/atom.svg?branch=master)](https://travis-ci.org/atom/atom)
[![Dependency Status](https://david-dm.org/atom/atom.svg)](https://david-dm.org/atom/atom) [![Dependency Status](https://david-dm.org/atom/atom.svg)](https://david-dm.org/atom/atom)
[![Join the Atom Community on Slack](https://atom-slack.herokuapp.com/badge.svg)](https://atom-slack.herokuapp.com) [![Join the Atom Community on Slack](https://atom-slack.herokuapp.com/badge.svg)](https://atom-slack.herokuapp.com)

27
apm/package-lock.json generated
View File

@ -4,9 +4,9 @@
"lockfileVersion": 1, "lockfileVersion": 1,
"dependencies": { "dependencies": {
"atom-package-manager": { "atom-package-manager": {
"version": "2.2.4", "version": "2.3.1",
"resolved": "https://registry.npmjs.org/atom-package-manager/-/atom-package-manager-2.2.4.tgz", "resolved": "https://registry.npmjs.org/atom-package-manager/-/atom-package-manager-2.3.1.tgz",
"integrity": "sha512-Iyfs8FNPH+fDLm2DlzE+71TGGZt0fAO2fchJKUHbMLqxFPBPjOgigViQZxDhb2eBRYi2jLKkbalCa4m21Q8CRA==", "integrity": "sha512-CAys5szBJbqhkizMm32o0+uOTpT9rgPh9TdFX0R//usjOAgDr8iJ7oGNfULPvJzaKnBhrokuniKNumAxVyuauA==",
"requires": { "requires": {
"@atom/plist": "0.4.4", "@atom/plist": "0.4.4",
"asar-require": "0.3.0", "asar-require": "0.3.0",
@ -834,19 +834,12 @@
} }
}, },
"keytar": { "keytar": {
"version": "4.7.0", "version": "4.9.0",
"resolved": "https://registry.npmjs.org/keytar/-/keytar-4.7.0.tgz", "resolved": "https://registry.npmjs.org/keytar/-/keytar-4.9.0.tgz",
"integrity": "sha512-0hLlRRkhdR0068fVQo21hnIndGvacsh9PtAHGAPMPzxFjJwP8idAkVAcbdb1P5B+gterCBa3+4hxL0NPMDlZtw==", "integrity": "sha512-5aKEpnxRWUIhSlRXckqTxomqokV1/tOBe3EdbCDyMjDaoa5AkVHVa1yK+fa2CgJR5MadbJndFWmcDMCq812F4A==",
"requires": { "requires": {
"nan": "2.13.2", "nan": "2.14.0",
"prebuild-install": "5.3.0" "prebuild-install": "5.3.0"
},
"dependencies": {
"nan": {
"version": "2.13.2",
"resolved": "https://registry.npmjs.org/nan/-/nan-2.13.2.tgz",
"integrity": "sha512-TghvYc72wlMGMVMluVo9WRJc0mB8KxxF/gZ4YYFy7V2ZQX9l7rgbPg7vjS9mt6U5HXODVFVI2bOduCzwOMv/lw=="
}
} }
}, },
"klaw": { "klaw": {
@ -3876,9 +3869,9 @@
} }
}, },
"psl": { "psl": {
"version": "1.1.31", "version": "1.1.32",
"resolved": "https://registry.npmjs.org/psl/-/psl-1.1.31.tgz", "resolved": "https://registry.npmjs.org/psl/-/psl-1.1.32.tgz",
"integrity": "sha512-/6pt4+C+T+wZUieKR620OpzN/LlnNKuWjy1iFLQ/UG35JqHlR/89MP1d96dUfkf6Dne3TuLQzOYEYshJ+Hx8mw==" "integrity": "sha512-MHACAkHpihU/REGGPLj4sEfc/XKW2bheigvHO1dUqjaKigMp1C8+WLQYRGgeKFMsw5PMfegZcaN8IDXK/cD0+g=="
}, },
"pump": { "pump": {
"version": "2.0.1", "version": "2.0.1",

View File

@ -6,6 +6,6 @@
"url": "https://github.com/atom/atom.git" "url": "https://github.com/atom/atom.git"
}, },
"dependencies": { "dependencies": {
"atom-package-manager": "2.2.4" "atom-package-manager": "2.3.1"
} }
} }

View File

@ -1,95 +0,0 @@
image: Visual Studio 2015
version: "{build}"
skip_tags: true
clone_folder: c:\projects\atom
clone_depth: 10
branches:
only:
- master
- /^[0-9.]+-releases$/
- /^electron-[0-9.]+$/
platform:
- x64
- x86
environment:
global:
ATOM_DEV_RESOURCE_PATH: c:\projects\atom
ATOM_JASMINE_REPORTER: list
CI: true
NODE_VERSION: 8.9.3
matrix:
- TASK: test
- TASK: installer
matrix:
fast_finish: true
exclude:
- platform: x86
TASK: test
install:
- SET PATH=C:\Program Files\Atom\resources\cli;%PATH%
- ps: Install-Product node $env:NODE_VERSION $env:PLATFORM
- npm install --global npm@6.2.0
build_script:
- CD %APPVEYOR_BUILD_FOLDER%
- IF NOT EXIST C:\tmp MKDIR C:\tmp
- SET SQUIRREL_TEMP=C:\tmp
- IF [%APPVEYOR_REPO_BRANCH:~-9%]==[-releases] IF NOT DEFINED APPVEYOR_PULL_REQUEST_NUMBER SET IS_RELEASE_BRANCH=true
- IF [%APPVEYOR_REPO_BRANCH%]==[master] IF NOT DEFINED APPVEYOR_PULL_REQUEST_NUMBER SET IS_SIGNED_ZIP_BRANCH=true
- IF [%APPVEYOR_REPO_BRANCH:~0,9%]==[electron-] IF NOT DEFINED APPVEYOR_PULL_REQUEST_NUMBER SET IS_SIGNED_ZIP_BRANCH=true
- IF [%TASK%]==[installer] (
IF [%IS_RELEASE_BRANCH%]==[true] (
ECHO Building on release branch - Creating production artifacts &&
script\build.cmd --code-sign --compress-artifacts --create-windows-installer
) ELSE (
IF [%IS_SIGNED_ZIP_BRANCH%]==[true] (
ECHO Building on %APPVEYOR_REPO_BRANCH% branch - Creating signed zips &&
script\build.cmd --code-sign --compress-artifacts
) ELSE (
ECHO Skipping installer build for non-release/non-master branch
)
)
) ELSE (
ECHO Test build only - Not creating artifacts &&
script\build.cmd
)
test_script:
- IF [%TASK%]==[test] (
script\lint.cmd &&
script\test.cmd
) ELSE (
ECHO Skipping tests on installer build matrix row
)
deploy: off
artifacts:
- path: out\AtomSetup.exe
name: AtomSetup.exe
- path: out\atom-windows.zip
name: atom-windows.zip
- path: out\RELEASES
name: RELEASES
- path: out\AtomSetup-x64.exe
name: AtomSetup-x64.exe
- path: out\atom-x64-windows.zip
name: atom-x64-windows.zip
- path: out\RELEASES-x64
name: RELEASES-x64
- path: out\atom-*-delta.nupkg
name: atom-delta.nupkg
- path: out\atom-*-full.nupkg
name: atom-full.nupkg
cache:
- '%APPVEYOR_BUILD_FOLDER%\electron'
- '%USERPROFILE%\.atom\.apm'
- '%USERPROFILE%\.atom\compile-cache'

View File

@ -2,7 +2,7 @@
| System | Travis | AppVeyor/Win | VSTS | Dependencies | | System | Travis | AppVeyor/Win | VSTS | Dependencies |
|--------|--------|--------------|------------|--------------| |--------|--------|--------------|------------|--------------|
| [Atom](https://github.com/atom/atom) | [![Travis Build Status](https://travis-ci.org/atom/atom.svg?branch=master)](https://travis-ci.org/atom/atom) | [![AppVeyor/Wi Build Status](https://ci.appveyor.com/api/projects/status/1tkktwh654w07eim?svg=true)](https://ci.appveyor.com/project/Atom/atom) | [![Build status](https://github.visualstudio.com/Atom/_apis/build/status/Atom%20Production%20Branches?branch=master)](https://github.visualstudio.com/Atom/_build/latest?definitionId=32&branch=master) | [![Dependency Status](https://david-dm.org/atom/atom.svg)](https://david-dm.org/atom/atom) | | [Atom](https://github.com/atom/atom) | [![Travis Build Status](https://travis-ci.org/atom/atom.svg?branch=master)](https://travis-ci.org/atom/atom) | | [![Build status](https://github.visualstudio.com/Atom/_apis/build/status/Atom%20Production%20Branches?branch=master)](https://github.visualstudio.com/Atom/_build/latest?definitionId=32&branch=master) | [![Dependency Status](https://david-dm.org/atom/atom.svg)](https://david-dm.org/atom/atom) |
| [APM](https://github.com/atom/apm) | [![Travis Build Status](https://travis-ci.org/atom/apm.svg?branch=master)](https://travis-ci.org/atom/apm) | [![AppVeyor/Wi Build Status](https://ci.appveyor.com/api/projects/status/j6ixw374a397ugkb/branch/master?svg=true)](https://ci.appveyor.com/project/Atom/apm/branch/master) | | [![Dependency Status](https://david-dm.org/atom/apm.svg)](https://david-dm.org/atom/apm) | | [APM](https://github.com/atom/apm) | [![Travis Build Status](https://travis-ci.org/atom/apm.svg?branch=master)](https://travis-ci.org/atom/apm) | [![AppVeyor/Wi Build Status](https://ci.appveyor.com/api/projects/status/j6ixw374a397ugkb/branch/master?svg=true)](https://ci.appveyor.com/project/Atom/apm/branch/master) | | [![Dependency Status](https://david-dm.org/atom/apm.svg)](https://david-dm.org/atom/apm) |
| [Electron](https://github.com/electron/electron) | [![Travis Build Status](https://travis-ci.org/electron/electron.svg?branch=master)](https://travis-ci.org/electron/electron) | [![AppVeyor/Wi Build Status](https://ci.appveyor.com/api/projects/status/kvxe4byi7jcxbe26/branch/master?svg=true)](https://ci.appveyor.com/project/Atom/electron) | | [![Dependency Status](https://david-dm.org/electron/electron/dev-status.svg)](https://david-dm.org/electron/electron) | [Electron](https://github.com/electron/electron) | [![Travis Build Status](https://travis-ci.org/electron/electron.svg?branch=master)](https://travis-ci.org/electron/electron) | [![AppVeyor/Wi Build Status](https://ci.appveyor.com/api/projects/status/kvxe4byi7jcxbe26/branch/master?svg=true)](https://ci.appveyor.com/project/Atom/electron) | | [![Dependency Status](https://david-dm.org/electron/electron/dev-status.svg)](https://david-dm.org/electron/electron)

580
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@ -1,7 +1,7 @@
{ {
"name": "atom", "name": "atom",
"productName": "Atom", "productName": "Atom",
"version": "1.39.0-dev", "version": "1.40.0-dev",
"description": "A hackable text editor for the 21st Century.", "description": "A hackable text editor for the 21st Century.",
"main": "./src/main-process/main.js", "main": "./src/main-process/main.js",
"repository": { "repository": {
@ -14,7 +14,7 @@
"license": "MIT", "license": "MIT",
"electronVersion": "3.1.10", "electronVersion": "3.1.10",
"dependencies": { "dependencies": {
"@atom/nsfw": "1.0.23", "@atom/nsfw": "1.0.25",
"@atom/source-map-support": "^0.3.4", "@atom/source-map-support": "^0.3.4",
"@atom/watcher": "1.3.1", "@atom/watcher": "1.3.1",
"about": "file:packages/about", "about": "file:packages/about",
@ -29,7 +29,7 @@
"autocomplete-atom-api": "https://www.atom.io/api/packages/autocomplete-atom-api/versions/0.10.7/tarball", "autocomplete-atom-api": "https://www.atom.io/api/packages/autocomplete-atom-api/versions/0.10.7/tarball",
"autocomplete-css": "https://www.atom.io/api/packages/autocomplete-css/versions/0.17.5/tarball", "autocomplete-css": "https://www.atom.io/api/packages/autocomplete-css/versions/0.17.5/tarball",
"autocomplete-html": "https://www.atom.io/api/packages/autocomplete-html/versions/0.8.8/tarball", "autocomplete-html": "https://www.atom.io/api/packages/autocomplete-html/versions/0.8.8/tarball",
"autocomplete-plus": "https://www.atom.io/api/packages/autocomplete-plus/versions/2.42.0/tarball", "autocomplete-plus": "https://www.atom.io/api/packages/autocomplete-plus/versions/2.42.3/tarball",
"autocomplete-snippets": "https://www.atom.io/api/packages/autocomplete-snippets/versions/1.12.1/tarball", "autocomplete-snippets": "https://www.atom.io/api/packages/autocomplete-snippets/versions/1.12.1/tarball",
"autoflow": "file:packages/autoflow", "autoflow": "file:packages/autoflow",
"autosave": "https://www.atom.io/api/packages/autosave/versions/0.24.6/tarball", "autosave": "https://www.atom.io/api/packages/autosave/versions/0.24.6/tarball",
@ -38,7 +38,7 @@
"base16-tomorrow-dark-theme": "file:packages/base16-tomorrow-dark-theme", "base16-tomorrow-dark-theme": "file:packages/base16-tomorrow-dark-theme",
"base16-tomorrow-light-theme": "file:packages/base16-tomorrow-light-theme", "base16-tomorrow-light-theme": "file:packages/base16-tomorrow-light-theme",
"bookmarks": "https://www.atom.io/api/packages/bookmarks/versions/0.46.0/tarball", "bookmarks": "https://www.atom.io/api/packages/bookmarks/versions/0.46.0/tarball",
"bracket-matcher": "https://www.atom.io/api/packages/bracket-matcher/versions/0.91.0/tarball", "bracket-matcher": "https://www.atom.io/api/packages/bracket-matcher/versions/0.91.1/tarball",
"chai": "3.5.0", "chai": "3.5.0",
"chart.js": "^2.3.0", "chart.js": "^2.3.0",
"clear-cut": "^2.0.2", "clear-cut": "^2.0.2",
@ -54,17 +54,17 @@
"etch": "^0.12.6", "etch": "^0.12.6",
"event-kit": "^2.5.3", "event-kit": "^2.5.3",
"exception-reporting": "file:packages/exception-reporting", "exception-reporting": "file:packages/exception-reporting",
"find-and-replace": "https://www.atom.io/api/packages/find-and-replace/versions/0.218.11/tarball", "find-and-replace": "https://www.atom.io/api/packages/find-and-replace/versions/0.218.14/tarball",
"find-parent-dir": "^0.3.0", "find-parent-dir": "^0.3.0",
"first-mate": "7.3.0", "first-mate": "7.4.0",
"focus-trap": "2.4.5", "focus-trap": "2.4.5",
"fs-admin": "^0.1.7", "fs-admin": "^0.5.0",
"fs-plus": "^3.1.1", "fs-plus": "^3.1.1",
"fstream": "0.1.24", "fstream": "0.1.24",
"fuzzaldrin": "^2.1", "fuzzaldrin": "^2.1",
"fuzzy-finder": "https://www.atom.io/api/packages/fuzzy-finder/versions/1.13.5/tarball", "fuzzy-finder": "https://www.atom.io/api/packages/fuzzy-finder/versions/1.13.8/tarball",
"git-diff": "file:packages/git-diff", "git-diff": "file:packages/git-diff",
"git-utils": "5.5.0", "git-utils": "5.6.1",
"github": "https://www.atom.io/api/packages/github/versions/0.29.0/tarball", "github": "https://www.atom.io/api/packages/github/versions/0.29.0/tarball",
"glob": "^7.1.1", "glob": "^7.1.1",
"go-to-line": "file:packages/go-to-line", "go-to-line": "file:packages/go-to-line",
@ -77,19 +77,19 @@
"jasmine-tagged": "^1.1.4", "jasmine-tagged": "^1.1.4",
"key-path-helpers": "^0.4.0", "key-path-helpers": "^0.4.0",
"keybinding-resolver": "https://www.atom.io/api/packages/keybinding-resolver/versions/0.39.0/tarball", "keybinding-resolver": "https://www.atom.io/api/packages/keybinding-resolver/versions/0.39.0/tarball",
"language-c": "https://www.atom.io/api/packages/language-c/versions/0.60.17/tarball", "language-c": "https://www.atom.io/api/packages/language-c/versions/0.60.18/tarball",
"language-clojure": "https://www.atom.io/api/packages/language-clojure/versions/0.22.8/tarball", "language-clojure": "https://www.atom.io/api/packages/language-clojure/versions/0.22.8/tarball",
"language-coffee-script": "https://www.atom.io/api/packages/language-coffee-script/versions/0.50.0/tarball", "language-coffee-script": "https://www.atom.io/api/packages/language-coffee-script/versions/0.50.0/tarball",
"language-csharp": "https://www.atom.io/api/packages/language-csharp/versions/1.1.0/tarball", "language-csharp": "https://www.atom.io/api/packages/language-csharp/versions/1.1.0/tarball",
"language-css": "https://www.atom.io/api/packages/language-css/versions/0.44.0/tarball", "language-css": "https://www.atom.io/api/packages/language-css/versions/0.44.0/tarball",
"language-gfm": "https://www.atom.io/api/packages/language-gfm/versions/0.90.6/tarball", "language-gfm": "https://www.atom.io/api/packages/language-gfm/versions/0.90.6/tarball",
"language-git": "https://www.atom.io/api/packages/language-git/versions/0.19.1/tarball", "language-git": "https://www.atom.io/api/packages/language-git/versions/0.19.1/tarball",
"language-go": "https://www.atom.io/api/packages/language-go/versions/0.47.0/tarball", "language-go": "https://www.atom.io/api/packages/language-go/versions/0.47.1/tarball",
"language-html": "https://www.atom.io/api/packages/language-html/versions/0.52.1/tarball", "language-html": "https://www.atom.io/api/packages/language-html/versions/0.52.3/tarball",
"language-hyperlink": "https://www.atom.io/api/packages/language-hyperlink/versions/0.17.1/tarball", "language-hyperlink": "https://www.atom.io/api/packages/language-hyperlink/versions/0.17.1/tarball",
"language-java": "https://www.atom.io/api/packages/language-java/versions/0.31.3/tarball", "language-java": "https://www.atom.io/api/packages/language-java/versions/0.31.3/tarball",
"language-javascript": "https://www.atom.io/api/packages/language-javascript/versions/0.130.0/tarball", "language-javascript": "https://www.atom.io/api/packages/language-javascript/versions/0.130.1/tarball",
"language-json": "https://www.atom.io/api/packages/language-json/versions/1.0.2/tarball", "language-json": "https://www.atom.io/api/packages/language-json/versions/1.0.4/tarball",
"language-less": "https://www.atom.io/api/packages/language-less/versions/0.34.3/tarball", "language-less": "https://www.atom.io/api/packages/language-less/versions/0.34.3/tarball",
"language-make": "https://www.atom.io/api/packages/language-make/versions/0.23.0/tarball", "language-make": "https://www.atom.io/api/packages/language-make/versions/0.23.0/tarball",
"language-mustache": "https://www.atom.io/api/packages/language-mustache/versions/0.14.5/tarball", "language-mustache": "https://www.atom.io/api/packages/language-mustache/versions/0.14.5/tarball",
@ -97,27 +97,27 @@
"language-perl": "https://www.atom.io/api/packages/language-perl/versions/0.38.1/tarball", "language-perl": "https://www.atom.io/api/packages/language-perl/versions/0.38.1/tarball",
"language-php": "https://www.atom.io/api/packages/language-php/versions/0.44.1/tarball", "language-php": "https://www.atom.io/api/packages/language-php/versions/0.44.1/tarball",
"language-property-list": "https://www.atom.io/api/packages/language-property-list/versions/0.9.1/tarball", "language-property-list": "https://www.atom.io/api/packages/language-property-list/versions/0.9.1/tarball",
"language-python": "https://www.atom.io/api/packages/language-python/versions/0.53.2/tarball", "language-python": "https://www.atom.io/api/packages/language-python/versions/0.53.3/tarball",
"language-ruby": "https://www.atom.io/api/packages/language-ruby/versions/0.72.16/tarball", "language-ruby": "https://www.atom.io/api/packages/language-ruby/versions/0.72.17/tarball",
"language-ruby-on-rails": "https://www.atom.io/api/packages/language-ruby-on-rails/versions/0.25.3/tarball", "language-ruby-on-rails": "https://www.atom.io/api/packages/language-ruby-on-rails/versions/0.25.3/tarball",
"language-rust-bundled": "file:packages/language-rust-bundled", "language-rust-bundled": "file:packages/language-rust-bundled",
"language-sass": "https://www.atom.io/api/packages/language-sass/versions/0.62.0/tarball", "language-sass": "https://www.atom.io/api/packages/language-sass/versions/0.62.0/tarball",
"language-shellscript": "https://www.atom.io/api/packages/language-shellscript/versions/0.27.11/tarball", "language-shellscript": "https://www.atom.io/api/packages/language-shellscript/versions/0.27.12/tarball",
"language-source": "https://www.atom.io/api/packages/language-source/versions/0.9.0/tarball", "language-source": "https://www.atom.io/api/packages/language-source/versions/0.9.0/tarball",
"language-sql": "https://www.atom.io/api/packages/language-sql/versions/0.25.10/tarball", "language-sql": "https://www.atom.io/api/packages/language-sql/versions/0.25.10/tarball",
"language-text": "https://www.atom.io/api/packages/language-text/versions/0.7.4/tarball", "language-text": "https://www.atom.io/api/packages/language-text/versions/0.7.4/tarball",
"language-todo": "https://www.atom.io/api/packages/language-todo/versions/0.29.4/tarball", "language-todo": "https://www.atom.io/api/packages/language-todo/versions/0.29.4/tarball",
"language-toml": "https://www.atom.io/api/packages/language-toml/versions/0.20.0/tarball", "language-toml": "https://www.atom.io/api/packages/language-toml/versions/0.20.0/tarball",
"language-typescript": "https://www.atom.io/api/packages/language-typescript/versions/0.5.0/tarball", "language-typescript": "https://www.atom.io/api/packages/language-typescript/versions/0.5.2/tarball",
"language-xml": "https://www.atom.io/api/packages/language-xml/versions/0.35.3/tarball", "language-xml": "https://www.atom.io/api/packages/language-xml/versions/0.35.3/tarball",
"language-yaml": "https://www.atom.io/api/packages/language-yaml/versions/0.32.0/tarball", "language-yaml": "https://www.atom.io/api/packages/language-yaml/versions/0.32.0/tarball",
"less-cache": "1.1.0", "less-cache": "1.1.0",
"line-ending-selector": "file:packages/line-ending-selector", "line-ending-selector": "file:packages/line-ending-selector",
"line-top-index": "0.3.1", "line-top-index": "0.3.1",
"link": "file:packages/link", "link": "file:packages/link",
"markdown-preview": "https://www.atom.io/api/packages/markdown-preview/versions/0.160.0/tarball", "markdown-preview": "https://www.atom.io/api/packages/markdown-preview/versions/0.160.2/tarball",
"marked": "^0.3.12", "marked": "^0.3.12",
"metrics": "https://www.atom.io/api/packages/metrics/versions/1.7.5/tarball", "metrics": "https://www.atom.io/api/packages/metrics/versions/1.8.1/tarball",
"minimatch": "^3.0.3", "minimatch": "^3.0.3",
"mocha": "2.5.1", "mocha": "2.5.1",
"mocha-junit-reporter": "^1.13.0", "mocha-junit-reporter": "^1.13.0",
@ -125,20 +125,20 @@
"mock-spawn": "^0.2.6", "mock-spawn": "^0.2.6",
"normalize-package-data": "^2.0.0", "normalize-package-data": "^2.0.0",
"notifications": "https://www.atom.io/api/packages/notifications/versions/0.70.6/tarball", "notifications": "https://www.atom.io/api/packages/notifications/versions/0.70.6/tarball",
"nslog": "^3", "nslog": "^3.0.0",
"one-dark-syntax": "file:packages/one-dark-syntax", "one-dark-syntax": "file:packages/one-dark-syntax",
"one-dark-ui": "file:packages/one-dark-ui", "one-dark-ui": "file:packages/one-dark-ui",
"one-light-syntax": "file:packages/one-light-syntax", "one-light-syntax": "file:packages/one-light-syntax",
"one-light-ui": "file:packages/one-light-ui", "one-light-ui": "file:packages/one-light-ui",
"open-on-github": "https://www.atom.io/api/packages/open-on-github/versions/1.3.1/tarball", "open-on-github": "https://www.atom.io/api/packages/open-on-github/versions/1.3.1/tarball",
"package-generator": "https://www.atom.io/api/packages/package-generator/versions/1.3.0/tarball", "package-generator": "https://www.atom.io/api/packages/package-generator/versions/1.3.0/tarball",
"pathwatcher": "8.0.2", "pathwatcher": "8.1.0",
"postcss": "5.2.4", "postcss": "5.2.4",
"postcss-selector-parser": "2.2.1", "postcss-selector-parser": "2.2.1",
"property-accessors": "^1.1.3", "property-accessors": "^1.1.3",
"random-words": "0.0.1", "random-words": "0.0.1",
"resolve": "^1.1.6", "resolve": "^1.1.6",
"scandal": "^3.1.0", "scandal": "^3.2.0",
"scoped-property-store": "^0.17.0", "scoped-property-store": "^0.17.0",
"scrollbar-style": "^3.2", "scrollbar-style": "^3.2",
"season": "^6.0.2", "season": "^6.0.2",
@ -149,15 +149,15 @@
"snippets": "https://www.atom.io/api/packages/snippets/versions/1.5.0/tarball", "snippets": "https://www.atom.io/api/packages/snippets/versions/1.5.0/tarball",
"solarized-dark-syntax": "file:packages/solarized-dark-syntax", "solarized-dark-syntax": "file:packages/solarized-dark-syntax",
"solarized-light-syntax": "file:packages/solarized-light-syntax", "solarized-light-syntax": "file:packages/solarized-light-syntax",
"spell-check": "https://www.atom.io/api/packages/spell-check/versions/0.74.5/tarball", "spell-check": "https://www.atom.io/api/packages/spell-check/versions/0.75.0/tarball",
"status-bar": "https://www.atom.io/api/packages/status-bar/versions/1.8.17/tarball", "status-bar": "https://www.atom.io/api/packages/status-bar/versions/1.8.17/tarball",
"styleguide": "https://www.atom.io/api/packages/styleguide/versions/0.49.12/tarball", "styleguide": "https://www.atom.io/api/packages/styleguide/versions/0.49.12/tarball",
"symbols-view": "https://www.atom.io/api/packages/symbols-view/versions/0.118.2/tarball", "symbols-view": "https://www.atom.io/api/packages/symbols-view/versions/0.118.2/tarball",
"tabs": "https://www.atom.io/api/packages/tabs/versions/0.110.0/tarball", "tabs": "https://www.atom.io/api/packages/tabs/versions/0.110.0/tarball",
"temp": "^0.9.0", "temp": "^0.9.0",
"text-buffer": "13.16.0", "text-buffer": "13.17.0",
"timecop": "https://www.atom.io/api/packages/timecop/versions/0.36.2/tarball", "timecop": "https://www.atom.io/api/packages/timecop/versions/0.36.2/tarball",
"tree-sitter": "0.15.0", "tree-sitter": "0.15.6",
"tree-sitter-css": "^0.13.7", "tree-sitter-css": "^0.13.7",
"tree-view": "https://www.atom.io/api/packages/tree-view/versions/0.228.0/tarball", "tree-view": "https://www.atom.io/api/packages/tree-view/versions/0.228.0/tarball",
"typescript-simple": "1.0.0", "typescript-simple": "1.0.0",
@ -187,21 +187,21 @@
"autocomplete-atom-api": "0.10.7", "autocomplete-atom-api": "0.10.7",
"autocomplete-css": "0.17.5", "autocomplete-css": "0.17.5",
"autocomplete-html": "0.8.8", "autocomplete-html": "0.8.8",
"autocomplete-plus": "2.42.0", "autocomplete-plus": "2.42.3",
"autocomplete-snippets": "1.12.1", "autocomplete-snippets": "1.12.1",
"autoflow": "file:./packages/autoflow", "autoflow": "file:./packages/autoflow",
"autosave": "0.24.6", "autosave": "0.24.6",
"background-tips": "0.28.0", "background-tips": "0.28.0",
"bookmarks": "0.46.0", "bookmarks": "0.46.0",
"bracket-matcher": "0.91.0", "bracket-matcher": "0.91.1",
"command-palette": "0.43.5", "command-palette": "0.43.5",
"dalek": "file:./packages/dalek", "dalek": "file:./packages/dalek",
"deprecation-cop": "file:./packages/deprecation-cop", "deprecation-cop": "file:./packages/deprecation-cop",
"dev-live-reload": "file:./packages/dev-live-reload", "dev-live-reload": "file:./packages/dev-live-reload",
"encoding-selector": "0.23.9", "encoding-selector": "0.23.9",
"exception-reporting": "file:./packages/exception-reporting", "exception-reporting": "file:./packages/exception-reporting",
"find-and-replace": "0.218.11", "find-and-replace": "0.218.14",
"fuzzy-finder": "1.13.5", "fuzzy-finder": "1.13.8",
"github": "0.29.0", "github": "0.29.0",
"git-diff": "file:./packages/git-diff", "git-diff": "file:./packages/git-diff",
"go-to-line": "file:./packages/go-to-line", "go-to-line": "file:./packages/go-to-line",
@ -211,14 +211,14 @@
"keybinding-resolver": "0.39.0", "keybinding-resolver": "0.39.0",
"line-ending-selector": "file:./packages/line-ending-selector", "line-ending-selector": "file:./packages/line-ending-selector",
"link": "file:./packages/link", "link": "file:./packages/link",
"markdown-preview": "0.160.0", "markdown-preview": "0.160.2",
"metrics": "1.7.5", "metrics": "1.8.1",
"notifications": "0.70.6", "notifications": "0.70.6",
"open-on-github": "1.3.1", "open-on-github": "1.3.1",
"package-generator": "1.3.0", "package-generator": "1.3.0",
"settings-view": "0.261.3", "settings-view": "0.261.3",
"snippets": "1.5.0", "snippets": "1.5.0",
"spell-check": "0.74.5", "spell-check": "0.75.0",
"status-bar": "1.8.17", "status-bar": "1.8.17",
"styleguide": "0.49.12", "styleguide": "0.49.12",
"symbols-view": "0.118.2", "symbols-view": "0.118.2",
@ -229,19 +229,19 @@
"welcome": "0.36.9", "welcome": "0.36.9",
"whitespace": "0.37.7", "whitespace": "0.37.7",
"wrap-guide": "0.41.0", "wrap-guide": "0.41.0",
"language-c": "0.60.17", "language-c": "0.60.18",
"language-clojure": "0.22.8", "language-clojure": "0.22.8",
"language-coffee-script": "0.50.0", "language-coffee-script": "0.50.0",
"language-csharp": "1.1.0", "language-csharp": "1.1.0",
"language-css": "0.44.0", "language-css": "0.44.0",
"language-gfm": "0.90.6", "language-gfm": "0.90.6",
"language-git": "0.19.1", "language-git": "0.19.1",
"language-go": "0.47.0", "language-go": "0.47.1",
"language-html": "0.52.1", "language-html": "0.52.3",
"language-hyperlink": "0.17.1", "language-hyperlink": "0.17.1",
"language-java": "0.31.3", "language-java": "0.31.3",
"language-javascript": "0.130.0", "language-javascript": "0.130.1",
"language-json": "1.0.2", "language-json": "1.0.4",
"language-less": "0.34.3", "language-less": "0.34.3",
"language-make": "0.23.0", "language-make": "0.23.0",
"language-mustache": "0.14.5", "language-mustache": "0.14.5",
@ -249,18 +249,18 @@
"language-perl": "0.38.1", "language-perl": "0.38.1",
"language-php": "0.44.1", "language-php": "0.44.1",
"language-property-list": "0.9.1", "language-property-list": "0.9.1",
"language-python": "0.53.2", "language-python": "0.53.3",
"language-ruby": "0.72.16", "language-ruby": "0.72.17",
"language-ruby-on-rails": "0.25.3", "language-ruby-on-rails": "0.25.3",
"language-rust-bundled": "file:./packages/language-rust-bundled", "language-rust-bundled": "file:./packages/language-rust-bundled",
"language-sass": "0.62.0", "language-sass": "0.62.0",
"language-shellscript": "0.27.11", "language-shellscript": "0.27.12",
"language-source": "0.9.0", "language-source": "0.9.0",
"language-sql": "0.25.10", "language-sql": "0.25.10",
"language-text": "0.7.4", "language-text": "0.7.4",
"language-todo": "0.29.4", "language-todo": "0.29.4",
"language-toml": "0.20.0", "language-toml": "0.20.0",
"language-typescript": "0.5.0", "language-typescript": "0.5.2",
"language-xml": "0.35.3", "language-xml": "0.35.3",
"language-yaml": "0.32.0" "language-yaml": "0.32.0"
}, },

View File

@ -60,15 +60,25 @@ module.exports =
latexTagRegex = /^\s*\\\w+(\[.*\])?\{\w+\}(\[.*\])?\s*$/g # e.g. \begin{verbatim} latexTagRegex = /^\s*\\\w+(\[.*\])?\{\w+\}(\[.*\])?\s*$/g # e.g. \begin{verbatim}
latexTagStartRegex = /^\s*\\\w+\s*\{\s*$/g # e.g. \item{ latexTagStartRegex = /^\s*\\\w+\s*\{\s*$/g # e.g. \item{
latexTagEndRegex = /^\s*\}\s*$/g # e.g. } latexTagEndRegex = /^\s*\}\s*$/g # e.g. }
while blockLines[0].match(latexTagRegex) or while blockLines.length > 0 and (
blockLines[0].match(latexTagStartRegex) blockLines[0].match(latexTagRegex) or
blockLines[0].match(latexTagStartRegex))
beginningLinesToIgnore.push(blockLines[0]) beginningLinesToIgnore.push(blockLines[0])
blockLines.shift() blockLines.shift()
while blockLines[blockLines.length - 1].match(latexTagRegex) or while blockLines.length > 0 and (
blockLines[blockLines.length - 1].match(latexTagEndRegex) blockLines[blockLines.length - 1].match(latexTagRegex) or
blockLines[blockLines.length - 1].match(latexTagEndRegex))
endingLinesToIgnore.unshift(blockLines[blockLines.length - 1]) endingLinesToIgnore.unshift(blockLines[blockLines.length - 1])
blockLines.pop() blockLines.pop()
# The paragraph might be a LaTeX section with no text, only tags:
# \documentclass{article}
# In that case, we have nothing to reflow.
# Push the tags verbatim and continue to the next paragraph.
unless blockLines.length > 0
paragraphs.push(block)
continue
# TODO: this could be more language specific. Use the actual comment char. # TODO: this could be more language specific. Use the actual comment char.
# Remember that `-` has to be the last character in the character class. # Remember that `-` has to be the last character in the character class.
linePrefix = blockLines[0].match(/^\s*(\/\/|\/\*|;;|#'|\|\|\||--|[#%*>-])?\s*/g)[0] linePrefix = blockLines[0].match(/^\s*(\/\/|\/\*|;;|#'|\|\|\||--|[#%*>-])?\s*/g)[0]
@ -112,7 +122,7 @@ module.exports =
wrappedLines = beginningLinesToIgnore.concat(lines.concat(endingLinesToIgnore)) wrappedLines = beginningLinesToIgnore.concat(lines.concat(endingLinesToIgnore))
paragraphs.push(wrappedLines.join('\n').replace(/\s+\n/g, '\n')) paragraphs.push(wrappedLines.join('\n').replace(/\s+\n/g, '\n'))
leadingVerticalSpace + paragraphs.join('\n\n') + trailingVerticalSpace return leadingVerticalSpace + paragraphs.join('\n\n') + trailingVerticalSpace
getTabLength: (editor) -> getTabLength: (editor) ->
atom.config.get('editor.tabLength', scope: editor.getRootScopeDescriptor()) ? 2 atom.config.get('editor.tabLength', scope: editor.getRootScopeDescriptor()) ? 2

View File

@ -561,70 +561,79 @@ describe "Autoflow package", ->
expect(autoflow.reflow(test, wrapColumn: 80)).toEqual res expect(autoflow.reflow(test, wrapColumn: 80)).toEqual res
it 'properly reflows text around LaTeX tags', -> describe 'LaTeX', ->
text = it 'properly reflows text around LaTeX tags', ->
''' text =
\\begin{verbatim} '''
Lorem ipsum dolor sit amet, nisl odio amet, et tempor netus neque at at blandit, vel vestibulum libero dolor, semper lobortis ligula praesent. Eget condimentum integer, porta sagittis nam, fusce vitae a vitae augue. Nec semper quis sed ut, est porttitor praesent. Nisl velit quam dolore velit quam, elementum neque pellentesque pulvinar et vestibulum. \\begin{verbatim}
\\end{verbatim} Lorem ipsum dolor sit amet, nisl odio amet, et tempor netus neque at at blandit, vel vestibulum libero dolor, semper lobortis ligula praesent. Eget condimentum integer, porta sagittis nam, fusce vitae a vitae augue. Nec semper quis sed ut, est porttitor praesent. Nisl velit quam dolore velit quam, elementum neque pellentesque pulvinar et vestibulum.
''' \\end{verbatim}
'''
res = res =
''' '''
\\begin{verbatim} \\begin{verbatim}
Lorem ipsum dolor sit amet, nisl odio amet, et tempor netus neque at at Lorem ipsum dolor sit amet, nisl odio amet, et tempor netus neque at at
blandit, vel vestibulum libero dolor, semper lobortis ligula praesent. Eget blandit, vel vestibulum libero dolor, semper lobortis ligula praesent. Eget
condimentum integer, porta sagittis nam, fusce vitae a vitae augue. Nec condimentum integer, porta sagittis nam, fusce vitae a vitae augue. Nec
semper quis sed ut, est porttitor praesent. Nisl velit quam dolore velit semper quis sed ut, est porttitor praesent. Nisl velit quam dolore velit
quam, elementum neque pellentesque pulvinar et vestibulum. quam, elementum neque pellentesque pulvinar et vestibulum.
\\end{verbatim} \\end{verbatim}
''' '''
expect(autoflow.reflow(text, wrapColumn: 80)).toEqual res expect(autoflow.reflow(text, wrapColumn: 80)).toEqual res
it 'properly reflows text inside LaTeX tags', -> it 'properly reflows text inside LaTeX tags', ->
text = text =
''' '''
\\item{ \\item{
Lorem ipsum dolor sit amet, nisl odio amet, et tempor netus neque at at blandit, vel vestibulum libero dolor, semper lobortis ligula praesent. Eget condimentum integer, porta sagittis nam, fusce vitae a vitae augue. Nec semper quis sed ut, est porttitor praesent. Nisl velit quam dolore velit quam, elementum neque pellentesque pulvinar et vestibulum. Lorem ipsum dolor sit amet, nisl odio amet, et tempor netus neque at at blandit, vel vestibulum libero dolor, semper lobortis ligula praesent. Eget condimentum integer, porta sagittis nam, fusce vitae a vitae augue. Nec semper quis sed ut, est porttitor praesent. Nisl velit quam dolore velit quam, elementum neque pellentesque pulvinar et vestibulum.
} }
''' '''
res = res =
''' '''
\\item{ \\item{
Lorem ipsum dolor sit amet, nisl odio amet, et tempor netus neque at at Lorem ipsum dolor sit amet, nisl odio amet, et tempor netus neque at at
blandit, vel vestibulum libero dolor, semper lobortis ligula praesent. Eget blandit, vel vestibulum libero dolor, semper lobortis ligula praesent. Eget
condimentum integer, porta sagittis nam, fusce vitae a vitae augue. Nec condimentum integer, porta sagittis nam, fusce vitae a vitae augue. Nec
semper quis sed ut, est porttitor praesent. Nisl velit quam dolore velit semper quis sed ut, est porttitor praesent. Nisl velit quam dolore velit
quam, elementum neque pellentesque pulvinar et vestibulum. quam, elementum neque pellentesque pulvinar et vestibulum.
} }
''' '''
expect(autoflow.reflow(text, wrapColumn: 80)).toEqual res expect(autoflow.reflow(text, wrapColumn: 80)).toEqual res
it 'properly reflows text inside nested LaTeX tags', -> it 'properly reflows text inside nested LaTeX tags', ->
text = text =
''' '''
\\begin{enumerate}[label=(\\alph*)] \\begin{enumerate}[label=(\\alph*)]
\\item{ \\item{
Lorem ipsum dolor sit amet, nisl odio amet, et tempor netus neque at at blandit, vel vestibulum libero dolor, semper lobortis ligula praesent. Eget condimentum integer, porta sagittis nam, fusce vitae a vitae augue. Nec semper quis sed ut, est porttitor praesent. Nisl velit quam dolore velit quam, elementum neque pellentesque pulvinar et vestibulum. Lorem ipsum dolor sit amet, nisl odio amet, et tempor netus neque at at blandit, vel vestibulum libero dolor, semper lobortis ligula praesent. Eget condimentum integer, porta sagittis nam, fusce vitae a vitae augue. Nec semper quis sed ut, est porttitor praesent. Nisl velit quam dolore velit quam, elementum neque pellentesque pulvinar et vestibulum.
} }
\\end{enumerate} \\end{enumerate}
''' '''
res = res =
''' '''
\\begin{enumerate}[label=(\\alph*)] \\begin{enumerate}[label=(\\alph*)]
\\item{ \\item{
Lorem ipsum dolor sit amet, nisl odio amet, et tempor netus neque at at Lorem ipsum dolor sit amet, nisl odio amet, et tempor netus neque at at
blandit, vel vestibulum libero dolor, semper lobortis ligula praesent. blandit, vel vestibulum libero dolor, semper lobortis ligula praesent.
Eget condimentum integer, porta sagittis nam, fusce vitae a vitae augue. Eget condimentum integer, porta sagittis nam, fusce vitae a vitae augue.
Nec semper quis sed ut, est porttitor praesent. Nisl velit quam dolore Nec semper quis sed ut, est porttitor praesent. Nisl velit quam dolore
velit quam, elementum neque pellentesque pulvinar et vestibulum. velit quam, elementum neque pellentesque pulvinar et vestibulum.
} }
\\end{enumerate} \\end{enumerate}
''' '''
expect(autoflow.reflow(text, wrapColumn: 80)).toEqual res expect(autoflow.reflow(text, wrapColumn: 80)).toEqual res
it 'does not attempt to reflow a selection that contains only LaTeX tags and nothing else', ->
text =
'''
\\begin{enumerate}
\\end{enumerate}
'''
expect(autoflow.reflow(text, wrapColumn: 5)).toEqual text

View File

@ -18,9 +18,25 @@ module.exports = class GrammarListView {
const div = document.createElement('div'); const div = document.createElement('div');
div.classList.add('pull-right'); div.classList.add('pull-right');
if (isTreeSitter(grammar)) {
const parser = document.createElement('span');
parser.classList.add(
'grammar-selector-parser',
'badge',
'badge-success'
);
parser.textContent = 'Tree-sitter';
parser.setAttribute(
'title',
'(Recommended) A faster parser with improved syntax highlighting & code navigation support.'
);
div.appendChild(parser);
}
if (grammar.scopeName) { if (grammar.scopeName) {
const scopeName = document.createElement('scopeName'); const scopeName = document.createElement('scopeName');
scopeName.classList.add('key-binding'); // It will be styled the same as the keybindings in the command palette scopeName.classList.add('badge', 'badge-info');
scopeName.textContent = grammar.scopeName; scopeName.textContent = grammar.scopeName;
div.appendChild(scopeName); div.appendChild(scopeName);
element.appendChild(div); element.appendChild(div);
@ -33,7 +49,7 @@ module.exports = class GrammarListView {
if (grammar === this.autoDetect) { if (grammar === this.autoDetect) {
atom.textEditors.clearGrammarOverride(this.editor); atom.textEditors.clearGrammarOverride(this.editor);
} else { } else {
atom.textEditors.setGrammarOverride(this.editor, grammar.scopeName); atom.grammars.assignGrammar(this.editor, grammar);
} }
}, },
didCancelSelection: () => { didCancelSelection: () => {
@ -72,28 +88,44 @@ module.exports = class GrammarListView {
async toggle() { async toggle() {
if (this.panel != null) { if (this.panel != null) {
this.cancel(); this.cancel();
} else if (atom.workspace.getActiveTextEditor()) { return;
this.editor = atom.workspace.getActiveTextEditor(); }
const editor = atom.workspace.getActiveTextEditor();
if (editor) {
this.editor = editor;
this.currentGrammar = this.editor.getGrammar(); this.currentGrammar = this.editor.getGrammar();
if (this.currentGrammar === atom.grammars.nullGrammar) { if (this.currentGrammar === atom.grammars.nullGrammar) {
this.currentGrammar = this.autoDetect; this.currentGrammar = this.autoDetect;
} }
const grammars = atom.grammars.getGrammars().filter(grammar => { let grammars = atom.grammars
return grammar !== atom.grammars.nullGrammar && grammar.name; .getGrammars({ includeTreeSitter: true })
}); .filter(grammar => {
return grammar !== atom.grammars.nullGrammar && grammar.name;
});
if (atom.config.get('grammar-selector.hideDuplicateTextMateGrammars')) {
const blacklist = new Set();
grammars.forEach(grammar => {
if (isTreeSitter(grammar)) {
blacklist.add(grammar.name);
}
});
grammars = grammars.filter(
grammar => isTreeSitter(grammar) || !blacklist.has(grammar.name)
);
}
grammars.sort((a, b) => { grammars.sort((a, b) => {
if (a.scopeName === 'text.plain') { if (a.scopeName === 'text.plain') {
return -1; return -1;
} else if (b.scopeName === 'text.plain') { } else if (b.scopeName === 'text.plain') {
return 1; return 1;
} else if (a.name) { } else if (a.name === b.name) {
return a.name.localeCompare(b.name); return compareGrammarType(a, b);
} else if (a.scopeName) {
return a.scopeName.localeCompare(b.scopeName);
} else {
return 1;
} }
return a.name.localeCompare(b.name);
}); });
grammars.unshift(this.autoDetect); grammars.unshift(this.autoDetect);
await this.selectListView.update({ items: grammars }); await this.selectListView.update({ items: grammars });
@ -101,3 +133,16 @@ module.exports = class GrammarListView {
} }
} }
}; };
function isTreeSitter(grammar) {
return grammar.constructor.name === 'TreeSitterGrammar';
}
function compareGrammarType(a, b) {
if (isTreeSitter(a)) {
return -1;
} else if (isTreeSitter(b)) {
return 1;
}
return 0;
}

View File

@ -37,6 +37,11 @@
"type": "boolean", "type": "boolean",
"default": true, "default": true,
"description": "Show the active pane item's language on the right side of Atom's status bar, instead of the left." "description": "Show the active pane item's language on the right side of Atom's status bar, instead of the left."
},
"hideDuplicateTextMateGrammars": {
"type": "boolean",
"default": true,
"description": "Hides the TextMate grammar when there is an existing Tree-sitter grammar"
} }
} }
} }

View File

@ -7,6 +7,7 @@ describe('GrammarSelector', () => {
beforeEach(async () => { beforeEach(async () => {
jasmine.attachToDOM(atom.views.getView(atom.workspace)); jasmine.attachToDOM(atom.views.getView(atom.workspace));
atom.config.set('grammar-selector.showOnRightSideOfStatusBar', false); atom.config.set('grammar-selector.showOnRightSideOfStatusBar', false);
atom.config.set('grammar-selector.hideDuplicateTextMateGrammars', false);
await atom.packages.activatePackage('status-bar'); await atom.packages.activatePackage('status-bar');
await atom.packages.activatePackage('grammar-selector'); await atom.packages.activatePackage('grammar-selector');
@ -27,21 +28,15 @@ describe('GrammarSelector', () => {
describe('when grammar-selector:show is triggered', () => describe('when grammar-selector:show is triggered', () =>
it('displays a list of all the available grammars', async () => { it('displays a list of all the available grammars', async () => {
atom.commands.dispatch(editor.getElement(), 'grammar-selector:show'); const grammarView = (await getGrammarView(editor)).element;
await SelectListView.getScheduler().getNextUpdatePromise();
const grammarView = atom.workspace.getModalPanels()[0].getItem().element; // -1 for removing nullGrammar, +1 for adding "Auto Detect"
// TODO: Remove once Atom 1.23 reaches stable // Tree-sitter names the regex and JSDoc grammars
if (parseFloat(atom.getVersion()) >= 1.23) { expect(grammarView.querySelectorAll('li').length).toBe(
// Do not take into account the two JS regex grammars or language-with-no-name atom.grammars
expect(grammarView.querySelectorAll('li').length).toBe( .getGrammars({ includeTreeSitter: true })
atom.grammars.grammars.length - 3 .filter(g => g.name).length
); );
} else {
expect(grammarView.querySelectorAll('li').length).toBe(
atom.grammars.grammars.length - 1
);
}
expect(grammarView.querySelectorAll('li')[0].textContent).toBe( expect(grammarView.querySelectorAll('li')[0].textContent).toBe(
'Auto Detect' 'Auto Detect'
); );
@ -51,31 +46,23 @@ describe('GrammarSelector', () => {
.forEach(li => .forEach(li =>
expect(li.textContent).not.toBe(atom.grammars.nullGrammar.name) expect(li.textContent).not.toBe(atom.grammars.nullGrammar.name)
); );
expect(grammarView.textContent.includes('Tree-sitter')).toBe(true); // check we are showing and labelling Tree-sitter grammars
})); }));
describe('when a grammar is selected', () => describe('when a grammar is selected', () =>
it('sets the new grammar on the editor', async () => { it('sets the new grammar on the editor', async () => {
atom.commands.dispatch(editor.getElement(), 'grammar-selector:show'); const grammarView = await getGrammarView(editor);
await SelectListView.getScheduler().getNextUpdatePromise();
const grammarView = atom.workspace.getModalPanels()[0].getItem();
grammarView.props.didConfirmSelection(textGrammar); grammarView.props.didConfirmSelection(textGrammar);
expect(editor.getGrammar()).toBe(textGrammar); expect(editor.getGrammar()).toBe(textGrammar);
})); }));
describe('when auto-detect is selected', () => describe('when auto-detect is selected', () =>
it('restores the auto-detected grammar on the editor', async () => { it('restores the auto-detected grammar on the editor', async () => {
atom.commands.dispatch(editor.getElement(), 'grammar-selector:show'); let grammarView = await getGrammarView(editor);
await SelectListView.getScheduler().getNextUpdatePromise();
let grammarView = atom.workspace.getModalPanels()[0].getItem();
grammarView.props.didConfirmSelection(textGrammar); grammarView.props.didConfirmSelection(textGrammar);
expect(editor.getGrammar()).toBe(textGrammar); expect(editor.getGrammar()).toBe(textGrammar);
atom.commands.dispatch(editor.getElement(), 'grammar-selector:show'); grammarView = await getGrammarView(editor);
await SelectListView.getScheduler().getNextUpdatePromise();
grammarView = atom.workspace.getModalPanels()[0].getItem();
grammarView.props.didConfirmSelection(grammarView.items[0]); grammarView.props.didConfirmSelection(grammarView.items[0]);
expect(editor.getGrammar()).toBe(jsGrammar); expect(editor.getGrammar()).toBe(jsGrammar);
})); }));
@ -83,10 +70,7 @@ describe('GrammarSelector', () => {
describe("when the editor's current grammar is the null grammar", () => describe("when the editor's current grammar is the null grammar", () =>
it('displays Auto Detect as the selected grammar', async () => { it('displays Auto Detect as the selected grammar', async () => {
editor.setGrammar(atom.grammars.nullGrammar); editor.setGrammar(atom.grammars.nullGrammar);
atom.commands.dispatch(editor.getElement(), 'grammar-selector:show'); const grammarView = (await getGrammarView(editor)).element;
await SelectListView.getScheduler().getNextUpdatePromise();
const grammarView = atom.workspace.getModalPanels()[0].getItem().element;
expect(grammarView.querySelector('li.active').textContent).toBe( expect(grammarView.querySelector('li.active').textContent).toBe(
'Auto Detect' 'Auto Detect'
); );
@ -97,10 +81,7 @@ describe('GrammarSelector', () => {
editor = await atom.workspace.open(); editor = await atom.workspace.open();
expect(editor.getGrammar()).not.toBe(jsGrammar); expect(editor.getGrammar()).not.toBe(jsGrammar);
atom.commands.dispatch(editor.getElement(), 'grammar-selector:show'); const grammarView = await getGrammarView(editor);
await SelectListView.getScheduler().getNextUpdatePromise();
const grammarView = atom.workspace.getModalPanels()[0].getItem();
grammarView.props.didConfirmSelection(jsGrammar); grammarView.props.didConfirmSelection(jsGrammar);
expect(editor.getGrammar()).toBe(jsGrammar); expect(editor.getGrammar()).toBe(jsGrammar);
})); }));
@ -199,6 +180,73 @@ describe('GrammarSelector', () => {
); );
})); }));
describe('when toggling hideDuplicateTextMateGrammars', () => {
it('shows only the Tree-sitter if true and both exist', async () => {
// the main JS grammar has both a TextMate and Tree-sitter implementation
atom.config.set('grammar-selector.hideDuplicateTextMateGrammars', true);
const grammarView = await getGrammarView(editor);
const observedNames = new Set();
grammarView.element.querySelectorAll('li').forEach(li => {
const name = li.getAttribute('data-grammar');
expect(observedNames.has(name)).toBe(false);
observedNames.add(name);
});
// check the seen JS is actually the Tree-sitter one
const list = atom.workspace.getModalPanels()[0].item;
for (const item of list.items) {
if (item.name === 'JavaScript') {
expect(item.constructor.name === 'TreeSitterGrammar');
}
}
});
it('shows both if false', async () => {
await atom.packages.activatePackage('language-c'); // punctuation making it sort wrong
atom.config.set(
'grammar-selector.hideDuplicateTextMateGrammars',
false
);
await getGrammarView(editor);
let cppCount = 0;
const listItems = atom.workspace.getModalPanels()[0].item.items;
for (let i = 0; i < listItems.length; i++) {
const grammar = listItems[i];
const name = grammar.name;
if (cppCount === 0 && name === 'C++') {
expect(grammar.constructor.name).toBe('TreeSitterGrammar'); // first C++ entry should be Tree-sitter
cppCount++;
} else if (cppCount === 1) {
expect(name).toBe('C++');
expect(grammar.constructor.name).toBe('Grammar'); // immediate next grammar should be the TextMate version
cppCount++;
} else {
expect(name).not.toBe('C++'); // there should not be any other C++ grammars
}
}
expect(cppCount).toBe(2); // ensure we actually saw both grammars
});
});
describe('for every Tree-sitter grammar', () => {
it('adds a label to identify it as Tree-sitter', async () => {
const grammarView = await getGrammarView(editor);
const elements = grammarView.element.querySelectorAll('li');
const listItems = atom.workspace.getModalPanels()[0].item.items;
for (let i = 0; i < listItems.length; i++) {
if (listItems[i].constructor.name === 'TreeSitterGrammar') {
expect(
elements[i].childNodes[1].childNodes[0].className.startsWith(
'grammar-selector-parser'
)
).toBe(true);
}
}
});
});
describe('when clicked', () => describe('when clicked', () =>
it('shows the grammar selector modal', () => { it('shows the grammar selector modal', () => {
const eventHandler = jasmine.createSpy('eventHandler'); const eventHandler = jasmine.createSpy('eventHandler');
@ -224,3 +272,9 @@ function getTooltipText(element) {
const [tooltip] = atom.tooltips.findTooltips(element); const [tooltip] = atom.tooltips.findTooltips(element);
return tooltip.getTitle(); return tooltip.getTitle();
} }
async function getGrammarView(editor) {
atom.commands.dispatch(editor.getElement(), 'grammar-selector:show');
await SelectListView.getScheduler().getNextUpdatePromise();
return atom.workspace.getModalPanels()[0].getItem();
}

View File

@ -4,3 +4,7 @@
.grammar-status a:hover { .grammar-status a:hover {
color: @text-color; color: @text-color;
} }
.grammar-selector-parser {
margin-right: @component-padding;
}

View File

@ -2,6 +2,7 @@ name: 'Rust'
scopeName: 'source.rust' scopeName: 'source.rust'
type: 'tree-sitter' type: 'tree-sitter'
parser: 'tree-sitter-rust' parser: 'tree-sitter-rust'
injectionRegex: 'rust'
fileTypes: [ fileTypes: [
'rs' 'rs'

View File

@ -0,0 +1,14 @@
exports.activate = function() {
for (const nodeType of ['macro_invocation', 'macro_rule']) {
atom.grammars.addInjectionPoint('source.rust', {
type: nodeType,
language() {
return 'rust';
},
content(node) {
return node.lastChild;
},
includeChildren: true
});
}
};

View File

@ -7,10 +7,11 @@
"grammar", "grammar",
"rust" "rust"
], ],
"main": "lib/main.js",
"repository": "https://github.com/atom/atom", "repository": "https://github.com/atom/atom",
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"tree-sitter-rust": "^0.13.7" "tree-sitter-rust": "^0.15.1"
}, },
"engines": { "engines": {
"atom": ">=1.0.0 <2.0.0" "atom": ">=1.0.0 <2.0.0"

View File

@ -28,7 +28,7 @@
} }
&.syntax--operator { &.syntax--operator {
color: @mono-1; color: @hue-3;
} }
&.syntax--other.syntax--special-method { &.syntax--other.syntax--special-method {

View File

@ -26,7 +26,7 @@ chmod 755 "%{buildroot}/<%= installDir %>/bin/<%= appFileName %>"
mkdir -p "%{buildroot}/<%= installDir %>/share/applications/" mkdir -p "%{buildroot}/<%= installDir %>/share/applications/"
cp "<%= appFileName %>.desktop" "%{buildroot}/<%= installDir %>/share/applications/" cp "<%= appFileName %>.desktop" "%{buildroot}/<%= installDir %>/share/applications/"
mkdir -p "%{buildroot}/<%= installDir %>/share/polkit-1/actions/" mkdir -p "%{buildroot}/<%= installDir %>/share/polkit-1/actions/"
cp "atom.policy" "%{buildroot}/<%= installDir %>/share/polkit-1/actions/atom.policy" cp "<%= policyFileName %>" "%{buildroot}/<%= installDir %>/share/polkit-1/actions/<%= policyFileName %>"
mkdir -p "%{buildroot}/<%= installDir %>/share/icons/hicolor/1024x1024/apps" mkdir -p "%{buildroot}/<%= installDir %>/share/icons/hicolor/1024x1024/apps"
cp "icons/1024.png" "%{buildroot}/<%= installDir %>/share/icons/hicolor/1024x1024/apps/<%= appFileName %>.png" cp "icons/1024.png" "%{buildroot}/<%= installDir %>/share/icons/hicolor/1024x1024/apps/<%= appFileName %>.png"
@ -52,5 +52,5 @@ cp "icons/16.png" "%{buildroot}/<%= installDir %>/share/icons/hicolor/16x16/apps
<%= installDir %>/bin/<%= apmFileName %> <%= installDir %>/bin/<%= apmFileName %>
<%= installDir %>/share/<%= appFileName %>/ <%= installDir %>/share/<%= appFileName %>/
<%= installDir %>/share/applications/<%= appFileName %>.desktop <%= installDir %>/share/applications/<%= appFileName %>.desktop
<%= installDir %>/share/polkit-1/actions/atom.policy <%= installDir %>/share/polkit-1/actions/<%= policyFileName %>
<%= installDir %>/share/icons/hicolor/ <%= installDir %>/share/icons/hicolor/

View File

@ -109,7 +109,7 @@ if (!argv.generateApiDocs) {
if (argv.codeSign) { if (argv.codeSign) {
const executablesToSign = [ path.join(packagedAppPath, 'Atom.exe') ] const executablesToSign = [ path.join(packagedAppPath, 'Atom.exe') ]
if (argv.createWindowsInstaller) { if (argv.createWindowsInstaller) {
executablesToSign.push(path.join(__dirname, 'node_modules', 'electron-winstaller', 'vendor', 'Update.exe')) executablesToSign.push(path.join(__dirname, 'node_modules', '@atom', 'electron-winstaller', 'vendor', 'Squirrel.exe'))
} }
codeSignOnWindows(executablesToSign) codeSignOnWindows(executablesToSign)
} else { } else {

View File

@ -40,6 +40,7 @@ module.exports = function(filesToSign) {
__dirname, __dirname,
'..', '..',
'node_modules', 'node_modules',
'@atom',
'electron-winstaller', 'electron-winstaller',
'vendor', 'vendor',
'signtool.exe' 'signtool.exe'

View File

@ -209,7 +209,12 @@ module.exports = function(packagedAppPath) {
); );
fs.copySync( fs.copySync(
path.join(CONFIG.repositoryRootPath, 'resources', 'linux', 'atom.policy'), path.join(CONFIG.repositoryRootPath, 'resources', 'linux', 'atom.policy'),
path.join(debianPackageShareDirPath, 'polkit-1', 'actions', 'atom.policy') path.join(
debianPackageShareDirPath,
'polkit-1',
'actions',
`atom-${CONFIG.channel}.policy`
)
); );
console.log(`Generating .deb file from ${debianPackageDirPath}`); console.log(`Generating .deb file from ${debianPackageDirPath}`);

View File

@ -19,6 +19,7 @@ module.exports = function(packagedAppPath) {
// RPM versions can't have dashes or tildes in them. // RPM versions can't have dashes or tildes in them.
// (Ref.: https://twiki.cern.ch/twiki/bin/view/Main/RPMAndDebVersioning) // (Ref.: https://twiki.cern.ch/twiki/bin/view/Main/RPMAndDebVersioning)
const appVersion = CONFIG.appMetadata.version.replace(/-/g, '.'); const appVersion = CONFIG.appMetadata.version.replace(/-/g, '.');
const policyFileName = `atom-${CONFIG.channel}.policy`;
const rpmPackageDirPath = path.join(CONFIG.homeDirPath, 'rpmbuild'); const rpmPackageDirPath = path.join(CONFIG.homeDirPath, 'rpmbuild');
const rpmPackageBuildDirPath = path.join(rpmPackageDirPath, 'BUILD'); const rpmPackageBuildDirPath = path.join(rpmPackageDirPath, 'BUILD');
@ -80,7 +81,8 @@ module.exports = function(packagedAppPath) {
apmFileName: apmExecutableName, apmFileName: apmExecutableName,
description: appDescription, description: appDescription,
installDir: '/usr', installDir: '/usr',
version: appVersion version: appVersion,
policyFileName
}); });
fs.writeFileSync(rpmPackageSpecFilePath, rpmPackageSpecsContents); fs.writeFileSync(rpmPackageSpecFilePath, rpmPackageSpecsContents);
@ -114,7 +116,7 @@ module.exports = function(packagedAppPath) {
console.log(`Copying atom.policy into "${rpmPackageBuildDirPath}"`); console.log(`Copying atom.policy into "${rpmPackageBuildDirPath}"`);
fs.copySync( fs.copySync(
path.join(CONFIG.repositoryRootPath, 'resources', 'linux', 'atom.policy'), path.join(CONFIG.repositoryRootPath, 'resources', 'linux', 'atom.policy'),
path.join(rpmPackageBuildDirPath, 'atom.policy') path.join(rpmPackageBuildDirPath, policyFileName)
); );
console.log(`Generating .rpm package from "${rpmPackageDirPath}"`); console.log(`Generating .rpm package from "${rpmPackageDirPath}"`);

View File

@ -1,6 +1,6 @@
'use strict'; 'use strict';
const electronInstaller = require('electron-winstaller'); const electronInstaller = require('@atom/electron-winstaller');
const fs = require('fs'); const fs = require('fs');
const glob = require('glob'); const glob = require('glob');
const path = require('path'); const path = require('path');
@ -26,7 +26,6 @@ module.exports = packagedAppPath => {
), ),
outputDirectory: CONFIG.buildOutputPath, outputDirectory: CONFIG.buildOutputPath,
noMsi: true, noMsi: true,
noDelta: CONFIG.channel === 'nightly', // Delta packages are broken for nightly versions past nightly9 due to Squirrel/NuGet limitations
remoteReleases: `${updateUrlPrefix}/api/updates${archSuffix}?version=${ remoteReleases: `${updateUrlPrefix}/api/updates${archSuffix}?version=${
CONFIG.computedAppVersion CONFIG.computedAppVersion
}`, }`,

View File

@ -16,7 +16,6 @@ const EXCLUDE_REGEXPS_SOURCES = [
escapeRegExp('.npmignore'), escapeRegExp('.npmignore'),
escapeRegExp('.pairs'), escapeRegExp('.pairs'),
escapeRegExp('.travis.yml'), escapeRegExp('.travis.yml'),
escapeRegExp('appveyor.yml'),
escapeRegExp('.idea'), escapeRegExp('.idea'),
escapeRegExp('.editorconfig'), escapeRegExp('.editorconfig'),
escapeRegExp('.lint'), escapeRegExp('.lint'),

1062
script/package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@ -14,7 +14,7 @@
"electron-link": "0.4.0", "electron-link": "0.4.0",
"electron-mksnapshot": "^3.1.10", "electron-mksnapshot": "^3.1.10",
"electron-packager": "12.2.0", "electron-packager": "12.2.0",
"electron-winstaller": "2.6.4", "@atom/electron-winstaller": "0.0.1",
"eslint": "^5.16.0", "eslint": "^5.16.0",
"eslint-config-prettier": "^4.2.0", "eslint-config-prettier": "^4.2.0",
"eslint-config-standard": "^12.0.0", "eslint-config-standard": "^12.0.0",
@ -23,7 +23,7 @@
"eslint-plugin-prettier": "^3.0.1", "eslint-plugin-prettier": "^3.0.1",
"eslint-plugin-promise": "^4.1.1", "eslint-plugin-promise": "^4.1.1",
"eslint-plugin-standard": "^4.0.0", "eslint-plugin-standard": "^4.0.0",
"fs-admin": "^0.1.5", "fs-admin": "^0.5.0",
"fs-extra": "0.30.0", "fs-extra": "0.30.0",
"glob": "7.0.3", "glob": "7.0.3",
"joanna": "0.0.10", "joanna": "0.0.10",
@ -46,7 +46,7 @@
"sync-request": "3.0.1", "sync-request": "3.0.1",
"tello": "1.0.7", "tello": "1.0.7",
"terser": "^3.8.1", "terser": "^3.8.1",
"webdriverio": "2.4.5", "webdriverio": "^5.9.2",
"yargs": "4.8.1" "yargs": "4.8.1"
} }
} }

View File

@ -39,6 +39,7 @@ const childProcess = require('child_process')
const fs = require('fs-extra') const fs = require('fs-extra')
const glob = require('glob') const glob = require('glob')
const path = require('path') const path = require('path')
const temp = require('temp').track()
const CONFIG = require('./config') const CONFIG = require('./config')
const backupNodeModules = require('./lib/backup-node-modules') const backupNodeModules = require('./lib/backup-node-modules')
@ -63,7 +64,8 @@ if (process.platform === 'darwin') {
} }
function prepareEnv (suiteName) { function prepareEnv (suiteName) {
const env = Object.assign({}, process.env) const atomHomeDirPath = temp.mkdirSync(suiteName)
const env = Object.assign({}, process.env, {ATOM_HOME: atomHomeDirPath})
if (process.env.TEST_JUNIT_XML_ROOT) { if (process.env.TEST_JUNIT_XML_ROOT) {
// Tell Jasmine to output this suite's results as a JUnit XML file to a subdirectory of the root, so that a // Tell Jasmine to output this suite's results as a JUnit XML file to a subdirectory of the root, so that a
@ -116,10 +118,7 @@ for (let packageName in CONFIG.appMetadata.packageDependencies) {
const testSubdir = ['spec', 'test'].find(subdir => fs.existsSync(path.join(repositoryPackagePath, subdir))) const testSubdir = ['spec', 'test'].find(subdir => fs.existsSync(path.join(repositoryPackagePath, subdir)))
if (!testSubdir) { if (!testSubdir) {
packageTestSuites.push(function (callback) { console.log(`No test folder found for package: ${packageName}`.yellow)
console.log(`Skipping tests for ${packageName} because no test folder was found`.bold.yellow)
callback(null, {exitCode: 0, step: `package-${packageName}`})
})
continue continue
} }
@ -201,7 +200,17 @@ function testSuitesForPlatform (platform) {
let suites = [] let suites = []
switch (platform) { switch (platform) {
case 'darwin': case 'darwin':
suites = [runCoreMainProcessTests, runCoreRenderProcessTests, runBenchmarkTests].concat(packageTestSuites) const PACKAGES_TO_TEST_IN_PARALLEL = 23
if (process.env.ATOM_RUN_CORE_TESTS === 'true') {
suites = [runCoreMainProcessTests, runCoreRenderProcessTests]
} else if (process.env.ATOM_RUN_PACKAGE_TESTS === '1') {
suites = packageTestSuites.slice(0, PACKAGES_TO_TEST_IN_PARALLEL)
} else if (process.env.ATOM_RUN_PACKAGE_TESTS === '2') {
suites = packageTestSuites.slice(PACKAGES_TO_TEST_IN_PARALLEL)
} else {
suites = [runCoreMainProcessTests, runCoreRenderProcessTests].concat(packageTestSuites)
}
break break
case 'win32': case 'win32':
suites = (process.arch === 'x64') ? [runCoreMainProcessTests, runCoreRenderProcessTests] : [runCoreMainProcessTests] suites = (process.arch === 'x64') ? [runCoreMainProcessTests, runCoreRenderProcessTests] : [runCoreMainProcessTests]

View File

@ -97,32 +97,60 @@ module.exports.generateForNightly = async function(
releaseVersion, releaseVersion,
githubToken githubToken
) { ) {
const releases = await octokit.repos.getReleases({
owner: 'atom',
repo: 'atom-nightly-releases'
});
const previousRelease = getPreviousRelease(releaseVersion, releases.data);
const oldReleaseNotes = previousRelease ? previousRelease.body : undefined;
const latestCommitResult = childProcess.spawnSync('git', [ const latestCommitResult = childProcess.spawnSync('git', [
'rev-parse', 'rev-parse',
'--short', '--short',
'HEAD' 'HEAD'
]); ]);
if (!latestCommitResult) {
console.log("Couldn't get the current commmit from git.");
if (latestCommitResult && oldReleaseNotes) { return undefined;
const latestCommit = latestCommitResult.stdout.toString().trim();
const extractMatch = oldReleaseNotes.match(
/atom\/atom\/compare\/([0-9a-f]{5,40})\.\.\.([0-9a-f]{5,40})/
);
if (extractMatch) {
return `### Click [here](https://github.com/atom/atom/compare/${
extractMatch[2]
}...${latestCommit}) to see the changes included with this release! :atom: :night_with_stars:`;
}
} }
return undefined; const latestCommit = latestCommitResult.stdout.toString().trim();
const output = [
`### This nightly release is based on https://github.com/atom/atom/commit/${latestCommit} :atom: :night_with_stars:`
];
try {
const releases = await octokit.repos.getReleases({
owner: 'atom',
repo: 'atom-nightly-releases'
});
const previousRelease = getPreviousRelease(releaseVersion, releases.data);
const oldReleaseNotes = previousRelease ? previousRelease.body : undefined;
if (oldReleaseNotes) {
const extractMatch = oldReleaseNotes.match(
/atom\/atom\/commit\/([0-9a-f]{5,40})/
);
if (extractMatch.length > 1 && extractMatch[1]) {
output.push('', '---', '');
const previousCommit = extractMatch[1];
if (
previousCommit === latestCommit ||
previousCommit.startsWith(latestCommit) ||
latestCommit.startsWith(previousCommit)
) {
// TODO: Maybe we can bail out and not publish a release if it contains no commits?
output.push('No changes have been included in this release');
} else {
output.push(
`Click [here](https://github.com/atom/atom/compare/${previousCommit}...${latestCommit}) to see the changes included with this release!`
);
}
}
}
} catch (e) {
console.log(
'Error when trying to find the previous nightly release: ' + e.message
);
}
return output.join('\n');
}; };
function extractWrittenReleaseNotes(oldReleaseNotes) { function extractWrittenReleaseNotes(oldReleaseNotes) {

View File

@ -1,65 +1,64 @@
resources: resources:
containers: containers:
- container: atom-linux-ci - container: atom-linux-ci
image: atomeditor/atom-linux-ci:latest image: atomeditor/atom-linux-ci:latest
jobs: jobs:
- job: GetReleaseVersion
steps:
# This has to be done separately because VSTS inexplicably
# exits the script block after `npm install` completes.
- script: |
cd script\vsts
npm install
displayName: npm install
- script: node script\vsts\get-release-version.js --nightly
name: Version
- job: GetReleaseVersion # Import OS-specific build definitions
steps: - template: platforms/windows.yml
# This has to be done separately because VSTS inexplicably - template: platforms/macos.yml
# exits the script block after `npm install` completes. - template: platforms/linux.yml
- script: |
cd script\vsts
npm install
displayName: npm install
- script: node script\vsts\get-release-version.js --nightly
name: Version
# Import OS-specific build definitions - job: Release
- template: platforms/windows.yml pool:
- template: platforms/macos.yml vmImage: vs2015-win2012r2 # needed for Python 2.7 and gyp
- template: platforms/linux.yml
- job: Release dependsOn:
pool: - GetReleaseVersion
vmImage: vs2015-win2012r2 # needed for Python 2.7 and gyp - Windows
- Linux
- macOS_tests
dependsOn: variables:
- GetReleaseVersion ReleaseVersion: $[ dependencies.GetReleaseVersion.outputs['Version.ReleaseVersion'] ]
- Windows
- Linux
- macOS
variables: steps:
ReleaseVersion: $[ dependencies.GetReleaseVersion.outputs['Version.ReleaseVersion'] ] - task: NodeTool@0
inputs:
versionSpec: 10.2.1
displayName: Install Node.js 10.2.1
steps: # This has to be done separately because VSTS inexplicably
- task: NodeTool@0 # exits the script block after `npm install` completes.
inputs: - script: |
versionSpec: 8.9.3 cd script\vsts
displayName: Install Node.js 8.9.3 npm install
displayName: npm install
# This has to be done separately because VSTS inexplicably - task: DownloadBuildArtifacts@0
# exits the script block after `npm install` completes. inputs:
- script: | itemPattern: '**'
cd script\vsts downloadType: 'specific'
npm install displayName: Download Release Artifacts
displayName: npm install
- task: DownloadBuildArtifacts@0 - script: |
inputs: node $(Build.SourcesDirectory)\script\vsts\upload-artifacts.js --create-github-release --assets-path "$(System.ArtifactsDirectory)" --linux-repo-name "atom"
itemPattern: '**' env:
downloadType: 'specific' GITHUB_TOKEN: $(GITHUB_TOKEN)
displayName: Download Release Artifacts ATOM_RELEASE_VERSION: $(ReleaseVersion)
ATOM_RELEASES_S3_KEY: $(ATOM_RELEASES_S3_KEY)
- script: | ATOM_RELEASES_S3_SECRET: $(ATOM_RELEASES_S3_SECRET)
node $(Build.SourcesDirectory)\script\vsts\upload-artifacts.js --create-github-release --assets-path "$(System.ArtifactsDirectory)" ATOM_RELEASES_S3_BUCKET: $(ATOM_RELEASES_S3_BUCKET)
env: PACKAGE_CLOUD_API_KEY: $(PACKAGE_CLOUD_API_KEY)
GITHUB_TOKEN: $(GITHUB_TOKEN) displayName: Create Nightly Release
ATOM_RELEASE_VERSION: $(ReleaseVersion)
ATOM_RELEASES_S3_KEY: $(ATOM_RELEASES_S3_KEY)
ATOM_RELEASES_S3_SECRET: $(ATOM_RELEASES_S3_SECRET)
ATOM_RELEASES_S3_BUCKET: $(ATOM_RELEASES_S3_BUCKET)
PACKAGE_CLOUD_API_KEY: $(PACKAGE_CLOUD_API_KEY)
displayName: Create Nightly Release

View File

@ -1,76 +1,99 @@
jobs: jobs:
- job: Linux - job: Linux
dependsOn: GetReleaseVersion dependsOn: GetReleaseVersion
timeoutInMinutes: 180 timeoutInMinutes: 180
variables: variables:
ReleaseVersion: $[ dependencies.GetReleaseVersion.outputs['Version.ReleaseVersion'] ] ReleaseVersion: $[ dependencies.GetReleaseVersion.outputs['Version.ReleaseVersion'] ]
pool: pool:
# This image is used to host the Docker container that runs the build # This image is used to host the Docker container that runs the build
vmImage: ubuntu-16.04 vmImage: ubuntu-16.04
container: atom-linux-ci container: atom-linux-ci
steps: steps:
- script: script/bootstrap - task: NodeTool@0
displayName: Bootstrap build environment inputs:
env: versionSpec: 10.2.1
CI: true displayName: Install Node.js 10.2.1
CI_PROVIDER: VSTS
- script: script/lint - script: npm install --global npm@6.2.0
displayName: Run linter displayName: Update npm
- script: script/build --no-bootstrap --create-debian-package --create-rpm-package --compress-artifacts - task: 1ESLighthouseEng.PipelineArtifactCaching.RestoreCacheV1.RestoreCache@1
env: displayName: Restore node_modules cache
GITHUB_TOKEN: $(GITHUB_TOKEN) inputs:
ATOM_RELEASE_VERSION: $(ReleaseVersion) keyfile: 'package.json, script/vsts/platforms/linux.yml, **/package-lock.json, !**/node_modules/**/package-lock.json, !**/.*/**/package-lock.json'
displayName: Build Atom targetfolder: '**/node_modules, !**/node_modules/**/node_modules'
vstsFeed: 'bae1bc26-220d-43c7-a955-4de039370de2'
- script: script/test - script: script/bootstrap
env: displayName: Bootstrap build environment
CI: true env:
CI_PROVIDER: VSTS CI: true
ATOM_JASMINE_REPORTER: list CI_PROVIDER: VSTS
TEST_JUNIT_XML_ROOT: $(Common.TestResultsDirectory)/junit condition: ne(variables['CacheRestored'], 'true')
displayName: Run tests
condition: and(succeeded(), ne(variables['Atom.SkipTests'], 'true'))
- script: script/postprocess-junit-results --search-folder "${TEST_JUNIT_XML_ROOT}" --test-results-files "**/*.xml" - task: 1ESLighthouseEng.PipelineArtifactCaching.SaveCacheV1.SaveCache@1
env: displayName: Save node_modules cache
TEST_JUNIT_XML_ROOT: $(Common.TestResultsDirectory)/junit inputs:
displayName: Post-process test results keyfile: 'package.json, script/vsts/platforms/linux.yml, **/package-lock.json, !**/node_modules/**/package-lock.json, !**/.*/**/package-lock.json'
condition: ne(variables['Atom.SkipTests'], 'true') targetfolder: '**/node_modules, !**/node_modules/**/node_modules'
vstsFeed: 'bae1bc26-220d-43c7-a955-4de039370de2'
- task: PublishTestResults@2 - script: script/lint
inputs: displayName: Run linter
testResultsFormat: JUnit
searchFolder: $(Common.TestResultsDirectory)/junit
testResultsFiles: "**/*.xml"
mergeTestResults: true
testRunTitle: Linux
condition: ne(variables['Atom.SkipTests'], 'true')
- task: PublishBuildArtifacts@1 - script: script/build --no-bootstrap --create-debian-package --create-rpm-package --compress-artifacts
inputs: env:
PathtoPublish: $(Build.SourcesDirectory)/out/atom.x86_64.rpm GITHUB_TOKEN: $(GITHUB_TOKEN)
ArtifactName: atom.x86_64.rpm ATOM_RELEASE_VERSION: $(ReleaseVersion)
ArtifactType: Container displayName: Build Atom
displayName: Upload atom.x84_64.rpm
condition: and(succeeded(), ne(variables['Build.Reason'], 'PullRequest'))
- task: PublishBuildArtifacts@1 - script: script/test
inputs: env:
PathtoPublish: $(Build.SourcesDirectory)/out/atom-amd64.deb CI: true
ArtifactName: atom-amd64.deb CI_PROVIDER: VSTS
ArtifactType: Container ATOM_JASMINE_REPORTER: list
displayName: Upload atom-amd64.deb TEST_JUNIT_XML_ROOT: $(Common.TestResultsDirectory)/junit
condition: and(succeeded(), ne(variables['Build.Reason'], 'PullRequest')) displayName: Run tests
condition: and(succeeded(), ne(variables['Atom.SkipTests'], 'true'))
- task: PublishBuildArtifacts@1 - script: script/postprocess-junit-results --search-folder "${TEST_JUNIT_XML_ROOT}" --test-results-files "**/*.xml"
inputs: env:
PathtoPublish: $(Build.SourcesDirectory)/out/atom-amd64.tar.gz TEST_JUNIT_XML_ROOT: $(Common.TestResultsDirectory)/junit
ArtifactName: atom-amd64.tar.gz displayName: Post-process test results
ArtifactType: Container condition: ne(variables['Atom.SkipTests'], 'true')
displayName: Upload atom-amd64.tar.gz
condition: and(succeeded(), ne(variables['Build.Reason'], 'PullRequest')) - task: PublishTestResults@2
inputs:
testResultsFormat: JUnit
searchFolder: $(Common.TestResultsDirectory)/junit
testResultsFiles: '**/*.xml'
mergeTestResults: true
testRunTitle: Linux
condition: ne(variables['Atom.SkipTests'], 'true')
- task: PublishBuildArtifacts@1
inputs:
PathtoPublish: $(Build.SourcesDirectory)/out/atom.x86_64.rpm
ArtifactName: atom.x86_64.rpm
ArtifactType: Container
displayName: Upload atom.x84_64.rpm
condition: and(succeeded(), ne(variables['Build.Reason'], 'PullRequest'))
- task: PublishBuildArtifacts@1
inputs:
PathtoPublish: $(Build.SourcesDirectory)/out/atom-amd64.deb
ArtifactName: atom-amd64.deb
ArtifactType: Container
displayName: Upload atom-amd64.deb
condition: and(succeeded(), ne(variables['Build.Reason'], 'PullRequest'))
- task: PublishBuildArtifacts@1
inputs:
PathtoPublish: $(Build.SourcesDirectory)/out/atom-amd64.tar.gz
ArtifactName: atom-amd64.tar.gz
ArtifactType: Container
displayName: Upload atom-amd64.tar.gz
condition: and(succeeded(), ne(variables['Build.Reason'], 'PullRequest'))

View File

@ -1,114 +1,195 @@
jobs: jobs:
- job: macOS - job: macOS_build
dependsOn: GetReleaseVersion displayName: macOS build
timeoutInMinutes: 180 dependsOn: GetReleaseVersion
timeoutInMinutes: 180
variables: variables:
ReleaseVersion: $[ dependencies.GetReleaseVersion.outputs['Version.ReleaseVersion'] ] ReleaseVersion: $[ dependencies.GetReleaseVersion.outputs['Version.ReleaseVersion'] ]
IsReleaseBranch: $[ dependencies.GetReleaseVersion.outputs['Version.IsReleaseBranch'] ] IsReleaseBranch: $[ dependencies.GetReleaseVersion.outputs['Version.IsReleaseBranch'] ]
IsSignedZipBranch: $[ dependencies.GetReleaseVersion.outputs['Version.IsSignedZipBranch'] ] IsSignedZipBranch: $[ dependencies.GetReleaseVersion.outputs['Version.IsSignedZipBranch'] ]
pool: pool:
vmImage: macos-10.13 vmImage: macos-10.13
steps: steps:
- task: NodeTool@0 - task: NodeTool@0
inputs: inputs:
versionSpec: 8.9.3 versionSpec: 10.2.1
displayName: Install Node.js 8.9.3 displayName: Install Node.js 10.2.1
- script: npm install --global npm@6.2.0 - script: npm install --global npm@6.2.0
displayName: Update npm displayName: Update npm
- script: script/bootstrap - task: 1ESLighthouseEng.PipelineArtifactCaching.RestoreCacheV1.RestoreCache@1
displayName: Bootstrap build environment displayName: Restore node_modules cache
env: inputs:
CI: true keyfile: 'package.json, script/vsts/platforms/macos.yml, **/package-lock.json, !**/node_modules/**/package-lock.json, !**/.*/**/package-lock.json'
CI_PROVIDER: VSTS targetfolder: '**/node_modules, !**/node_modules/**/node_modules'
NPM_BIN_PATH: /usr/local/bin/npm vstsFeed: 'bae1bc26-220d-43c7-a955-4de039370de2'
- script: script/lint - script: script/bootstrap
displayName: Run linter displayName: Bootstrap build environment
env:
CI: true
CI_PROVIDER: VSTS
NPM_BIN_PATH: /usr/local/bin/npm
condition: ne(variables['CacheRestored'], 'true')
- script: | - task: 1ESLighthouseEng.PipelineArtifactCaching.SaveCacheV1.SaveCache@1
if [ $IS_RELEASE_BRANCH == "true" ] || [ $IS_SIGNED_ZIP_BRANCH == "true" ]; then displayName: Save node_modules cache
script/build --no-bootstrap --code-sign --compress-artifacts inputs:
else keyfile: 'package.json, script/vsts/platforms/macos.yml, **/package-lock.json, !**/node_modules/**/package-lock.json, !**/.*/**/package-lock.json'
script/build --no-bootstrap --compress-artifacts targetfolder: '**/node_modules, !**/node_modules/**/node_modules'
fi vstsFeed: 'bae1bc26-220d-43c7-a955-4de039370de2'
displayName: Build Atom
env:
GITHUB_TOKEN: $(GITHUB_TOKEN)
IS_RELEASE_BRANCH: $(IsReleaseBranch)
IS_SIGNED_ZIP_BRANCH: $(IsSignedZipBranch)
ATOM_RELEASE_VERSION: $(ReleaseVersion)
ATOM_MAC_CODE_SIGNING_CERT_DOWNLOAD_URL: $(ATOM_MAC_CODE_SIGNING_CERT_DOWNLOAD_URL)
ATOM_MAC_CODE_SIGNING_CERT_PASSWORD: $(ATOM_MAC_CODE_SIGNING_CERT_PASSWORD)
ATOM_MAC_CODE_SIGNING_KEYCHAIN: $(ATOM_MAC_CODE_SIGNING_KEYCHAIN)
ATOM_MAC_CODE_SIGNING_KEYCHAIN_PASSWORD: $(ATOM_MAC_CODE_SIGNING_KEYCHAIN_PASSWORD)
- script: | - script: script/lint
osascript -e 'tell application "System Events" to keystroke "x"' # clear screen saver displayName: Run linter
caffeinate -s script/test # Run with caffeinate to prevent screen saver
env:
CI: true
CI_PROVIDER: VSTS
ATOM_JASMINE_REPORTER: list
TEST_JUNIT_XML_ROOT: $(Common.TestResultsDirectory)/junit
displayName: Run tests
condition: and(succeeded(), ne(variables['Atom.SkipTests'], 'true'))
- script: script/postprocess-junit-results --search-folder "${TEST_JUNIT_XML_ROOT}" --test-results-files "**/*.xml" - script: |
env: if [ $IS_RELEASE_BRANCH == "true" ] || [ $IS_SIGNED_ZIP_BRANCH == "true" ]; then
TEST_JUNIT_XML_ROOT: $(Common.TestResultsDirectory)/junit script/build --no-bootstrap --code-sign --compress-artifacts
displayName: Post-process test results else
condition: ne(variables['Atom.SkipTests'], 'true') script/build --no-bootstrap --compress-artifacts
fi
displayName: Build Atom
env:
GITHUB_TOKEN: $(GITHUB_TOKEN)
IS_RELEASE_BRANCH: $(IsReleaseBranch)
IS_SIGNED_ZIP_BRANCH: $(IsSignedZipBranch)
ATOM_RELEASE_VERSION: $(ReleaseVersion)
ATOM_MAC_CODE_SIGNING_CERT_DOWNLOAD_URL: $(ATOM_MAC_CODE_SIGNING_CERT_DOWNLOAD_URL)
ATOM_MAC_CODE_SIGNING_CERT_PASSWORD: $(ATOM_MAC_CODE_SIGNING_CERT_PASSWORD)
ATOM_MAC_CODE_SIGNING_KEYCHAIN: $(ATOM_MAC_CODE_SIGNING_KEYCHAIN)
ATOM_MAC_CODE_SIGNING_KEYCHAIN_PASSWORD: $(ATOM_MAC_CODE_SIGNING_KEYCHAIN_PASSWORD)
- task: PublishTestResults@2 - script: |
inputs: cp $(Build.SourcesDirectory)/out/*.zip $(Build.ArtifactStagingDirectory)
testResultsFormat: JUnit displayName: Stage Artifacts
searchFolder: $(Common.TestResultsDirectory)/junit
testResultsFiles: "**/*.xml"
mergeTestResults: true
testRunTitle: MacOS
condition: ne(variables['Atom.SkipTests'], 'true')
- script: | - task: PublishBuildArtifacts@1
cp $(Build.SourcesDirectory)/out/*.zip $(Build.ArtifactStagingDirectory) inputs:
displayName: Stage Artifacts PathtoPublish: $(Build.ArtifactStagingDirectory)/atom-mac.zip
ArtifactName: atom-mac.zip
ArtifactType: Container
displayName: Upload atom-mac.zip
condition: succeeded()
- script: | - task: PublishBuildArtifacts@1
mkdir -p $(Build.ArtifactStagingDirectory)/crash-reports inputs:
cp ${HOME}/Library/Logs/DiagnosticReports/*.crash $(Build.ArtifactStagingDirectory)/crash-reports PathtoPublish: $(Build.ArtifactStagingDirectory)/atom-mac-symbols.zip
displayName: Stage Crash Reports ArtifactName: atom-mac-symbols.zip
condition: failed() ArtifactType: Container
displayName: Upload atom-mac-symbols.zip
condition: succeeded()
- task: PublishBuildArtifacts@1 - task: PublishBuildArtifacts@1
inputs: inputs:
PathtoPublish: $(Build.ArtifactStagingDirectory)/atom-mac.zip PathtoPublish: $(Build.SourcesDirectory)/docs/output/atom-api.json
ArtifactName: atom-mac.zip ArtifactName: atom-api.json
ArtifactType: Container ArtifactType: Container
displayName: Upload atom-mac.zip displayName: Upload atom-api.json
condition: and(succeeded(), ne(variables['Build.Reason'], 'PullRequest')) condition: succeeded()
- task: PublishBuildArtifacts@1 - job: macOS_tests
inputs: displayName: macOS test
PathtoPublish: $(Build.ArtifactStagingDirectory)/atom-mac-symbols.zip dependsOn: macOS_build
ArtifactName: atom-mac-symbols.zip timeoutInMinutes: 180
ArtifactType: Container pool:
displayName: Upload atom-mac-symbols.zip vmImage: macos-10.13
condition: and(succeeded(), ne(variables['Build.Reason'], 'PullRequest')) strategy:
maxParallel: 3
matrix:
core:
RunCoreTests: true
RunPackageTests: false
packages-1:
RunCoreTests: false
RunPackageTests: 1
packages-2:
RunCoreTests: false
RunPackageTests: 2
- task: PublishBuildArtifacts@1 steps:
inputs: - task: NodeTool@0
PathtoPublish: $(Build.SourcesDirectory)/docs/output/atom-api.json inputs:
ArtifactName: atom-api.json versionSpec: 10.2.1
ArtifactType: Container displayName: Install Node.js 10.2.1
displayName: Upload atom-api.json
condition: and(succeeded(), ne(variables['Build.Reason'], 'PullRequest'))
- task: PublishBuildArtifacts@1 - script: npm install --global npm@6.2.0
inputs: displayName: Update npm
PathtoPublish: $(Build.ArtifactStagingDirectory)/crash-reports
ArtifactName: crash-reports.zip - task: 1ESLighthouseEng.PipelineArtifactCaching.RestoreCacheV1.RestoreCache@1
displayName: Upload Crash Reports displayName: Restore node_modules cache
condition: failed() inputs:
keyfile: 'package.json, script/vsts/platforms/macos.yml, **/package-lock.json, !**/node_modules/**/package-lock.json, !**/.*/**/package-lock.json'
targetfolder: '**/node_modules, !**/node_modules/**/node_modules'
vstsFeed: 'bae1bc26-220d-43c7-a955-4de039370de2'
# The artifact caching task does not work on forks, so we need to
# bootstrap again for pull requests coming from forked repositories.
- script: script/bootstrap
displayName: Bootstrap build environment
env:
CI: true
CI_PROVIDER: VSTS
NPM_BIN_PATH: /usr/local/bin/npm
condition: ne(variables['CacheRestored'], 'true')
- task: DownloadBuildArtifacts@0
displayName: Download atom-mac.zip
inputs:
artifactName: 'atom-mac.zip'
downloadPath: $(Build.SourcesDirectory)
- script: unzip atom-mac.zip/atom-mac.zip -d out
displayName: Unzip atom-mac.zip
- task: DownloadBuildArtifacts@0
displayName: Download atom-mac-symbols.zip
inputs:
artifactName: 'atom-mac-symbols.zip'
downloadPath: $(Build.SourcesDirectory)
- script: unzip atom-mac-symbols.zip/atom-mac-symbols.zip -d out
displayName: Unzip atom-mac-symbols.zip
- script: |
osascript -e 'tell application "System Events" to keystroke "x"' # clear screen saver
caffeinate -s script/test # Run with caffeinate to prevent screen saver
env:
CI: true
CI_PROVIDER: VSTS
ATOM_JASMINE_REPORTER: list
TEST_JUNIT_XML_ROOT: $(Common.TestResultsDirectory)/junit
ATOM_RUN_CORE_TESTS: $(RunCoreTests)
ATOM_RUN_PACKAGE_TESTS: $(RunPackageTests)
displayName: Run tests
condition: and(succeeded(), ne(variables['Atom.SkipTests'], 'true'))
- script: script/postprocess-junit-results --search-folder "${TEST_JUNIT_XML_ROOT}" --test-results-files "**/*.xml"
env:
TEST_JUNIT_XML_ROOT: $(Common.TestResultsDirectory)/junit
displayName: Post-process test results
condition: ne(variables['Atom.SkipTests'], 'true')
- task: PublishTestResults@2
inputs:
testResultsFormat: JUnit
searchFolder: $(Common.TestResultsDirectory)/junit
testResultsFiles: '**/*.xml'
mergeTestResults: true
testRunTitle: MacOS
condition: ne(variables['Atom.SkipTests'], 'true')
- script: |
mkdir -p $(Build.ArtifactStagingDirectory)/crash-reports
cp ${HOME}/Library/Logs/DiagnosticReports/*.crash $(Build.ArtifactStagingDirectory)/crash-reports
displayName: Stage Crash Reports
condition: failed()
- task: PublishBuildArtifacts@1
inputs:
PathtoPublish: $(Build.ArtifactStagingDirectory)/crash-reports
ArtifactName: crash-reports.zip
displayName: Upload Crash Reports
condition: failed()

View File

@ -1,216 +1,249 @@
jobs: jobs:
- job: Windows - job: Windows
dependsOn: GetReleaseVersion dependsOn: GetReleaseVersion
timeoutInMinutes: 180 timeoutInMinutes: 180
strategy: strategy:
maxParallel: 2 maxParallel: 2
matrix: matrix:
x64: x64:
buildArch: x64 buildArch: x64
x86: x86:
buildArch: x86 buildArch: x86
pool: pool:
vmImage: vs2015-win2012r2 # needed for python 2.7 and gyp vmImage: vs2015-win2012r2 # needed for python 2.7 and gyp
variables: variables:
ReleaseVersion: $[ dependencies.GetReleaseVersion.outputs['Version.ReleaseVersion'] ] ReleaseVersion: $[ dependencies.GetReleaseVersion.outputs['Version.ReleaseVersion'] ]
IsReleaseBranch: $[ dependencies.GetReleaseVersion.outputs['Version.IsReleaseBranch'] ] IsReleaseBranch: $[ dependencies.GetReleaseVersion.outputs['Version.IsReleaseBranch'] ]
IsSignedZipBranch: $[ dependencies.GetReleaseVersion.outputs['Version.IsSignedZipBranch'] ] IsSignedZipBranch: $[ dependencies.GetReleaseVersion.outputs['Version.IsSignedZipBranch'] ]
steps: steps:
- task: NodeTool@0 - task: NodeTool@0
inputs: inputs:
versionSpec: 8.9.3 versionSpec: 10.2.1
displayName: Install Node.js 8.9.3 displayName: Install Node.js 10.2.1
- script: | - script: |
ECHO Installing npm-windows-upgrade ECHO Installing npm-windows-upgrade
npm install --global --production npm-windows-upgrade npm install --global --production npm-windows-upgrade
displayName: Install npm-windows-upgrade displayName: Install npm-windows-upgrade
- script: | - script: |
ECHO Upgrading npm ECHO Upgrading npm
npm-windows-upgrade --no-spinner --no-prompt --npm-version 6.2.0 npm-windows-upgrade --no-spinner --no-prompt --npm-version 6.2.0
displayName: Install npm 6.2.0 displayName: Install npm 6.2.0
- script: | - script: |
cd script\vsts cd script\vsts
npm install npm install
displayName: Install Windows build dependencies displayName: Install Windows build dependencies
- script: | - task: 1ESLighthouseEng.PipelineArtifactCaching.RestoreCacheV1.RestoreCache@1
node script\vsts\windows-run.js script\bootstrap.cmd displayName: Restore node_modules cache (x64)
env: inputs:
BUILD_ARCH: $(buildArch) keyfile: 'package.json, script/vsts/platforms/windows.yml, **/package-lock.json, !**/node_modules/**/package-lock.json, !**/.*/**/package-lock.json, script/vsts/x64-cache-key'
CI: true targetfolder: '**/node_modules, !**/node_modules/**/node_modules'
CI_PROVIDER: VSTS vstsFeed: 'bae1bc26-220d-43c7-a955-4de039370de2'
NPM_BIN_PATH: "D:\\a\\_tool\\node\\8.9.3\\x64\\npm.cmd" condition: eq(variables['buildArch'], 'x64')
displayName: Bootstrap build environment
- script: node script\vsts\windows-run.js script\lint.cmd - task: 1ESLighthouseEng.PipelineArtifactCaching.RestoreCacheV1.RestoreCache@1
env: displayName: Restore node_modules cache (x86)
BUILD_ARCH: $(buildArch) inputs:
displayName: Run linter keyfile: 'package.json, script/vsts/platforms/windows.yml, **/package-lock.json, !**/node_modules/**/package-lock.json, !**/.*/**/package-lock.json, script/vsts/x86-cache-key'
targetfolder: '**/node_modules, !**/node_modules/**/node_modules'
vstsFeed: 'bae1bc26-220d-43c7-a955-4de039370de2'
condition: eq(variables['buildArch'], 'x86')
- script: | - script: |
IF NOT EXIST C:\tmp MKDIR C:\tmp node script\vsts\windows-run.js script\bootstrap.cmd
SET SQUIRREL_TEMP=C:\tmp env:
IF [%IS_RELEASE_BRANCH%]==[true] ( BUILD_ARCH: $(buildArch)
ECHO Creating production artifacts for release branch %BUILD_SOURCEBRANCHNAME% CI: true
node script\vsts\windows-run.js script\build.cmd --code-sign --compress-artifacts --create-windows-installer CI_PROVIDER: VSTS
) ELSE ( NPM_BIN_PATH: "D:\\a\\_tool\\node\\10.2.1\\x64\\npm.cmd"
IF [%IS_SIGNED_ZIP_BRANCH%]==[true] ( displayName: Bootstrap build environment
ECHO Creating signed CI artifacts for branch %BUILD_SOURCEBRANCHNAME% condition: ne(variables['CacheRestored'], 'true')
node script\vsts\windows-run.js script\build.cmd --code-sign --compress-artifacts
) ELSE (
ECHO Pull request build, no code signing will be performed
node script\vsts\windows-run.js script\build.cmd --compress-artifacts
)
)
env:
GITHUB_TOKEN: $(GITHUB_TOKEN)
BUILD_ARCH: $(buildArch)
ATOM_RELEASE_VERSION: $(ReleaseVersion)
ATOM_WIN_CODE_SIGNING_CERT_DOWNLOAD_URL: $(ATOM_WIN_CODE_SIGNING_CERT_DOWNLOAD_URL)
ATOM_WIN_CODE_SIGNING_CERT_PASSWORD: $(ATOM_WIN_CODE_SIGNING_CERT_PASSWORD)
IS_RELEASE_BRANCH: $(IsReleaseBranch)
IS_SIGNED_ZIP_BRANCH: $(IsSignedZipBranch)
displayName: Build Atom
- script: node script\vsts\windows-run.js script\test.cmd - task: 1ESLighthouseEng.PipelineArtifactCaching.SaveCacheV1.SaveCache@1
env: displayName: Save node_modules cache (x64)
CI: true inputs:
CI_PROVIDER: VSTS keyfile: 'package.json, script/vsts/platforms/windows.yml, **/package-lock.json, !**/node_modules/**/package-lock.json, !**/.*/**/package-lock.json, script/vsts/x64-cache-key'
ATOM_JASMINE_REPORTER: list targetfolder: '**/node_modules, !**/node_modules/**/node_modules'
TEST_JUNIT_XML_ROOT: $(Common.TestResultsDirectory)\junit vstsFeed: 'bae1bc26-220d-43c7-a955-4de039370de2'
BUILD_ARCH: $(buildArch) condition: eq(variables['buildArch'], 'x64')
displayName: Run tests
condition: and(succeeded(), ne(variables['Atom.SkipTests'], 'true'))
- script: > - task: 1ESLighthouseEng.PipelineArtifactCaching.SaveCacheV1.SaveCache@1
node script\vsts\windows-run.js script\postprocess-junit-results.cmd displayName: Save node_modules cache (x86)
--search-folder %TEST_JUNIT_XML_ROOT% --test-results-files "**/*.xml" inputs:
env: keyfile: 'package.json, script/vsts/platforms/windows.yml, **/package-lock.json, !**/node_modules/**/package-lock.json, !**/.*/**/package-lock.json, script/vsts/x86-cache-key'
TEST_JUNIT_XML_ROOT: $(Common.TestResultsDirectory)\junit targetfolder: '**/node_modules, !**/node_modules/**/node_modules'
displayName: Post-process test results vstsFeed: 'bae1bc26-220d-43c7-a955-4de039370de2'
condition: ne(variables['Atom.SkipTests'], 'true') condition: eq(variables['buildArch'], 'x86')
- task: PublishTestResults@2 - script: node script\vsts\windows-run.js script\lint.cmd
inputs: env:
testResultsFormat: JUnit BUILD_ARCH: $(buildArch)
searchFolder: $(Common.TestResultsDirectory)\junit displayName: Run linter
testResultsFiles: "**/*.xml"
mergeTestResults: true
testRunTitle: Windows $(buildArch)
condition: ne(variables['Atom.SkipTests'], 'true')
- script: | - script: |
IF NOT EXIST "%ARTIFACT_STAGING_DIR%\crash-reports" MKDIR "%ARTIFACT_STAGING_DIR%\crash-reports" IF NOT EXIST C:\tmp MKDIR C:\tmp
IF EXIST "%Temp%\Atom Crashes" ( SET SQUIRREL_TEMP=C:\tmp
FOR %%a in ("%Temp%\Atom Crashes\*.dmp") DO XCOPY "%%a" "%ARTIFACT_STAGING_DIR%\crash-reports" /I IF [%IS_RELEASE_BRANCH%]==[true] (
) ECHO Creating production artifacts for release branch %BUILD_SOURCEBRANCHNAME%
displayName: Stage crash reports node script\vsts\windows-run.js script\build.cmd --no-bootstrap --code-sign --compress-artifacts --create-windows-installer
condition: failed() ) ELSE (
env: IF [%IS_SIGNED_ZIP_BRANCH%]==[true] (
ARTIFACT_STAGING_DIR: $(Build.ArtifactStagingDirectory) ECHO Creating signed CI artifacts for branch %BUILD_SOURCEBRANCHNAME%
node script\vsts\windows-run.js script\build.cmd --no-bootstrap --code-sign --compress-artifacts
) ELSE (
ECHO Pull request build, no code signing will be performed
node script\vsts\windows-run.js script\build.cmd --no-bootstrap --compress-artifacts
)
)
env:
GITHUB_TOKEN: $(GITHUB_TOKEN)
BUILD_ARCH: $(buildArch)
ATOM_RELEASE_VERSION: $(ReleaseVersion)
ATOM_WIN_CODE_SIGNING_CERT_DOWNLOAD_URL: $(ATOM_WIN_CODE_SIGNING_CERT_DOWNLOAD_URL)
ATOM_WIN_CODE_SIGNING_CERT_PASSWORD: $(ATOM_WIN_CODE_SIGNING_CERT_PASSWORD)
IS_RELEASE_BRANCH: $(IsReleaseBranch)
IS_SIGNED_ZIP_BRANCH: $(IsSignedZipBranch)
displayName: Build Atom
- task: PublishBuildArtifacts@1 - script: node script\vsts\windows-run.js script\test.cmd
inputs: env:
PathtoPublish: $(Build.ArtifactStagingDirectory)/crash-reports CI: true
ArtifactName: crash-reports CI_PROVIDER: VSTS
displayName: Publish crash reports on non-release branch ATOM_JASMINE_REPORTER: list
condition: and(failed(), eq(variables['ATOM_RELEASES_S3_KEY'], '')) TEST_JUNIT_XML_ROOT: $(Common.TestResultsDirectory)\junit
BUILD_ARCH: $(buildArch)
displayName: Run tests
condition: and(succeeded(), ne(variables['Atom.SkipTests'], 'true'))
- script: > - script: >
node $(Build.SourcesDirectory)\script\vsts\upload-crash-reports.js --crash-report-path "%ARTIFACT_STAGING_DIR%\crash-reports" --s3-path "vsts-artifacts/%BUILD_ID%/" node script\vsts\windows-run.js script\postprocess-junit-results.cmd
env: --search-folder %TEST_JUNIT_XML_ROOT% --test-results-files "**/*.xml"
ATOM_RELEASES_S3_KEY: $(ATOM_RELEASES_S3_KEY) env:
ATOM_RELEASES_S3_SECRET: $(ATOM_RELEASES_S3_SECRET) TEST_JUNIT_XML_ROOT: $(Common.TestResultsDirectory)\junit
ATOM_RELEASES_S3_BUCKET: $(ATOM_RELEASES_S3_BUCKET) displayName: Post-process test results
ARTIFACT_STAGING_DIR: $(Build.ArtifactStagingDirectory) condition: ne(variables['Atom.SkipTests'], 'true')
BUILD_ID: $(Build.BuildId)
displayName: Upload crash reports to S3 on release branch
condition: and(failed(), ne(variables['ATOM_RELEASES_S3_KEY'], ''))
- task: PublishBuildArtifacts@1 - task: PublishTestResults@2
inputs: inputs:
PathtoPublish: $(Build.SourcesDirectory)/out/atom-x64-windows.zip testResultsFormat: JUnit
ArtifactName: atom-x64-windows.zip searchFolder: $(Common.TestResultsDirectory)\junit
ArtifactType: Container testResultsFiles: '**/*.xml'
displayName: Upload atom-x64-windows.zip mergeTestResults: true
condition: and(succeeded(), ne(variables['Build.Reason'], 'PullRequest'), eq(variables['buildArch'], 'x64')) testRunTitle: Windows $(buildArch)
condition: ne(variables['Atom.SkipTests'], 'true')
- task: PublishBuildArtifacts@1 - script: |
inputs: IF NOT EXIST "%ARTIFACT_STAGING_DIR%\crash-reports" MKDIR "%ARTIFACT_STAGING_DIR%\crash-reports"
PathtoPublish: $(Build.SourcesDirectory)/out/AtomSetup-x64.exe IF EXIST "%Temp%\Atom Crashes" (
ArtifactName: AtomSetup-x64.exe FOR %%a in ("%Temp%\Atom Crashes\*.dmp") DO XCOPY "%%a" "%ARTIFACT_STAGING_DIR%\crash-reports" /I
ArtifactType: Container )
displayName: Upload AtomSetup-x64.exe displayName: Stage crash reports
condition: and(succeeded(), eq(variables['IsReleaseBranch'], 'true'), eq(variables['buildArch'], 'x64')) condition: failed()
env:
ARTIFACT_STAGING_DIR: $(Build.ArtifactStagingDirectory)
- task: PublishBuildArtifacts@1 - task: PublishBuildArtifacts@1
inputs: inputs:
PathtoPublish: $(Build.SourcesDirectory)/out/atom-x64-$(ReleaseVersion)-full.nupkg PathtoPublish: $(Build.ArtifactStagingDirectory)/crash-reports
ArtifactName: atom-x64-$(ReleaseVersion)-full.nupkg ArtifactName: crash-reports
ArtifactType: Container displayName: Publish crash reports on non-release branch
displayName: Upload atom-x64-$(ReleaseVersion)-full.nupkg condition: and(failed(), eq(variables['ATOM_RELEASES_S3_KEY'], ''))
condition: and(succeeded(), eq(variables['IsReleaseBranch'], 'true'), eq(variables['buildArch'], 'x64'))
- task: PublishBuildArtifacts@1 - script: >
inputs: node $(Build.SourcesDirectory)\script\vsts\upload-crash-reports.js --crash-report-path "%ARTIFACT_STAGING_DIR%\crash-reports" --s3-path "vsts-artifacts/%BUILD_ID%/"
PathtoPublish: $(Build.SourcesDirectory)/out/atom-x64-$(ReleaseVersion)-delta.nupkg env:
ArtifactName: atom-x64-$(ReleaseVersion)-delta.nupkg ATOM_RELEASES_S3_KEY: $(ATOM_RELEASES_S3_KEY)
ArtifactType: Container ATOM_RELEASES_S3_SECRET: $(ATOM_RELEASES_S3_SECRET)
displayName: Upload atom-x64-$(ReleaseVersion)-delta.nupkg ATOM_RELEASES_S3_BUCKET: $(ATOM_RELEASES_S3_BUCKET)
condition: and(succeeded(), eq(variables['IsReleaseBranch'], 'true'), eq(variables['buildArch'], 'x64')) ARTIFACT_STAGING_DIR: $(Build.ArtifactStagingDirectory)
continueOnError: true # Nightly builds don't produce delta packages yet, so don't fail the build BUILD_ID: $(Build.BuildId)
displayName: Upload crash reports to S3 on release branch
condition: and(failed(), ne(variables['ATOM_RELEASES_S3_KEY'], ''))
- task: PublishBuildArtifacts@1 - task: PublishBuildArtifacts@1
inputs: inputs:
PathtoPublish: $(Build.SourcesDirectory)/out/RELEASES-x64 PathtoPublish: $(Build.SourcesDirectory)/out/atom-x64-windows.zip
ArtifactName: RELEASES-x64 ArtifactName: atom-x64-windows.zip
ArtifactType: Container ArtifactType: Container
displayName: Upload RELEASES-x64 displayName: Upload atom-x64-windows.zip
condition: and(succeeded(), eq(variables['IsReleaseBranch'], 'true'), eq(variables['buildArch'], 'x64')) condition: and(succeeded(), ne(variables['Build.Reason'], 'PullRequest'), eq(variables['buildArch'], 'x64'))
- task: PublishBuildArtifacts@1 - task: PublishBuildArtifacts@1
inputs: inputs:
PathtoPublish: $(Build.SourcesDirectory)/out/atom-windows.zip PathtoPublish: $(Build.SourcesDirectory)/out/AtomSetup-x64.exe
ArtifactName: atom-windows.zip ArtifactName: AtomSetup-x64.exe
ArtifactType: Container ArtifactType: Container
displayName: Upload atom-windows.zip displayName: Upload AtomSetup-x64.exe
condition: and(succeeded(), ne(variables['Build.Reason'], 'PullRequest'), eq(variables['buildArch'], 'x86')) condition: and(succeeded(), eq(variables['IsReleaseBranch'], 'true'), eq(variables['buildArch'], 'x64'))
- task: PublishBuildArtifacts@1 - task: PublishBuildArtifacts@1
inputs: inputs:
PathtoPublish: $(Build.SourcesDirectory)/out/AtomSetup.exe PathtoPublish: $(Build.SourcesDirectory)/out/atom-x64-$(ReleaseVersion)-full.nupkg
ArtifactName: AtomSetup.exe ArtifactName: atom-x64-$(ReleaseVersion)-full.nupkg
ArtifactType: Container ArtifactType: Container
displayName: Upload AtomSetup.exe displayName: Upload atom-x64-$(ReleaseVersion)-full.nupkg
condition: and(succeeded(), eq(variables['IsReleaseBranch'], 'true'), eq(variables['buildArch'], 'x86')) condition: and(succeeded(), eq(variables['IsReleaseBranch'], 'true'), eq(variables['buildArch'], 'x64'))
- task: PublishBuildArtifacts@1 - task: PublishBuildArtifacts@1
inputs: inputs:
PathtoPublish: $(Build.SourcesDirectory)/out/atom-$(ReleaseVersion)-full.nupkg PathtoPublish: $(Build.SourcesDirectory)/out/atom-x64-$(ReleaseVersion)-delta.nupkg
ArtifactName: atom-$(ReleaseVersion)-full.nupkg ArtifactName: atom-x64-$(ReleaseVersion)-delta.nupkg
ArtifactType: Container ArtifactType: Container
displayName: Upload atom-$(ReleaseVersion)-full.nupkg displayName: Upload atom-x64-$(ReleaseVersion)-delta.nupkg
condition: and(succeeded(), eq(variables['IsReleaseBranch'], 'true'), eq(variables['buildArch'], 'x86')) condition: and(succeeded(), eq(variables['IsReleaseBranch'], 'true'), eq(variables['buildArch'], 'x64'))
continueOnError: true # Nightly builds don't produce delta packages yet, so don't fail the build
- task: PublishBuildArtifacts@1 - task: PublishBuildArtifacts@1
inputs: inputs:
PathtoPublish: $(Build.SourcesDirectory)/out/atom-$(ReleaseVersion)-delta.nupkg PathtoPublish: $(Build.SourcesDirectory)/out/RELEASES-x64
ArtifactName: atom-$(ReleaseVersion)-delta.nupkg ArtifactName: RELEASES-x64
ArtifactType: Container ArtifactType: Container
displayName: Upload atom-$(ReleaseVersion)-delta.nupkg displayName: Upload RELEASES-x64
condition: and(succeeded(), eq(variables['IsReleaseBranch'], 'true'), eq(variables['buildArch'], 'x86')) condition: and(succeeded(), eq(variables['IsReleaseBranch'], 'true'), eq(variables['buildArch'], 'x64'))
continueOnError: true # Nightly builds don't produce delta packages yet, so don't fail the build
- task: PublishBuildArtifacts@1 - task: PublishBuildArtifacts@1
inputs: inputs:
PathtoPublish: $(Build.SourcesDirectory)/out/RELEASES PathtoPublish: $(Build.SourcesDirectory)/out/atom-windows.zip
ArtifactName: RELEASES ArtifactName: atom-windows.zip
ArtifactType: Container ArtifactType: Container
displayName: Upload RELEASES displayName: Upload atom-windows.zip
condition: and(succeeded(), eq(variables['IsReleaseBranch'], 'true'), eq(variables['buildArch'], 'x86')) condition: and(succeeded(), ne(variables['Build.Reason'], 'PullRequest'), eq(variables['buildArch'], 'x86'))
- task: PublishBuildArtifacts@1
inputs:
PathtoPublish: $(Build.SourcesDirectory)/out/AtomSetup.exe
ArtifactName: AtomSetup.exe
ArtifactType: Container
displayName: Upload AtomSetup.exe
condition: and(succeeded(), eq(variables['IsReleaseBranch'], 'true'), eq(variables['buildArch'], 'x86'))
- task: PublishBuildArtifacts@1
inputs:
PathtoPublish: $(Build.SourcesDirectory)/out/atom-$(ReleaseVersion)-full.nupkg
ArtifactName: atom-$(ReleaseVersion)-full.nupkg
ArtifactType: Container
displayName: Upload atom-$(ReleaseVersion)-full.nupkg
condition: and(succeeded(), eq(variables['IsReleaseBranch'], 'true'), eq(variables['buildArch'], 'x86'))
- task: PublishBuildArtifacts@1
inputs:
PathtoPublish: $(Build.SourcesDirectory)/out/atom-$(ReleaseVersion)-delta.nupkg
ArtifactName: atom-$(ReleaseVersion)-delta.nupkg
ArtifactType: Container
displayName: Upload atom-$(ReleaseVersion)-delta.nupkg
condition: and(succeeded(), eq(variables['IsReleaseBranch'], 'true'), eq(variables['buildArch'], 'x86'))
continueOnError: true # Nightly builds don't produce delta packages yet, so don't fail the build
- task: PublishBuildArtifacts@1
inputs:
PathtoPublish: $(Build.SourcesDirectory)/out/RELEASES
ArtifactName: RELEASES
ArtifactType: Container
displayName: Upload RELEASES
condition: and(succeeded(), eq(variables['IsReleaseBranch'], 'true'), eq(variables['buildArch'], 'x86'))

View File

@ -1,24 +1,23 @@
trigger: none # No CI builds, only PR builds trigger: none # No CI builds, only PR builds
resources: resources:
containers: containers:
- container: atom-linux-ci - container: atom-linux-ci
image: atomeditor/atom-linux-ci:latest image: atomeditor/atom-linux-ci:latest
jobs: jobs:
- job: GetReleaseVersion
steps:
# This has to be done separately because VSTS inexplicably
# exits the script block after `npm install` completes.
- script: |
cd script\vsts
npm install
displayName: npm install
- script: node script\vsts\get-release-version.js
name: Version
- job: GetReleaseVersion # Import OS-specific build definitions
steps: - template: platforms/windows.yml
# This has to be done separately because VSTS inexplicably - template: platforms/macos.yml
# exits the script block after `npm install` completes. - template: platforms/linux.yml
- script: |
cd script\vsts
npm install
displayName: npm install
- script: node script\vsts\get-release-version.js
name: Version
# Import OS-specific build definitions
- template: platforms/windows.yml
- template: platforms/macos.yml
- template: platforms/linux.yml

View File

@ -1,85 +1,84 @@
trigger: trigger:
- master - master
- 1.* # VSTS only supports wildcards at the end - 1.* # VSTS only supports wildcards at the end
- electron-* - electron-*
resources: resources:
containers: containers:
- container: atom-linux-ci - container: atom-linux-ci
image: atomeditor/atom-linux-ci:latest image: atomeditor/atom-linux-ci:latest
jobs: jobs:
- job: GetReleaseVersion
steps:
# This has to be done separately because VSTS inexplicably
# exits the script block after `npm install` completes.
- script: |
cd script\vsts
npm install
displayName: npm install
- script: node script\vsts\get-release-version.js
name: Version
- job: GetReleaseVersion # Import OS-specific build definitions.
steps: - template: platforms/windows.yml
# This has to be done separately because VSTS inexplicably - template: platforms/macos.yml
# exits the script block after `npm install` completes. - template: platforms/linux.yml
- script: |
cd script\vsts
npm install
displayName: npm install
- script: node script\vsts\get-release-version.js
name: Version
# Import OS-specific build definitions. - job: UploadArtifacts
- template: platforms/windows.yml pool:
- template: platforms/macos.yml vmImage: vs2015-win2012r2 # needed for python 2.7 and gyp
- template: platforms/linux.yml
- job: UploadArtifacts dependsOn:
pool: - GetReleaseVersion
vmImage: vs2015-win2012r2 # needed for python 2.7 and gyp - Windows
- Linux
- macOS_tests
dependsOn: variables:
- GetReleaseVersion ReleaseVersion: $[ dependencies.GetReleaseVersion.outputs['Version.ReleaseVersion'] ]
- Windows IsReleaseBranch: $[ dependencies.GetReleaseVersion.outputs['Version.IsReleaseBranch'] ]
- Linux IsSignedZipBranch: $[ dependencies.GetReleaseVersion.outputs['Version.IsSignedZipBranch'] ]
- macOS
variables: steps:
ReleaseVersion: $[ dependencies.GetReleaseVersion.outputs['Version.ReleaseVersion'] ] - task: NodeTool@0
IsReleaseBranch: $[ dependencies.GetReleaseVersion.outputs['Version.IsReleaseBranch'] ] inputs:
IsSignedZipBranch: $[ dependencies.GetReleaseVersion.outputs['Version.IsSignedZipBranch'] ] versionSpec: 10.2.1
displayName: Install Node.js 10.2.1
steps: # This has to be done separately because VSTS inexplicably
- task: NodeTool@0 # exits the script block after `npm install` completes.
inputs: - script: |
versionSpec: 8.9.3 cd script\vsts
displayName: Install Node.js 8.9.3 npm install
env:
GITHUB_TOKEN: $(GITHUB_TOKEN)
displayName: npm install
# This has to be done separately because VSTS inexplicably - task: DownloadBuildArtifacts@0
# exits the script block after `npm install` completes. inputs:
- script: | itemPattern: '**'
cd script\vsts downloadType: 'specific'
npm install displayName: Download Release Artifacts
env:
GITHUB_TOKEN: $(GITHUB_TOKEN)
displayName: npm install
- task: DownloadBuildArtifacts@0 - script: |
inputs: node $(Build.SourcesDirectory)\script\vsts\upload-artifacts.js --create-github-release --assets-path "$(System.ArtifactsDirectory)" --linux-repo-name "atom-staging"
itemPattern: '**' env:
downloadType: 'specific' GITHUB_TOKEN: $(GITHUB_TOKEN)
displayName: Download Release Artifacts ATOM_RELEASE_VERSION: $(ReleaseVersion)
ATOM_RELEASES_S3_KEY: $(ATOM_RELEASES_S3_KEY)
ATOM_RELEASES_S3_SECRET: $(ATOM_RELEASES_S3_SECRET)
ATOM_RELEASES_S3_BUCKET: $(ATOM_RELEASES_S3_BUCKET)
PACKAGE_CLOUD_API_KEY: $(PACKAGE_CLOUD_API_KEY)
displayName: Create Draft Release
condition: and(succeeded(), eq(variables['Atom.AutoDraftRelease'], 'true'), eq(variables['IsReleaseBranch'], 'true'))
- script: | - script: |
node $(Build.SourcesDirectory)\script\vsts\upload-artifacts.js --create-github-release --assets-path "$(System.ArtifactsDirectory)" --linux-repo-name "atom-staging" node $(Build.SourcesDirectory)\script\vsts\upload-artifacts.js --assets-path "$(System.ArtifactsDirectory)" --s3-path "vsts-artifacts/$(Build.BuildId)/"
env: env:
GITHUB_TOKEN: $(GITHUB_TOKEN) ATOM_RELEASE_VERSION: $(ReleaseVersion)
ATOM_RELEASE_VERSION: $(ReleaseVersion) ATOM_RELEASES_S3_KEY: $(ATOM_RELEASES_S3_KEY)
ATOM_RELEASES_S3_KEY: $(ATOM_RELEASES_S3_KEY) ATOM_RELEASES_S3_SECRET: $(ATOM_RELEASES_S3_SECRET)
ATOM_RELEASES_S3_SECRET: $(ATOM_RELEASES_S3_SECRET) ATOM_RELEASES_S3_BUCKET: $(ATOM_RELEASES_S3_BUCKET)
ATOM_RELEASES_S3_BUCKET: $(ATOM_RELEASES_S3_BUCKET) displayName: Upload CI Artifacts to S3
PACKAGE_CLOUD_API_KEY: $(PACKAGE_CLOUD_API_KEY) condition: and(succeeded(), eq(variables['IsSignedZipBranch'], 'true'))
displayName: Create Draft Release
condition: and(succeeded(), eq(variables['Atom.AutoDraftRelease'], 'true'), eq(variables['IsReleaseBranch'], 'true'))
- script: |
node $(Build.SourcesDirectory)\script\vsts\upload-artifacts.js --assets-path "$(System.ArtifactsDirectory)" --s3-path "vsts-artifacts/$(Build.BuildId)/"
env:
ATOM_RELEASE_VERSION: $(ReleaseVersion)
ATOM_RELEASES_S3_KEY: $(ATOM_RELEASES_S3_KEY)
ATOM_RELEASES_S3_SECRET: $(ATOM_RELEASES_S3_SECRET)
ATOM_RELEASES_S3_BUCKET: $(ATOM_RELEASES_S3_BUCKET)
displayName: Upload CI Artifacts to S3
condition: and(succeeded(), eq(variables['IsSignedZipBranch'], 'true'))

View File

@ -5,7 +5,7 @@ const path = require('path');
const download = require('download'); const download = require('download');
const childProcess = require('child_process'); const childProcess = require('child_process');
const nodeVersion = '8.9.3'; const nodeVersion = '10.2.1';
const nodeFileName = `node-v${nodeVersion}-win-x86`; const nodeFileName = `node-v${nodeVersion}-win-x86`;
const extractedNodePath = `c:\\tmp\\${nodeFileName}`; const extractedNodePath = `c:\\tmp\\${nodeFileName}`;

View File

@ -0,0 +1 @@
x64

View File

@ -0,0 +1 @@
x86

View File

@ -334,6 +334,30 @@ describe "ContextMenuManager", ->
] ]
]) ])
it "does not add accelerators for multi-keystroke key bindings", ->
atom.keymaps.add('source', {
'.child': {
'ctrl-a ctrl-b': 'test:multi-keystroke-command'
}
})
contextMenu.clear()
contextMenu.add('.parent': [{
label: 'Multi-keystroke command',
command: 'test:multi-keystroke-command',
}])
child.focus()
label =
if process.platform is 'darwin'
'⌃A ⌃B'
else
'Ctrl+A Ctrl+B'
expect(contextMenu.templateForEvent({target: child})).toEqual([{
label: "Multi-keystroke command [#{label}]",
command: 'test:multi-keystroke-command',
}])
describe "::templateForEvent(target) (sorting)", -> describe "::templateForEvent(target) (sorting)", ->
it "applies simple sorting rules", -> it "applies simple sorting rules", ->
contextMenu.add('.parent': [{ contextMenu.add('.parent': [{

View File

@ -0,0 +1,25 @@
module.exports = {
activateCallCount: 0,
activationCommandCallCount: 0,
initialize() {},
activate () {
this.activateCallCount++
atom.commands.add('atom-workspace', 'activation-command-2', () => this.activationCommandCallCount++)
},
deserializeMethod1 (state) {
return {
wasDeserializedBy: 'deserializeMethod1',
state: state
}
},
deserializeMethod2 (state) {
return {
wasDeserializedBy: 'deserializeMethod2',
state: state
}
}
}

View File

@ -0,0 +1,14 @@
{
"name": "package-with-activation-commands-and-deserializers",
"version": "1.0.0",
"main": "./index",
"activationCommands": {
"atom-workspace": [
"activation-command-2"
]
},
"deserializers": {
"Deserializer1": "deserializeMethod1",
"Deserializer2": "deserializeMethod2"
}
}

View File

@ -0,0 +1 @@
module.exports = activate: ->

View File

@ -0,0 +1,5 @@
{
"name": "package-with-empty-workspace-openers",
"version": "0.1.0",
"workspaceOpeners": []
}

View File

@ -0,0 +1,9 @@
module.exports =
activateCallCount: 0
openerCount: 0
activate: ->
@activateCallCount++
atom.workspace.addOpener (filePath) =>
if filePath is 'atom://fictitious'
@openerCount++

View File

@ -0,0 +1,5 @@
{
"name": "package-with-workspace-openers",
"version": "0.1.0",
"workspaceOpeners": ['atom://fictitious']
}

View File

@ -69,6 +69,23 @@ describe('GrammarRegistry', () => {
}); });
}); });
describe('.assignGrammar(buffer, grammar)', () => {
it('allows a TextMate grammar to be assigned directly, even when Tree-sitter is permitted', () => {
grammarRegistry.loadGrammarSync(
require.resolve(
'language-javascript/grammars/tree-sitter-javascript.cson'
)
);
const tmGrammar = grammarRegistry.loadGrammarSync(
require.resolve('language-javascript/grammars/javascript.cson')
);
const buffer = new TextBuffer();
expect(grammarRegistry.assignGrammar(buffer, tmGrammar)).toBe(true);
expect(buffer.getLanguageMode().getGrammar()).toBe(tmGrammar);
});
});
describe('.grammarForId(languageId)', () => { describe('.grammarForId(languageId)', () => {
it('returns a text-mate grammar when `core.useTreeSitterParsers` is false', () => { it('returns a text-mate grammar when `core.useTreeSitterParsers` is false', () => {
atom.config.set('core.useTreeSitterParsers', false, { atom.config.set('core.useTreeSitterParsers', false, {
@ -859,6 +876,29 @@ describe('GrammarRegistry', () => {
expect(buffer2Copy.getLanguageMode().getLanguageId()).toBe('source.js'); expect(buffer2Copy.getLanguageMode().getLanguageId()).toBe('source.js');
}); });
}); });
describe('when working with grammars', () => {
beforeEach(async () => {
await atom.packages.activatePackage('language-javascript');
});
it('returns only Tree-sitter grammars by default', async () => {
const tmGrammars = atom.grammars.getGrammars();
const allGrammars = atom.grammars.getGrammars({
includeTreeSitter: true
});
expect(allGrammars.length).toBeGreaterThan(tmGrammars.length);
});
it('executes the foreach callback on both Tree-sitter and TextMate grammars', async () => {
const numAllGrammars = atom.grammars.getGrammars({
includeTreeSitter: true
}).length;
let i = 0;
atom.grammars.forEachGrammar(() => i++);
expect(i).toBe(numAllGrammars);
});
});
}); });
function retainedBufferCount(grammarRegistry) { function retainedBufferCount(grammarRegistry) {

View File

@ -1,165 +0,0 @@
path = require 'path'
http = require 'http'
temp = require('temp').track()
os = require('os')
remote = require 'remote'
async = require 'async'
{map, extend, once, difference} = require 'underscore-plus'
{spawn, spawnSync} = require 'child_process'
webdriverio = require '../../../script/node_modules/webdriverio'
AtomPath = remote.process.argv[0]
AtomLauncherPath = path.join(__dirname, "..", "helpers", "atom-launcher.sh")
ChromedriverPath = path.resolve(__dirname, '..', '..', '..', 'script', 'node_modules', 'electron-chromedriver', 'bin', 'chromedriver')
ChromedriverPort = 9515
ChromedriverURLBase = "/wd/hub"
ChromedriverStatusURL = "http://localhost:#{ChromedriverPort}#{ChromedriverURLBase}/status"
userDataDir = null
chromeDriverUp = (done) ->
checkStatus = ->
http
.get ChromedriverStatusURL, (response) ->
if response.statusCode is 200
done()
else
chromeDriverUp(done)
.on("error", -> chromeDriverUp(done))
setTimeout(checkStatus, 100)
chromeDriverDown = (done) ->
checkStatus = ->
http
.get ChromedriverStatusURL, (response) ->
chromeDriverDown(done)
.on("error", done)
setTimeout(checkStatus, 100)
buildAtomClient = (args, env) ->
userDataDir = temp.mkdirSync('atom-user-data-dir')
client = webdriverio.remote(
host: 'localhost'
port: ChromedriverPort
desiredCapabilities:
browserName: "atom"
chromeOptions:
binary: AtomLauncherPath
args: [
"atom-path=#{AtomPath}"
"atom-args=#{args.join(" ")}"
"atom-env=#{map(env, (value, key) -> "#{key}=#{value}").join(" ")}"
"dev"
"safe"
"user-data-dir=#{userDataDir}"
])
isRunning = false
client.on "init", -> isRunning = true
client.on "end", -> isRunning = false
client
.addCommand "waitUntil", (conditionFn, timeout, cb) ->
timedOut = succeeded = false
pollingInterval = Math.min(timeout, 100)
setTimeout((-> timedOut = true), timeout)
async.until(
(-> succeeded or timedOut),
((next) =>
setTimeout(=>
conditionFn.call(this).then(
((result) ->
succeeded = result
next()),
((err) -> next(err))
)
, pollingInterval)),
((err) -> cb(err, succeeded)))
.addCommand "waitForWindowCount", (count, timeout, cb) ->
@waitUntil(->
@windowHandles().then ({value}) -> value.length is count
, timeout)
.then (result) -> expect(result).toBe(true)
.windowHandles(cb)
.addCommand "waitForPaneItemCount", (count, timeout, cb) ->
@waitUntil(->
@execute(-> atom.workspace?.getActivePane()?.getItems().length)
.then(({value}) -> value is count)
, timeout)
.then (result) ->
expect(result).toBe(true)
cb(null)
.addCommand "treeViewRootDirectories", (cb) ->
@waitForExist('.tree-view', 10000)
.execute(->
for element in document.querySelectorAll(".tree-view .project-root > .header .name")
element.dataset.path
, cb)
.addCommand "waitForNewWindow", (fn, timeout, done) ->
@windowHandles (err, {value: oldWindowHandles}) ->
return done() unless isRunning
@call(fn)
.waitForWindowCount(oldWindowHandles.length + 1, 5000)
.then ({value: newWindowHandles}) ->
[newWindowHandle] = difference(newWindowHandles, oldWindowHandles)
return done() unless newWindowHandle
@window(newWindowHandle)
.waitForExist('atom-workspace', 10000, done)
.addCommand "dispatchCommand", (command, done) ->
@execute "atom.commands.dispatch(document.activeElement, '#{command}')"
.call(done)
module.exports = (args, env, fn) ->
[chromedriver, chromedriverLogs, chromedriverExit] = []
runs ->
chromedriver = spawn(ChromedriverPath, [
"--verbose",
"--port=#{ChromedriverPort}",
"--url-base=#{ChromedriverURLBase}"
])
chromedriverLogs = []
chromedriverExit = new Promise (resolve) ->
errorCode = null
chromedriver.on "exit", (code, signal) ->
errorCode = code unless signal?
chromedriver.stderr.on "data", (log) ->
chromedriverLogs.push(log.toString())
chromedriver.stderr.on "close", ->
resolve(errorCode)
waitsFor("webdriver to start", chromeDriverUp, 15000)
waitsFor("tests to run", (done) ->
finish = once ->
client.end()
.then(-> chromedriver.kill())
.then(chromedriverExit.then(
(errorCode) ->
if errorCode?
jasmine.getEnv().currentSpec.fail """
Chromedriver exited with code #{errorCode}.
Logs:\n#{chromedriverLogs.join("\n")}
"""
done()))
client = buildAtomClient(args, env)
client.on "error", (err) ->
jasmine.getEnv().currentSpec.fail(new Error(err.response?.body?.value?.message))
finish()
fn(
client.init()
.waitUntil((-> @windowHandles().then ({value}) -> value.length > 0), 10000)
.waitForExist("atom-workspace", 10000)
).then(finish)
, 30000)
waitsFor("webdriver to stop", chromeDriverDown, 15000)

View File

@ -0,0 +1,195 @@
const path = require('path');
const http = require('http');
const temp = require('temp').track();
const remote = require('remote');
const { once } = require('underscore-plus');
const { spawn } = require('child_process');
const webdriverio = require('../../../script/node_modules/webdriverio');
const AtomPath = remote.process.argv[0];
const AtomLauncherPath = path.join(
__dirname,
'..',
'helpers',
'atom-launcher.sh'
);
const ChromedriverPath = path.resolve(
__dirname,
'..',
'..',
'..',
'script',
'node_modules',
'electron-chromedriver',
'bin',
'chromedriver'
);
const ChromedriverPort = 9515;
const ChromedriverURLBase = '/wd/hub';
const ChromedriverStatusURL = `http://localhost:${ChromedriverPort}${ChromedriverURLBase}/status`;
const chromeDriverUp = done => {
const checkStatus = () =>
http
.get(ChromedriverStatusURL, response => {
if (response.statusCode === 200) {
done();
} else {
chromeDriverUp(done);
}
})
.on('error', () => chromeDriverUp(done));
setTimeout(checkStatus, 100);
};
const chromeDriverDown = done => {
const checkStatus = () =>
http
.get(ChromedriverStatusURL, response => chromeDriverDown(done))
.on('error', done);
setTimeout(checkStatus, 100);
};
const buildAtomClient = async (args, env) => {
const userDataDir = temp.mkdirSync('atom-user-data-dir');
const client = await webdriverio.remote({
host: 'localhost',
port: ChromedriverPort,
capabilities: {
browserName: 'atom',
chromeOptions: {
binary: AtomLauncherPath,
args: [
`atom-path=${AtomPath}`,
`atom-args=${args.join(' ')}`,
`atom-env=${Object.entries(env)
.map(([key, value]) => `${key}=${value}`)
.join(' ')}`,
'dev',
'safe',
`user-data-dir=${userDataDir}`
]
}
}
});
client.addCommand('waitForPaneItemCount', async function(count, timeout) {
await this.waitUntil(
() =>
this.execute(() => atom.workspace.getActivePane().getItems().length),
timeout
);
});
client.addCommand('treeViewRootDirectories', async function() {
const treeViewElement = await this.$('.tree-view');
await treeViewElement.waitForExist(10000);
return this.execute(() =>
Array.from(
document.querySelectorAll('.tree-view .project-root > .header .name')
).map(element => element.dataset.path)
);
});
client.addCommand('dispatchCommand', async function(command) {
return this.execute(
command => atom.commands.dispatch(document.activeElement, command),
command
);
});
return client;
};
module.exports = function(args, env, fn) {
let chromedriver, chromedriverLogs, chromedriverExit;
runs(() => {
chromedriver = spawn(ChromedriverPath, [
'--verbose',
`--port=${ChromedriverPort}`,
`--url-base=${ChromedriverURLBase}`
]);
chromedriverLogs = [];
chromedriverExit = new Promise(resolve => {
let errorCode = null;
chromedriver.on('exit', (code, signal) => {
if (signal == null) {
errorCode = code;
}
});
chromedriver.stderr.on('data', log =>
chromedriverLogs.push(log.toString())
);
chromedriver.stderr.on('close', () => resolve(errorCode));
});
});
waitsFor('webdriver to start', chromeDriverUp, 15000);
waitsFor(
'tests to run',
async done => {
const finish = once(async () => {
await client.deleteSession();
chromedriver.kill();
const errorCode = await chromedriverExit;
if (errorCode != null) {
jasmine.getEnv().currentSpec
.fail(`Chromedriver exited with code ${errorCode}.
Logs:\n${chromedriverLogs.join('\n')}`);
}
done();
});
let client;
try {
client = await buildAtomClient(args, env);
} catch (error) {
jasmine
.getEnv()
.currentSpec.fail(`Unable to build Atom client.\n${error}`);
finish();
return;
}
try {
await client.waitUntil(async function() {
const handles = await this.getWindowHandles();
return handles.length > 0;
}, 10000);
} catch (error) {
jasmine
.getEnv()
.currentSpec.fail(`Unable to locate windows.\n\n${error}`);
finish();
return;
}
try {
const workspaceElement = await client.$('atom-workspace');
await workspaceElement.waitForExist(10000);
} catch (error) {
jasmine
.getEnv()
.currentSpec.fail(`Unable to find workspace element.\n\n${error}`);
finish();
return;
}
try {
await fn(client);
} catch (error) {
jasmine.getEnv().currentSpec.fail(error);
finish();
return;
}
finish();
},
30000
);
waitsFor('webdriver to stop', chromeDriverDown, 15000);
};

View File

@ -1,42 +0,0 @@
fs = require 'fs-plus'
path = require 'path'
season = require 'season'
temp = require('temp').track()
runAtom = require './helpers/start-atom'
describe "Smoke Test", ->
return unless process.platform is 'darwin' # Fails on win32
atomHome = temp.mkdirSync('atom-home')
beforeEach ->
jasmine.useRealClock()
season.writeFileSync(path.join(atomHome, 'config.cson'), {
'*': {
welcome: {showOnStartup: false},
core: {
telemetryConsent: 'no',
disabledPackages: ['github']
}
}
})
it "can open a file in Atom and perform basic operations on it", ->
tempDirPath = temp.mkdirSync("empty-dir")
filePath = path.join(tempDirPath, "new-file")
fs.writeFileSync filePath, "", {encoding: "utf8"}
runAtom [filePath], {ATOM_HOME: atomHome}, (client) ->
client
.treeViewRootDirectories()
.then ({value}) -> expect(value).toEqual([])
.waitForExist("atom-text-editor", 5000)
.then (exists) -> expect(exists).toBe true
.waitForPaneItemCount(1, 1000)
.click("atom-text-editor")
.waitUntil((-> @execute(-> document.activeElement.closest('atom-text-editor'))), 5000)
.keys("Hello!")
.execute -> atom.workspace.getActiveTextEditor().getText()
.then ({value}) -> expect(value).toBe "Hello!"
.dispatchCommand("editor:delete-line")

View File

@ -0,0 +1,62 @@
const fs = require('fs-plus');
const path = require('path');
const season = require('season');
const temp = require('temp').track();
const runAtom = require('./helpers/start-atom');
describe('Smoke Test', () => {
// Fails on win32
if (process.platform !== 'darwin') {
return;
}
const atomHome = temp.mkdirSync('atom-home');
beforeEach(() => {
jasmine.useRealClock();
season.writeFileSync(path.join(atomHome, 'config.cson'), {
'*': {
welcome: { showOnStartup: false },
core: {
telemetryConsent: 'no',
disabledPackages: ['github']
}
}
});
});
it('can open a file in Atom and perform basic operations on it', async () => {
const tempDirPath = temp.mkdirSync('empty-dir');
const filePath = path.join(tempDirPath, 'new-file');
fs.writeFileSync(filePath, '', { encoding: 'utf8' });
runAtom([tempDirPath], { ATOM_HOME: atomHome }, async client => {
const roots = await client.treeViewRootDirectories();
expect(roots).toEqual([tempDirPath]);
await client.execute(filePath => atom.workspace.open(filePath), filePath);
const textEditorElement = await client.$('atom-text-editor');
await textEditorElement.waitForExist(5000);
await client.waitForPaneItemCount(1, 1000);
await textEditorElement.click();
const closestElement = await client.execute(() =>
document.activeElement.closest('atom-text-editor')
);
expect(closestElement).not.toBeNull();
await client.keys('Hello!');
const text = await client.execute(() =>
atom.workspace.getActiveTextEditor().getText()
);
expect(text).toBe('Hello!');
await client.dispatchCommand('editor:delete-line');
});
});
});

View File

@ -47,6 +47,10 @@ const {
describe('AtomApplication', function() { describe('AtomApplication', function() {
let scenario, sinon; let scenario, sinon;
if (process.env.CI) {
this.timeout(10 * 1000);
}
beforeEach(async function() { beforeEach(async function() {
sinon = sandbox.create(); sinon = sandbox.create();
scenario = await LaunchScenario.create(sinon); scenario = await LaunchScenario.create(sinon);

View File

@ -77,21 +77,6 @@ describe('AtomWindow', function() {
); );
}); });
await new Promise((resolve, reject) => {
fs.symlink(
path.join(original.ATOM_HOME, 'compile-cache'),
path.join(atomHome, 'compile-cache'),
'junction',
err => {
if (err) {
reject(err);
} else {
resolve();
}
}
);
});
process.env.ATOM_HOME = atomHome; process.env.ATOM_HOME = atomHome;
process.env.ATOM_DISABLE_SHELLING_OUT_FOR_ENVIRONMENT = 'true'; process.env.ATOM_DISABLE_SHELLING_OUT_FOR_ENVIRONMENT = 'true';
}); });

View File

@ -625,6 +625,10 @@ describe('PackageManager', () => {
}); });
describe('when the package has a main module', () => { describe('when the package has a main module', () => {
beforeEach(() => {
spyOn(Package.prototype, 'requireMainModule').andCallThrough();
});
describe('when the metadata specifies a main module path˜', () => { describe('when the metadata specifies a main module path˜', () => {
it('requires the module at the specified path', async () => { it('requires the module at the specified path', async () => {
const mainModule = require('./fixtures/packages/package-with-main/main-module'); const mainModule = require('./fixtures/packages/package-with-main/main-module');
@ -680,13 +684,12 @@ describe('PackageManager', () => {
mainModule = require('./fixtures/packages/package-with-activation-commands/index'); mainModule = require('./fixtures/packages/package-with-activation-commands/index');
mainModule.activationCommandCallCount = 0; mainModule.activationCommandCallCount = 0;
spyOn(mainModule, 'activate').andCallThrough(); spyOn(mainModule, 'activate').andCallThrough();
spyOn(Package.prototype, 'requireMainModule').andCallThrough();
workspaceCommandListener = jasmine.createSpy( workspaceCommandListener = jasmine.createSpy(
'workspaceCommandListener' 'workspaceCommandListener'
); );
registration = atom.commands.add( registration = atom.commands.add(
'.workspace', 'atom-workspace',
'activation-command', 'activation-command',
workspaceCommandListener workspaceCommandListener
); );
@ -835,72 +838,171 @@ describe('PackageManager', () => {
); );
}); });
}); });
});
describe('when the package metadata includes `activationHooks`', () => { describe('when the package metadata includes both activation commands and deserializers', () => {
let mainModule, promise; let mainModule, promise, workspaceCommandListener, registration;
beforeEach(() => { beforeEach(() => {
mainModule = require('./fixtures/packages/package-with-activation-hooks/index'); jasmine.attachToDOM(atom.workspace.getElement());
spyOn(mainModule, 'activate').andCallThrough(); spyOn(atom.packages, 'hasActivatedInitialPackages').andReturn(true);
spyOn(Package.prototype, 'requireMainModule').andCallThrough(); mainModule = require('./fixtures/packages/package-with-activation-commands-and-deserializers/index');
mainModule.activationCommandCallCount = 0;
spyOn(mainModule, 'activate').andCallThrough();
workspaceCommandListener = jasmine.createSpy(
'workspaceCommandListener'
);
registration = atom.commands.add(
'.workspace',
'activation-command-2',
workspaceCommandListener
);
promise = atom.packages.activatePackage(
'package-with-activation-commands-and-deserializers'
);
});
afterEach(() => {
if (registration) {
registration.dispose();
}
mainModule = null;
});
it('activates the package when a deserializer is called', async () => {
expect(Package.prototype.requireMainModule.callCount).toBe(0);
const state1 = { deserializer: 'Deserializer1', a: 'b' };
expect(atom.deserializers.deserialize(state1, atom)).toEqual({
wasDeserializedBy: 'deserializeMethod1',
state: state1
});
await promise;
expect(Package.prototype.requireMainModule.callCount).toBe(1);
});
it('defers requiring/activating the main module until an activation event bubbles to the root view', async () => {
expect(Package.prototype.requireMainModule.callCount).toBe(0);
atom.workspace
.getElement()
.dispatchEvent(
new CustomEvent('activation-command-2', { bubbles: true })
);
await promise;
expect(mainModule.activate.callCount).toBe(1);
expect(mainModule.activationCommandCallCount).toBe(1);
expect(Package.prototype.requireMainModule.callCount).toBe(1);
});
}); });
it('defers requiring/activating the main module until an triggering of an activation hook occurs', async () => { describe('when the package metadata includes `activationHooks`', () => {
promise = atom.packages.activatePackage( let mainModule, promise;
'package-with-activation-hooks'
);
expect(Package.prototype.requireMainModule.callCount).toBe(0);
atom.packages.triggerActivationHook('language-fictitious:grammar-used');
atom.packages.triggerDeferredActivationHooks();
await promise; beforeEach(() => {
expect(Package.prototype.requireMainModule.callCount).toBe(1); mainModule = require('./fixtures/packages/package-with-activation-hooks/index');
spyOn(mainModule, 'activate').andCallThrough();
});
it('defers requiring/activating the main module until an triggering of an activation hook occurs', async () => {
promise = atom.packages.activatePackage(
'package-with-activation-hooks'
);
expect(Package.prototype.requireMainModule.callCount).toBe(0);
atom.packages.triggerActivationHook(
'language-fictitious:grammar-used'
);
atom.packages.triggerDeferredActivationHooks();
await promise;
expect(Package.prototype.requireMainModule.callCount).toBe(1);
});
it('does not double register activation hooks when deactivating and reactivating', async () => {
promise = atom.packages.activatePackage(
'package-with-activation-hooks'
);
expect(mainModule.activate.callCount).toBe(0);
atom.packages.triggerActivationHook(
'language-fictitious:grammar-used'
);
atom.packages.triggerDeferredActivationHooks();
await promise;
expect(mainModule.activate.callCount).toBe(1);
await atom.packages.deactivatePackage(
'package-with-activation-hooks'
);
promise = atom.packages.activatePackage(
'package-with-activation-hooks'
);
atom.packages.triggerActivationHook(
'language-fictitious:grammar-used'
);
atom.packages.triggerDeferredActivationHooks();
await promise;
expect(mainModule.activate.callCount).toBe(2);
});
it('activates the package immediately when activationHooks is empty', async () => {
mainModule = require('./fixtures/packages/package-with-empty-activation-hooks/index');
spyOn(mainModule, 'activate').andCallThrough();
expect(Package.prototype.requireMainModule.callCount).toBe(0);
await atom.packages.activatePackage(
'package-with-empty-activation-hooks'
);
expect(mainModule.activate.callCount).toBe(1);
expect(Package.prototype.requireMainModule.callCount).toBe(1);
});
it('activates the package immediately if the activation hook had already been triggered', async () => {
atom.packages.triggerActivationHook(
'language-fictitious:grammar-used'
);
atom.packages.triggerDeferredActivationHooks();
expect(Package.prototype.requireMainModule.callCount).toBe(0);
await atom.packages.activatePackage('package-with-activation-hooks');
expect(mainModule.activate.callCount).toBe(1);
expect(Package.prototype.requireMainModule.callCount).toBe(1);
});
}); });
it('does not double register activation hooks when deactivating and reactivating', async () => { describe('when the package metadata includes `workspaceOpeners`', () => {
promise = atom.packages.activatePackage( let mainModule, promise;
'package-with-activation-hooks'
);
expect(mainModule.activate.callCount).toBe(0);
atom.packages.triggerActivationHook('language-fictitious:grammar-used');
atom.packages.triggerDeferredActivationHooks();
await promise; beforeEach(() => {
expect(mainModule.activate.callCount).toBe(1); mainModule = require('./fixtures/packages/package-with-workspace-openers/index');
spyOn(mainModule, 'activate').andCallThrough();
});
await atom.packages.deactivatePackage('package-with-activation-hooks'); it('defers requiring/activating the main module until a registered opener is called', async () => {
promise = atom.packages.activatePackage(
'package-with-workspace-openers'
);
expect(Package.prototype.requireMainModule.callCount).toBe(0);
atom.workspace.open('atom://fictitious');
promise = atom.packages.activatePackage( await promise;
'package-with-activation-hooks' expect(Package.prototype.requireMainModule.callCount).toBe(1);
); expect(mainModule.openerCount).toBe(1);
atom.packages.triggerActivationHook('language-fictitious:grammar-used'); });
atom.packages.triggerDeferredActivationHooks();
await promise; it('activates the package immediately when the events are empty', async () => {
expect(mainModule.activate.callCount).toBe(2); mainModule = require('./fixtures/packages/package-with-empty-workspace-openers/index');
}); spyOn(mainModule, 'activate').andCallThrough();
it('activates the package immediately when activationHooks is empty', async () => { atom.packages.activatePackage('package-with-empty-workspace-openers');
mainModule = require('./fixtures/packages/package-with-empty-activation-hooks/index');
spyOn(mainModule, 'activate').andCallThrough();
expect(Package.prototype.requireMainModule.callCount).toBe(0); expect(mainModule.activate.callCount).toBe(1);
});
await atom.packages.activatePackage(
'package-with-empty-activation-hooks'
);
expect(mainModule.activate.callCount).toBe(1);
expect(Package.prototype.requireMainModule.callCount).toBe(1);
});
it('activates the package immediately if the activation hook had already been triggered', async () => {
atom.packages.triggerActivationHook('language-fictitious:grammar-used');
atom.packages.triggerDeferredActivationHooks();
expect(Package.prototype.requireMainModule.callCount).toBe(0);
await atom.packages.activatePackage('package-with-activation-hooks');
expect(Package.prototype.requireMainModule.callCount).toBe(1);
}); });
}); });

View File

@ -4,9 +4,9 @@ ThemePackage = require '../src/theme-package'
{mockLocalStorage} = require './spec-helper' {mockLocalStorage} = require './spec-helper'
describe "Package", -> describe "Package", ->
build = (constructor, path) -> build = (constructor, packagePath) ->
new constructor( new constructor(
path: path, packageManager: atom.packages, config: atom.config, path: packagePath, packageManager: atom.packages, config: atom.config,
styleManager: atom.styles, notificationManager: atom.notifications, styleManager: atom.styles, notificationManager: atom.notifications,
keymapManager: atom.keymaps, commandRegistry: atom.command, keymapManager: atom.keymaps, commandRegistry: atom.command,
grammarRegistry: atom.grammars, themeManager: atom.themes, grammarRegistry: atom.grammars, themeManager: atom.themes,

View File

@ -1042,11 +1042,12 @@ describe('Project', () => {
}); });
describe('.onDidChangeFiles()', () => { describe('.onDidChangeFiles()', () => {
let sub = []; let sub;
const events = []; let events;
let checkCallback = () => {}; let checkCallback = () => {};
beforeEach(() => { beforeEach(() => {
events = [];
sub = atom.project.onDidChangeFiles(incoming => { sub = atom.project.onDidChangeFiles(incoming => {
events.push(...incoming); events.push(...incoming);
checkCallback(); checkCallback();
@ -1058,11 +1059,13 @@ describe('Project', () => {
const waitForEvents = paths => { const waitForEvents = paths => {
const remaining = new Set(paths.map(p => fs.realpathSync(p))); const remaining = new Set(paths.map(p => fs.realpathSync(p)));
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
let expireTimeoutId;
checkCallback = () => { checkCallback = () => {
for (let event of events) { for (let event of events) {
remaining.delete(event.path); remaining.delete(event.path);
} }
if (remaining.size === 0) { if (remaining.size === 0) {
clearTimeout(expireTimeoutId);
resolve(); resolve();
} }
}; };
@ -1075,12 +1078,13 @@ describe('Project', () => {
); );
}; };
expireTimeoutId = setTimeout(expire, 2000);
checkCallback(); checkCallback();
setTimeout(expire, 2000);
}); });
}; };
it('reports filesystem changes within project paths', () => { it('reports filesystem changes within project paths', async () => {
jasmine.useRealClock();
const dirOne = temp.mkdirSync('atom-spec-project-one'); const dirOne = temp.mkdirSync('atom-spec-project-one');
const fileOne = path.join(dirOne, 'file-one.txt'); const fileOne = path.join(dirOne, 'file-one.txt');
const fileTwo = path.join(dirOne, 'file-two.txt'); const fileTwo = path.join(dirOne, 'file-two.txt');
@ -1088,24 +1092,17 @@ describe('Project', () => {
const fileThree = path.join(dirTwo, 'file-three.txt'); const fileThree = path.join(dirTwo, 'file-three.txt');
// Ensure that all preexisting watchers are stopped // Ensure that all preexisting watchers are stopped
waitsForPromise(() => stopAllWatchers()); await stopAllWatchers();
runs(() => atom.project.setPaths([dirOne])); atom.project.setPaths([dirOne]);
waitsForPromise(() => atom.project.getWatcherPromise(dirOne)); await atom.project.getWatcherPromise(dirOne);
runs(() => { expect(atom.project.watcherPromisesByPath[dirTwo]).toEqual(undefined);
expect(atom.project.watcherPromisesByPath[dirTwo]).toEqual(undefined); fs.writeFileSync(fileThree, 'three\n');
fs.writeFileSync(fileTwo, 'two\n');
fs.writeFileSync(fileThree, 'three\n'); fs.writeFileSync(fileOne, 'one\n');
fs.writeFileSync(fileTwo, 'two\n'); await waitForEvents([fileOne, fileTwo]);
fs.writeFileSync(fileOne, 'one\n'); expect(events.some(event => event.path === fileThree)).toBeFalsy();
});
waitsForPromise(() => waitForEvents([fileOne, fileTwo]));
runs(() =>
expect(events.some(event => event.path === fileThree)).toBeFalsy()
);
}); });
}); });

View File

@ -3297,9 +3297,12 @@ describe('TextEditorComponent', () => {
// make the editor taller and wider and the same time, ensuring the number // make the editor taller and wider and the same time, ensuring the number
// of rendered lines is correct. // of rendered lines is correct.
setEditorHeightInLines(component, 13); setEditorHeightInLines(component, 13);
await setEditorWidthInCharacters(component, 50); setEditorWidthInCharacters(component, 50);
expect(component.getRenderedStartRow()).toBe(0); await conditionPromise(
expect(component.getRenderedEndRow()).toBe(13); () =>
component.getRenderedStartRow() === 0 &&
component.getRenderedEndRow() === 13
);
expect(component.getScrollHeight()).toBe( expect(component.getScrollHeight()).toBe(
editor.getScreenLineCount() * component.getLineHeight() + editor.getScreenLineCount() * component.getLineHeight() +
getElementHeight(item2) + getElementHeight(item2) +

View File

@ -27,6 +27,9 @@ const ejsGrammarPath = require.resolve(
const rubyGrammarPath = require.resolve( const rubyGrammarPath = require.resolve(
'language-ruby/grammars/tree-sitter-ruby.cson' 'language-ruby/grammars/tree-sitter-ruby.cson'
); );
const rustGrammarPath = require.resolve(
'language-rust-bundled/grammars/tree-sitter-rust.cson'
);
describe('TreeSitterLanguageMode', () => { describe('TreeSitterLanguageMode', () => {
let editor, buffer; let editor, buffer;
@ -831,6 +834,81 @@ describe('TreeSitterLanguageMode', () => {
]); ]);
}); });
it('respects the `includeChildren` property of injection points', async () => {
const rustGrammar = new TreeSitterGrammar(
atom.grammars,
rustGrammarPath,
{
scopeName: 'rust',
parser: 'tree-sitter-rust',
scopes: {
identifier: 'variable',
field_identifier: 'property',
'call_expression > field_expression > field_identifier':
'function',
'macro_invocation > identifier': 'macro'
},
injectionRegExp: 'rust',
injectionPoints: [
{
type: 'macro_invocation',
language() {
return 'rust';
},
content(node) {
return node.lastChild;
},
// The tokens within a `token_tree` are all parsed as separate
// children of the `token_tree`. By default, when adding a language
// injection for a node, the node's children's ranges would be
// excluded from the injection. But for this injection point
// (parsing token trees as rust code), we want to reparse all of the
// content of the token tree.
includeChildren: true
}
]
}
);
atom.grammars.addGrammar(rustGrammar);
// Macro call within another macro call.
buffer.setText('assert_eq!(a.b.c(), vec![d.e()]); f.g();');
const languageMode = new TreeSitterLanguageMode({
buffer,
grammar: rustGrammar,
grammars: atom.grammars
});
buffer.setLanguageMode(languageMode);
// There should not be duplicate scopes due to the root layer
// and for the injected rust layer.
expectTokensToEqual(editor, [
[
{ text: 'assert_eq', scopes: ['macro'] },
{ text: '!(', scopes: [] },
{ text: 'a', scopes: ['variable'] },
{ text: '.', scopes: [] },
{ text: 'b', scopes: ['property'] },
{ text: '.', scopes: [] },
{ text: 'c', scopes: ['function'] },
{ text: '(), ', scopes: [] },
{ text: 'vec', scopes: ['macro'] },
{ text: '![', scopes: [] },
{ text: 'd', scopes: ['variable'] },
{ text: '.', scopes: [] },
{ text: 'e', scopes: ['function'] },
{ text: '()]); ', scopes: [] },
{ text: 'f', scopes: ['variable'] },
{ text: '.', scopes: [] },
{ text: 'g', scopes: ['function'] },
{ text: '();', scopes: [] }
]
]);
});
it('notifies onDidTokenize listeners the first time all syntax highlighting is done', async () => { it('notifies onDidTokenize listeners the first time all syntax highlighting is done', async () => {
const promise = new Promise(resolve => { const promise = new Promise(resolve => {
editor.onDidTokenize(event => { editor.onDidTokenize(event => {
@ -1477,7 +1555,7 @@ describe('TreeSitterLanguageMode', () => {
scopes: {}, scopes: {},
folds: [ folds: [
{ {
type: ['element', 'raw_element'], type: ['element', 'script_element'],
start: { index: 0 }, start: { index: 0 },
end: { index: -1 } end: { index: -1 }
} }
@ -1618,7 +1696,7 @@ describe('TreeSitterLanguageMode', () => {
parser: 'tree-sitter-html', parser: 'tree-sitter-html',
scopes: { scopes: {
fragment: 'text.html', fragment: 'text.html',
raw_element: 'script.tag' script_element: 'script.tag'
}, },
injectionRegExp: 'html', injectionRegExp: 'html',
injectionPoints: [SCRIPT_TAG_INJECTION_POINT] injectionPoints: [SCRIPT_TAG_INJECTION_POINT]
@ -1781,7 +1859,7 @@ describe('TreeSitterLanguageMode', () => {
'text.html', 'text.html',
'fragment', 'fragment',
'element', 'element',
'raw_element', 'script_element',
'raw_text', 'raw_text',
'program', 'program',
'expression_statement', 'expression_statement',
@ -1811,7 +1889,7 @@ describe('TreeSitterLanguageMode', () => {
[0, 5], [0, 5],
[0, 8] [0, 8]
]); ]);
expect(editor.bufferRangeForScopeAtPosition(null, [0, 9])).toEqual([ expect(editor.bufferRangeForScopeAtPosition(null, [0, 8])).toEqual([
[0, 8], [0, 8],
[0, 9] [0, 9]
]); ]);
@ -2210,6 +2288,47 @@ describe('TreeSitterLanguageMode', () => {
expect(editor.getSelectedText()).toBe('html ` <b>c${def()}e${f}g</b> `'); expect(editor.getSelectedText()).toBe('html ` <b>c${def()}e${f}g</b> `');
}); });
}); });
describe('.tokenizedLineForRow(row)', () => {
it('returns a shimmed TokenizedLine with tokens', () => {
const grammar = new TreeSitterGrammar(atom.grammars, jsGrammarPath, {
parser: 'tree-sitter-javascript',
scopes: {
program: 'source',
'call_expression > identifier': 'function',
property_identifier: 'property',
'call_expression > member_expression > property_identifier': 'method',
identifier: 'variable'
}
});
buffer.setText('aa.bbb = cc(d.eee());\n\n \n b');
const languageMode = new TreeSitterLanguageMode({ buffer, grammar });
buffer.setLanguageMode(languageMode);
expect(languageMode.tokenizedLineForRow(0).tokens).toEqual([
{ value: 'aa', scopes: ['source', 'variable'] },
{ value: '.', scopes: ['source'] },
{ value: 'bbb', scopes: ['source', 'property'] },
{ value: ' = ', scopes: ['source'] },
{ value: 'cc', scopes: ['source', 'function'] },
{ value: '(', scopes: ['source'] },
{ value: 'd', scopes: ['source', 'variable'] },
{ value: '.', scopes: ['source'] },
{ value: 'eee', scopes: ['source', 'method'] },
{ value: '());', scopes: ['source'] }
]);
expect(languageMode.tokenizedLineForRow(1).tokens).toEqual([]);
expect(languageMode.tokenizedLineForRow(2).tokens).toEqual([
{ value: ' ', scopes: ['source'] }
]);
expect(languageMode.tokenizedLineForRow(3).tokens).toEqual([
{ value: ' ', scopes: ['source'] },
{ value: 'b', scopes: ['source', 'variable'] }
]);
});
});
}); });
function nextHighlightingUpdate(languageMode) { function nextHighlightingUpdate(languageMode) {
@ -2290,7 +2409,7 @@ const HTML_TEMPLATE_LITERAL_INJECTION_POINT = {
}; };
const SCRIPT_TAG_INJECTION_POINT = { const SCRIPT_TAG_INJECTION_POINT = {
type: 'raw_element', type: 'script_element',
language() { language() {
return 'javascript'; return 'javascript';
}, },

View File

@ -1994,15 +1994,18 @@ describe('Workspace', () => {
expect( expect(
atom2.grammars atom2.grammars
.getGrammars() .getGrammars({ includeTreeSitter: true })
.map(grammar => grammar.scopeName) .map(grammar => grammar.scopeName)
.sort() .sort()
).toEqual([ ).toEqual([
'source.coffee', 'source.coffee',
'source.js', // Tree-sitter grammars also load
'source.js', 'source.js',
'source.js.regexp', 'source.js.regexp',
'source.js.regexp',
'source.js.regexp.replacement', 'source.js.regexp.replacement',
'source.jsdoc', 'source.jsdoc',
'source.jsdoc',
'source.litcoffee', 'source.litcoffee',
'text.plain.null-grammar', 'text.plain.null-grammar',
'text.todo' 'text.todo'
@ -2697,11 +2700,11 @@ describe('Workspace', () => {
}); });
}); });
describe('when the core.excludeVcsIgnoredPaths config is truthy', () => { describe('when the core.excludeVcsIgnoredPaths config is used', () => {
let projectPath; let projectPath;
let ignoredPath; let ignoredPath;
beforeEach(() => { beforeEach(async () => {
const sourceProjectPath = path.join( const sourceProjectPath = path.join(
__dirname, __dirname,
'fixtures', 'fixtures',
@ -2713,22 +2716,17 @@ describe('Workspace', () => {
const writerStream = fstream.Writer(projectPath); const writerStream = fstream.Writer(projectPath);
fstream.Reader(sourceProjectPath).pipe(writerStream); fstream.Reader(sourceProjectPath).pipe(writerStream);
waitsFor(done => { await new Promise(resolve => {
writerStream.on('close', done); writerStream.on('close', resolve);
writerStream.on('error', done); writerStream.on('error', resolve);
}); });
runs(() => { fs.renameSync(
fs.renameSync( path.join(projectPath, 'git.git'),
path.join(projectPath, 'git.git'), path.join(projectPath, '.git')
path.join(projectPath, '.git') );
); ignoredPath = path.join(projectPath, 'ignored.txt');
ignoredPath = path.join(projectPath, 'ignored.txt'); fs.writeFileSync(ignoredPath, 'this match should not be included');
fs.writeFileSync(
ignoredPath,
'this match should not be included'
);
});
}); });
afterEach(() => { afterEach(() => {
@ -2737,15 +2735,144 @@ describe('Workspace', () => {
} }
}); });
it('excludes ignored files', async () => { it('excludes ignored files when core.excludeVcsIgnoredPaths is true', async () => {
atom.project.setPaths([projectPath]); atom.project.setPaths([projectPath]);
atom.config.set('core.excludeVcsIgnoredPaths', true); atom.config.set('core.excludeVcsIgnoredPaths', true);
const resultHandler = jasmine.createSpy('result found'); const resultHandler = jasmine.createSpy('result found');
await scan(/match/, {}, () => resultHandler()); await scan(/match/, {}, ({ filePath }) => resultHandler(filePath));
expect(resultHandler).not.toHaveBeenCalled(); expect(resultHandler).not.toHaveBeenCalled();
}); });
it('does not exclude ignored files when core.excludeVcsIgnoredPaths is false', async () => {
atom.project.setPaths([projectPath]);
atom.config.set('core.excludeVcsIgnoredPaths', false);
const resultHandler = jasmine.createSpy('result found');
await scan(/match/, {}, ({ filePath }) => resultHandler(filePath));
expect(resultHandler).toHaveBeenCalledWith(
path.join(projectPath, 'ignored.txt')
);
});
it('does not exclude files when searching on an ignored folder even when core.excludeVcsIgnoredPaths is true', async () => {
fs.mkdirSync(path.join(projectPath, 'poop'));
ignoredPath = path.join(
path.join(projectPath, 'poop', 'whatever.txt')
);
fs.writeFileSync(ignoredPath, 'this match should be included');
atom.project.setPaths([projectPath]);
atom.config.set('core.excludeVcsIgnoredPaths', true);
const resultHandler = jasmine.createSpy('result found');
await scan(/match/, { paths: ['poop'] }, ({ filePath }) =>
resultHandler(filePath)
);
expect(resultHandler).toHaveBeenCalledWith(ignoredPath);
});
});
describe('when the core.followSymlinks config is used', () => {
let projectPath;
beforeEach(async () => {
const sourceProjectPath = path.join(
__dirname,
'fixtures',
'dir',
'a-dir'
);
projectPath = path.join(temp.mkdirSync('atom'));
const writerStream = fstream.Writer(projectPath);
fstream.Reader(sourceProjectPath).pipe(writerStream);
await new Promise(resolve => {
writerStream.on('close', resolve);
writerStream.on('error', resolve);
});
fs.symlinkSync(
path.join(__dirname, 'fixtures', 'dir', 'b'),
path.join(projectPath, 'symlink')
);
});
afterEach(() => {
if (fs.existsSync(projectPath)) {
fs.removeSync(projectPath);
}
});
it('follows symlinks when core.followSymlinks is true', async () => {
atom.project.setPaths([projectPath]);
atom.config.set('core.followSymlinks', true);
const resultHandler = jasmine.createSpy('result found');
await scan(/ccc/, {}, ({ filePath }) => resultHandler(filePath));
expect(resultHandler).toHaveBeenCalledWith(
path.join(projectPath, 'symlink')
);
});
it('does not follow symlinks when core.followSymlinks is false', async () => {
atom.project.setPaths([projectPath]);
atom.config.set('core.followSymlinks', false);
const resultHandler = jasmine.createSpy('result found');
await scan(/ccc/, {}, ({ filePath }) => resultHandler(filePath));
expect(resultHandler).not.toHaveBeenCalled();
});
});
describe('when there are hidden files', () => {
let projectPath;
beforeEach(async () => {
const sourceProjectPath = path.join(
__dirname,
'fixtures',
'dir',
'a-dir'
);
projectPath = path.join(temp.mkdirSync('atom'));
const writerStream = fstream.Writer(projectPath);
fstream.Reader(sourceProjectPath).pipe(writerStream);
await new Promise(resolve => {
writerStream.on('close', resolve);
writerStream.on('error', resolve);
});
// Note: This won't create a hidden file on Windows, in order to more
// accurately test this behaviour there, we should either use a package
// like `fswin` or manually spawn an `ATTRIB` command.
fs.writeFileSync(path.join(projectPath, '.hidden'), 'ccc');
});
afterEach(() => {
if (fs.existsSync(projectPath)) {
fs.removeSync(projectPath);
}
});
it('searches on hidden files', async () => {
atom.project.setPaths([projectPath]);
const resultHandler = jasmine.createSpy('result found');
await scan(/ccc/, {}, ({ filePath }) => resultHandler(filePath));
expect(resultHandler).toHaveBeenCalledWith(
path.join(projectPath, '.hidden')
);
});
}); });
it('includes only files when a directory filter is specified', async () => { it('includes only files when a directory filter is specified', async () => {

View File

@ -313,6 +313,8 @@ class AtomEnvironment {
this.attachSaveStateListeners(); this.attachSaveStateListeners();
this.windowEventHandler.initialize(this.window, this.document); this.windowEventHandler.initialize(this.window, this.document);
this.workspace.initialize();
const didChangeStyles = this.didChangeStyles.bind(this); const didChangeStyles = this.didChangeStyles.bind(this);
this.disposables.add(this.styles.onDidAddStyleElement(didChangeStyles)); this.disposables.add(this.styles.onDidAddStyleElement(didChangeStyles));
this.disposables.add(this.styles.onDidUpdateStyleElement(didChangeStyles)); this.disposables.add(this.styles.onDidUpdateStyleElement(didChangeStyles));
@ -429,7 +431,7 @@ class AtomEnvironment {
this.workspace.reset(this.packages); this.workspace.reset(this.packages);
this.registerDefaultOpeners(); this.registerDefaultOpeners();
this.project.reset(this.packages); this.project.reset(this.packages);
this.workspace.subscribeToEvents(); this.workspace.initialize();
this.grammars.clear(); this.grammars.clear();
this.textEditors.clear(); this.textEditors.clear();
this.views.clear(); this.views.clear();

View File

@ -6,6 +6,7 @@ fs = require 'fs-plus'
{remote} = require 'electron' {remote} = require 'electron'
MenuHelpers = require './menu-helpers' MenuHelpers = require './menu-helpers'
{sortMenuItems} = require './menu-sort-helpers' {sortMenuItems} = require './menu-sort-helpers'
_ = require 'underscore-plus'
platformContextMenu = require('../package.json')?._atomMenu?['context-menu'] platformContextMenu = require('../package.json')?._atomMenu?['context-menu']
@ -158,8 +159,15 @@ class ContextMenuManager
for id, item of template for id, item of template
if item.command if item.command
keymaps = @keymapManager.findKeyBindings({command: item.command, target: document.activeElement}) keymaps = @keymapManager.findKeyBindings({command: item.command, target: document.activeElement})
accelerator = MenuHelpers.acceleratorForKeystroke(keymaps?[0]?.keystrokes) keystrokes = keymaps?[0]?.keystrokes
item.accelerator = accelerator if accelerator if keystrokes
# Electron does not support multi-keystroke accelerators. Therefore,
# when the command maps to a multi-stroke key binding, show the
# keystrokes next to the item's label.
if keystrokes.includes(' ')
item.label += " [#{_.humanizeKeystroke(keystrokes)}]"
else
item.accelerator = MenuHelpers.acceleratorForKeystroke(keystrokes)
if Array.isArray(item.submenu) if Array.isArray(item.submenu)
@addAccelerators(item.submenu) @addAccelerators(item.submenu)

View File

@ -82,7 +82,7 @@ module.exports = class DefaultDirectorySearcher {
// Each item in the array is a file/directory pattern, e.g., `src` to search in the "src" // Each item in the array is a file/directory pattern, e.g., `src` to search in the "src"
// directory or `*.js` to search all JavaScript files. In practice, this often comes from the // directory or `*.js` to search all JavaScript files. In practice, this often comes from the
// comma-delimited list of patterns in the bottom text input of the ProjectFindView dialog. // comma-delimited list of patterns in the bottom text input of the ProjectFindView dialog.
// * `ignoreHidden` {boolean} whether to ignore hidden files. // * `includeHidden` {boolean} whether to ignore hidden files.
// * `excludeVcsIgnores` {boolean} whether to exclude VCS ignored paths. // * `excludeVcsIgnores` {boolean} whether to exclude VCS ignored paths.
// * `exclusions` {Array} similar to inclusions // * `exclusions` {Array} similar to inclusions
// * `follow` {boolean} whether symlinks should be followed. // * `follow` {boolean} whether symlinks should be followed.

View File

@ -148,6 +148,26 @@ module.exports = class GrammarRegistry {
return true; return true;
} }
// Extended: Force a {TextBuffer} to use a different grammar than the
// one that would otherwise be selected for it.
//
// * `buffer` The {TextBuffer} whose grammar will be set.
// * `grammar` The desired {Grammar}.
//
// Returns a {Boolean} that indicates whether the assignment was sucessful
assignGrammar(buffer, grammar) {
if (!grammar) return false;
if (buffer.getBuffer) buffer = buffer.getBuffer();
this.languageOverridesByBufferId.set(buffer.id, grammar.scopeName || null);
this.grammarScoresByBuffer.set(buffer, null);
if (grammar !== buffer.getLanguageMode().grammar) {
buffer.setLanguageMode(
this.languageModeForGrammarAndBuffer(grammar, buffer)
);
}
return true;
}
// Extended: Get the `languageId` that has been explicitly assigned to // Extended: Get the `languageId` that has been explicitly assigned to
// to the given buffer, if any. // to the given buffer, if any.
// //
@ -330,11 +350,7 @@ module.exports = class GrammarRegistry {
} }
forEachGrammar(callback) { forEachGrammar(callback) {
this.textmateRegistry.grammars.forEach(callback); this.getGrammars({ includeTreeSitter: true }).forEach(callback);
for (const grammarId in this.treeSitterGrammarsById) {
const grammar = this.treeSitterGrammarsById[grammarId];
if (grammar.scopeName) callback(grammar);
}
} }
grammarForId(languageId) { grammarForId(languageId) {
@ -482,7 +498,7 @@ module.exports = class GrammarRegistry {
} }
get grammars() { get grammars() {
return this.textmateRegistry.grammars; return this.getGrammars();
} }
decodeTokens() { decodeTokens() {
@ -601,9 +617,19 @@ module.exports = class GrammarRegistry {
// Extended: Get all the grammars in this registry. // Extended: Get all the grammars in this registry.
// //
// * `options` (optional) {Object}
// * `includeTreeSitter` (optional) {Boolean} Set to include
// [Tree-sitter](https://github.blog/2018-10-31-atoms-new-parsing-system/) grammars
//
// Returns a non-empty {Array} of {Grammar} instances. // Returns a non-empty {Array} of {Grammar} instances.
getGrammars() { getGrammars(params) {
return this.textmateRegistry.getGrammars(); let tmGrammars = this.textmateRegistry.getGrammars();
if (!(params && params.includeTreeSitter)) return tmGrammars;
const tsGrammars = Object.values(this.treeSitterGrammarsById).filter(
g => g.scopeName
);
return tmGrammars.concat(tsGrammars); // NullGrammar is expected to be first
} }
scopeForId(id) { scopeForId(id) {

View File

@ -41,6 +41,7 @@ if (global.isGeneratingSnapshot) {
require('language-html'); require('language-html');
require('language-javascript'); require('language-javascript');
require('language-ruby'); require('language-ruby');
require('language-rust-bundled');
require('language-typescript'); require('language-typescript');
require('line-ending-selector'); require('line-ending-selector');
require('link'); require('link');

View File

@ -222,10 +222,18 @@ module.exports = class ApplicationMenu {
template.forEach(item => { template.forEach(item => {
if (item.metadata == null) item.metadata = {}; if (item.metadata == null) item.metadata = {};
if (item.command) { if (item.command) {
item.accelerator = this.acceleratorForCommand( const keystrokes = keystrokesByCommand[item.command];
item.command, if (keystrokes && keystrokes.length > 0) {
keystrokesByCommand const keystroke = keystrokes[0];
); // Electron does not support multi-keystroke accelerators. Therefore,
// when the command maps to a multi-stroke key binding, show the
// keystrokes next to the item's label.
if (keystroke.includes(' ')) {
item.label += ` [${_.humanizeKeystroke(keystroke)}]`;
} else {
item.accelerator = MenuHelpers.acceleratorForKeystroke(keystroke);
}
}
item.click = () => item.click = () =>
global.atomApplication.sendCommand(item.command, item.commandDetail); global.atomApplication.sendCommand(item.command, item.commandDetail);
if (!/^application:/.test(item.command)) { if (!/^application:/.test(item.command)) {
@ -237,18 +245,4 @@ module.exports = class ApplicationMenu {
}); });
return template; return template;
} }
// Determine the accelerator for a given command.
//
// command - The name of the command.
// keystrokesByCommand - An Object where the keys are commands and the values
// are Arrays containing the keystroke.
//
// Returns a String containing the keystroke in a format that can be interpreted
// by Electron to provide nice icons where available.
acceleratorForCommand(command, keystrokesByCommand) {
const firstKeystroke =
keystrokesByCommand[command] && keystrokesByCommand[command][0];
return MenuHelpers.acceleratorForKeystroke(firstKeystroke);
}
}; };

View File

@ -283,7 +283,12 @@ module.exports = class AtomApplication extends EventEmitter {
// We need to do this because `listenForArgumentsFromNewProcess()` calls `crypto.randomBytes`, // We need to do this because `listenForArgumentsFromNewProcess()` calls `crypto.randomBytes`,
// which is really slow on Windows machines. // which is really slow on Windows machines.
// (TodoElectronIssue: This got fixed in electron v3: https://github.com/electron/electron/issues/2073). // (TodoElectronIssue: This got fixed in electron v3: https://github.com/electron/electron/issues/2073).
const socketServerPromise = this.listenForArgumentsFromNewProcess(options); let socketServerPromise;
if (options.test || options.benchmark || options.benchmarkTest) {
socketServerPromise = Promise.resolve();
} else {
socketServerPromise = this.listenForArgumentsFromNewProcess();
}
this.setupDockMenu(); this.setupDockMenu();
@ -505,12 +510,10 @@ module.exports = class AtomApplication extends EventEmitter {
// You can run the atom command multiple times, but after the first launch // You can run the atom command multiple times, but after the first launch
// the other launches will just pass their information to this server and then // the other launches will just pass their information to this server and then
// close immediately. // close immediately.
async listenForArgumentsFromNewProcess(options) { async listenForArgumentsFromNewProcess() {
if (!options.test && !options.benchmark && !options.benchmarkTest) { this.socketSecretPromise = createSocketSecret(this.version);
this.socketSecretPromise = createSocketSecret(this.version); this.socketSecret = await this.socketSecretPromise;
this.socketSecret = await this.socketSecretPromise; this.socketPath = getSocketPath(this.socketSecret);
this.socketPath = getSocketPath(this.socketSecret);
}
await this.deleteSocketFile(); await this.deleteSocketFile();

View File

@ -161,7 +161,6 @@ class MenuManager
for binding in @keymapManager.getKeyBindings() for binding in @keymapManager.getKeyBindings()
continue unless @includeSelector(binding.selector) continue unless @includeSelector(binding.selector)
continue if unsetKeystrokes.has(binding.keystrokes) continue if unsetKeystrokes.has(binding.keystrokes)
continue if binding.keystrokes.includes(' ')
continue if process.platform is 'darwin' and /^alt-(shift-)?.$/.test(binding.keystrokes) continue if process.platform is 'darwin' and /^alt-(shift-)?.$/.test(binding.keystrokes)
continue if process.platform is 'win32' and /^ctrl-alt-(shift-)?.$/.test(binding.keystrokes) continue if process.platform is 'win32' and /^ctrl-alt-(shift-)?.$/.test(binding.keystrokes)
keystrokesByCommand[binding.command] ?= [] keystrokesByCommand[binding.command] ?= []

View File

@ -43,7 +43,7 @@ class NativeCompileCache {
const script = new vm.Script(code, { filename, produceCachedData: true }); const script = new vm.Script(code, { filename, produceCachedData: true });
return { return {
result: script.runInThisContext(), result: script.runInThisContext(),
cacheBuffer: script.cachedData cacheBuffer: script.cachedDataProduced ? script.cachedData : null
}; };
} }
@ -102,7 +102,7 @@ class NativeCompileCache {
console.error(`Error running script ${filename}`); console.error(`Error running script ${filename}`);
throw err; throw err;
} }
if (compilationResult.cacheBuffer !== null) { if (compilationResult.cacheBuffer) {
self.cacheStore.set(cacheKey, compilationResult.cacheBuffer); self.cacheStore.set(cacheKey, compilationResult.cacheBuffer);
} }
compiledWrapper = compilationResult.result; compiledWrapper = compilationResult.result;

View File

@ -169,6 +169,7 @@ module.exports = class Package {
this.settings = []; this.settings = [];
this.mainInitialized = false; this.mainInitialized = false;
this.mainActivated = false; this.mainActivated = false;
this.deserialized = false;
} }
initializeIfNeeded() { initializeIfNeeded() {
@ -248,6 +249,8 @@ module.exports = class Package {
this.activationCommandSubscriptions.dispose(); this.activationCommandSubscriptions.dispose();
if (this.activationHookSubscriptions) if (this.activationHookSubscriptions)
this.activationHookSubscriptions.dispose(); this.activationHookSubscriptions.dispose();
if (this.workspaceOpenerSubscriptions)
this.workspaceOpenerSubscriptions.dispose();
} catch (error) { } catch (error) {
this.handleError(`Failed to activate the ${this.name} package`, error); this.handleError(`Failed to activate the ${this.name} package`, error);
} }
@ -559,6 +562,19 @@ module.exports = class Package {
this.registerViewProviders(); this.registerViewProviders();
this.requireMainModule(); this.requireMainModule();
this.initializeIfNeeded(); this.initializeIfNeeded();
if (atomEnvironment.packages.hasActivatedInitialPackages()) {
// Only explicitly activate the package if initial packages
// have finished activating. This is because deserialization
// generally occurs at Atom startup, which happens before the
// workspace element is added to the DOM and is inconsistent with
// with when initial package activation occurs. Triggering activation
// immediately may cause problems with packages that expect to
// always have access to the workspace element.
// Otherwise, we just set the deserialized flag and package-manager
// will activate this package as normal during initial package activation.
this.activateNow();
}
this.deserialized = true;
return this.mainModule[methodName](state, atomEnvironment); return this.mainModule[methodName](state, atomEnvironment);
} }
}); });
@ -933,9 +949,11 @@ module.exports = class Package {
activationShouldBeDeferred() { activationShouldBeDeferred() {
return ( return (
this.hasActivationCommands() || !this.deserialized &&
this.hasActivationHooks() || (this.hasActivationCommands() ||
this.hasDeferredURIHandler() this.hasActivationHooks() ||
this.hasWorkspaceOpeners() ||
this.hasDeferredURIHandler())
); );
} }
@ -944,6 +962,11 @@ module.exports = class Package {
return hooks && hooks.length > 0; return hooks && hooks.length > 0;
} }
hasWorkspaceOpeners() {
const openers = this.getWorkspaceOpeners();
return openers && openers.length > 0;
}
hasActivationCommands() { hasActivationCommands() {
const object = this.getActivationCommands(); const object = this.getActivationCommands();
for (let selector in object) { for (let selector in object) {
@ -961,6 +984,7 @@ module.exports = class Package {
subscribeToDeferredActivation() { subscribeToDeferredActivation() {
this.subscribeToActivationCommands(); this.subscribeToActivationCommands();
this.subscribeToActivationHooks(); this.subscribeToActivationHooks();
this.subscribeToWorkspaceOpeners();
} }
subscribeToActivationCommands() { subscribeToActivationCommands() {
@ -1058,6 +1082,41 @@ module.exports = class Package {
return this.activationHooks; return this.activationHooks;
} }
subscribeToWorkspaceOpeners() {
this.workspaceOpenerSubscriptions = new CompositeDisposable();
for (let opener of this.getWorkspaceOpeners()) {
this.workspaceOpenerSubscriptions.add(
atom.workspace.addOpener(filePath => {
if (filePath === opener) {
this.activateNow();
this.workspaceOpenerSubscriptions.dispose();
return atom.workspace.createItemForURI(opener);
}
})
);
}
}
getWorkspaceOpeners() {
if (this.workspaceOpeners) return this.workspaceOpeners;
if (this.metadata.workspaceOpeners) {
if (Array.isArray(this.metadata.workspaceOpeners)) {
this.workspaceOpeners = Array.from(
new Set(this.metadata.workspaceOpeners)
);
} else if (typeof this.metadata.workspaceOpeners === 'string') {
this.workspaceOpeners = [this.metadata.workspaceOpeners];
} else {
this.workspaceOpeners = [];
}
} else {
this.workspaceOpeners = [];
}
return this.workspaceOpeners;
}
getURIHandler() { getURIHandler() {
return this.metadata && this.metadata.uriHandler; return this.metadata && this.metadata.uriHandler;
} }

View File

@ -193,7 +193,7 @@ module.exports = class RipgrepDirectorySearcher {
// Each item in the array is a file/directory pattern, e.g., `src` to search in the "src" // Each item in the array is a file/directory pattern, e.g., `src` to search in the "src"
// directory or `*.js` to search all JavaScript files. In practice, this often comes from the // directory or `*.js` to search all JavaScript files. In practice, this often comes from the
// comma-delimited list of patterns in the bottom text input of the ProjectFindView dialog. // comma-delimited list of patterns in the bottom text input of the ProjectFindView dialog.
// * `ignoreHidden` {boolean} whether to ignore hidden files. // * `includeHidden` {boolean} whether to ignore hidden files.
// * `excludeVcsIgnores` {boolean} whether to exclude VCS ignored paths. // * `excludeVcsIgnores` {boolean} whether to exclude VCS ignored paths.
// * `exclusions` {Array} similar to inclusions // * `exclusions` {Array} similar to inclusions
// * `follow` {boolean} whether symlinks should be followed. // * `follow` {boolean} whether symlinks should be followed.
@ -230,7 +230,7 @@ module.exports = class RipgrepDirectorySearcher {
const directoryPath = directory.getPath(); const directoryPath = directory.getPath();
const regexpStr = this.prepareRegexp(regexp.source); const regexpStr = this.prepareRegexp(regexp.source);
const args = ['--hidden', '--json', '--regexp', regexpStr]; const args = ['--json', '--regexp', regexpStr];
if (options.leadingContextLineCount) { if (options.leadingContextLineCount) {
args.push('--before-context', options.leadingContextLineCount); args.push('--before-context', options.leadingContextLineCount);
} }
@ -257,10 +257,22 @@ module.exports = class RipgrepDirectorySearcher {
args.push('--multiline'); args.push('--multiline');
} }
args.push(directoryPath); if (options.includeHidden) {
args.push('--hidden');
}
if (options.follow) {
args.push('--follow');
}
if (!options.excludeVcsIgnores) {
args.push('--no-ignore-vcs');
}
args.push('.');
const child = spawn(this.rgPath, args, { const child = spawn(this.rgPath, args, {
cwd: directory.getPath(), cwd: directoryPath,
stdio: ['pipe', 'pipe', 'pipe'] stdio: ['pipe', 'pipe', 'pipe']
}); });
@ -301,7 +313,7 @@ module.exports = class RipgrepDirectorySearcher {
if (message.type === 'begin') { if (message.type === 'begin') {
pendingEvent = { pendingEvent = {
filePath: getText(message.data.path), filePath: path.join(directoryPath, getText(message.data.path)),
matches: [] matches: []
}; };
pendingLeadingContext = []; pendingLeadingContext = [];
@ -379,8 +391,6 @@ module.exports = class RipgrepDirectorySearcher {
pattern = pattern.slice(0, -1); pattern = pattern.slice(0, -1);
} }
pattern = pattern.startsWith('**/') ? pattern : `**/${pattern}`;
output.push(pattern); output.push(pattern);
output.push(pattern.endsWith('/**') ? pattern : `${pattern}/**`); output.push(pattern.endsWith('/**') ? pattern : `${pattern}/**`);
} }

View File

@ -10,21 +10,25 @@ class TokenizedLine
return unless properties? return unless properties?
{@openScopes, @text, @tags, @ruleStack, @tokenIterator, @grammar} = properties {@openScopes, @text, @tags, @ruleStack, @tokenIterator, @grammar, tokens} = properties
@cachedTokens = tokens
getTokenIterator: -> @tokenIterator.reset(this) getTokenIterator: -> @tokenIterator.reset(this)
Object.defineProperty @prototype, 'tokens', get: -> Object.defineProperty @prototype, 'tokens', get: ->
iterator = @getTokenIterator() if @cachedTokens
tokens = [] @cachedTokens
else
iterator = @getTokenIterator()
tokens = []
while iterator.next() while iterator.next()
tokens.push(new Token({ tokens.push(new Token({
value: iterator.getText() value: iterator.getText()
scopes: iterator.getScopes().slice() scopes: iterator.getScopes().slice()
})) }))
tokens tokens
tokenAtBufferColumn: (bufferColumn) -> tokenAtBufferColumn: (bufferColumn) ->
@tokens[@tokenIndexAtBufferColumn(bufferColumn)] @tokens[@tokenIndexAtBufferColumn(bufferColumn)]

View File

@ -119,6 +119,25 @@ module.exports = class TreeSitterGrammar {
} }
} }
} }
/*
Section - Backward compatibility shims
*/
onDidUpdate(callback) {
// do nothing
}
tokenizeLines(text, compatibilityMode = true) {
return text.split('\n').map(line => this.tokenizeLine(line, null, false));
}
tokenizeLine(line, ruleStack, firstLine) {
return {
value: line,
scopes: [this.scopeName]
};
}
}; };
const preprocessScopes = value => const preprocessScopes = value =>

View File

@ -32,7 +32,7 @@ class TreeSitterLanguageMode {
this.config = config; this.config = config;
this.grammarRegistry = grammars; this.grammarRegistry = grammars;
this.parser = new Parser(); this.parser = new Parser();
this.rootLanguageLayer = new LanguageLayer(this, grammar); this.rootLanguageLayer = new LanguageLayer(this, grammar, 0);
this.injectionsMarkerLayer = buffer.addMarkerLayer(); this.injectionsMarkerLayer = buffer.addMarkerLayer();
if (syncTimeoutMicros != null) { if (syncTimeoutMicros != null) {
@ -488,9 +488,45 @@ class TreeSitterLanguageMode {
*/ */
tokenizedLineForRow(row) { tokenizedLineForRow(row) {
const lineText = this.buffer.lineForRow(row);
const tokens = [];
const iterator = this.buildHighlightIterator();
let start = { row, column: 0 };
const scopes = iterator.seek(start, row);
while (true) {
const end = iterator.getPosition();
if (end.row > row) {
end.row = row;
end.column = lineText.length;
}
if (end.column > start.column) {
tokens.push(
new Token({
value: lineText.substring(start.column, end.column),
scopes: scopes.map(s => this.grammar.scopeNameForScopeId(s))
})
);
}
if (end.column < lineText.length) {
const closeScopeCount = iterator.getCloseScopeIds().length;
for (let i = 0; i < closeScopeCount; i++) {
scopes.pop();
}
scopes.push(...iterator.getOpenScopeIds());
start = end;
iterator.moveToSuccessor();
} else {
break;
}
}
return new TokenizedLine({ return new TokenizedLine({
openScopes: [], openScopes: [],
text: this.buffer.lineForRow(row), text: lineText,
tokens,
tags: [], tags: [],
ruleStack: [], ruleStack: [],
lineEnding: this.buffer.lineEndingForRow(row), lineEnding: this.buffer.lineEndingForRow(row),
@ -601,13 +637,13 @@ class TreeSitterLanguageMode {
} }
class LanguageLayer { class LanguageLayer {
constructor(languageMode, grammar, contentChildTypes) { constructor(languageMode, grammar, depth) {
this.languageMode = languageMode; this.languageMode = languageMode;
this.grammar = grammar; this.grammar = grammar;
this.tree = null; this.tree = null;
this.currentParsePromise = null; this.currentParsePromise = null;
this.patchSinceCurrentParseStarted = null; this.patchSinceCurrentParseStarted = null;
this.contentChildTypes = contentChildTypes; this.depth = depth;
} }
buildHighlightIterator() { buildHighlightIterator() {
@ -849,7 +885,7 @@ class LanguageLayer {
marker.languageLayer = new LanguageLayer( marker.languageLayer = new LanguageLayer(
this.languageMode, this.languageMode,
grammar, grammar,
injectionPoint.contentChildTypes this.depth + 1
); );
marker.parentLanguageLayer = this; marker.parentLanguageLayer = this;
} }
@ -859,7 +895,8 @@ class LanguageLayer {
new NodeRangeSet( new NodeRangeSet(
nodeRangeSet, nodeRangeSet,
injectionNodes, injectionNodes,
injectionPoint.newlinesBetween injectionPoint.newlinesBetween,
injectionPoint.includeChildren
) )
); );
} }
@ -874,7 +911,6 @@ class LanguageLayer {
} }
if (markersToUpdate.size > 0) { if (markersToUpdate.size > 0) {
this.lastUpdateWasAsync = true;
const promises = []; const promises = [];
for (const [marker, nodeRangeSet] of markersToUpdate) { for (const [marker, nodeRangeSet] of markersToUpdate) {
promises.push(marker.languageLayer.update(nodeRangeSet)); promises.push(marker.languageLayer.update(nodeRangeSet));
@ -911,75 +947,131 @@ class HighlightIterator {
} }
); );
this.iterators = [
this.languageMode.rootLanguageLayer.buildHighlightIterator()
];
for (const marker of injectionMarkers) {
this.iterators.push(marker.languageLayer.buildHighlightIterator());
}
this.iterators.sort((a, b) => b.getIndex() - a.getIndex());
const containingTags = []; const containingTags = [];
const containingTagStartIndices = []; const containingTagStartIndices = [];
const targetIndex = this.languageMode.buffer.characterIndexForPosition( const targetIndex = this.languageMode.buffer.characterIndexForPosition(
targetPosition targetPosition
); );
for (let i = this.iterators.length - 1; i >= 0; i--) {
this.iterators[i].seek( this.iterators = [];
targetIndex, const iterator = this.languageMode.rootLanguageLayer.buildHighlightIterator();
containingTags, if (iterator.seek(targetIndex, containingTags, containingTagStartIndices)) {
containingTagStartIndices this.iterators.push(iterator);
);
} }
this.iterators.sort((a, b) => b.getIndex() - a.getIndex());
// Populate the iterators array with all of the iterators whose syntax
// trees span the given position.
for (const marker of injectionMarkers) {
const iterator = marker.languageLayer.buildHighlightIterator();
if (
iterator.seek(targetIndex, containingTags, containingTagStartIndices)
) {
this.iterators.push(iterator);
}
}
// Sort the iterators so that the last one in the array is the earliest
// in the document, and represents the current position.
this.iterators.sort((a, b) => b.compare(a));
this.detectCoveredScope();
return containingTags; return containingTags;
} }
moveToSuccessor() { moveToSuccessor() {
const lastIndex = this.iterators.length - 1; // Advance the earliest layer iterator to its next scope boundary.
const leader = this.iterators[lastIndex]; let leader = last(this.iterators);
leader.moveToSuccessor();
const leaderCharIndex = leader.getIndex(); // Maintain the sorting of the iterators by their position in the document.
let i = lastIndex; if (leader.moveToSuccessor()) {
while (i > 0 && this.iterators[i - 1].getIndex() < leaderCharIndex) i--; const leaderIndex = this.iterators.length - 1;
if (i < lastIndex) this.iterators.splice(i, 0, this.iterators.pop()); let i = leaderIndex;
while (i > 0 && this.iterators[i - 1].compare(leader) < 0) i--;
if (i < leaderIndex) {
this.iterators.splice(i, 0, this.iterators.pop());
}
} else {
// If the layer iterator was at the end of its syntax tree, then remove
// it from the array.
this.iterators.pop();
}
this.detectCoveredScope();
}
// Detect whether or not another more deeply-nested language layer has a
// scope boundary at this same position. If so, the current language layer's
// scope boundary should not be reported.
detectCoveredScope() {
const layerCount = this.iterators.length;
if (layerCount > 1) {
const first = this.iterators[layerCount - 1];
const next = this.iterators[layerCount - 2];
if (
next.offset === first.offset &&
next.atEnd === first.atEnd &&
next.depth > first.depth
) {
this.currentScopeIsCovered = true;
return;
}
}
this.currentScopeIsCovered = false;
} }
getPosition() { getPosition() {
return last(this.iterators).getPosition(); const iterator = last(this.iterators);
if (iterator) {
return iterator.getPosition();
} else {
return Point.INFINITY;
}
} }
getCloseScopeIds() { getCloseScopeIds() {
return last(this.iterators).getCloseScopeIds(); const iterator = last(this.iterators);
if (iterator && !this.currentScopeIsCovered) {
return iterator.getCloseScopeIds();
}
return [];
} }
getOpenScopeIds() { getOpenScopeIds() {
return last(this.iterators).getOpenScopeIds(); const iterator = last(this.iterators);
if (iterator && !this.currentScopeIsCovered) {
return iterator.getOpenScopeIds();
}
return [];
} }
logState() { logState() {
const iterator = last(this.iterators); const iterator = last(this.iterators);
if (iterator.treeCursor) { if (iterator && iterator.treeCursor) {
console.log( console.log(
iterator.getPosition(), iterator.getPosition(),
iterator.treeCursor.nodeType, iterator.treeCursor.nodeType,
`depth=${iterator.languageLayer.depth}`,
new Range( new Range(
iterator.languageLayer.tree.rootNode.startPosition, iterator.languageLayer.tree.rootNode.startPosition,
iterator.languageLayer.tree.rootNode.endPosition iterator.languageLayer.tree.rootNode.endPosition
).toString() ).toString()
); );
console.log( if (this.currentScopeIsCovered) {
'close', console.log('covered');
iterator.closeTags.map(id => } else {
this.languageMode.grammar.scopeNameForScopeId(id) console.log(
) 'close',
); iterator.closeTags.map(id =>
console.log( this.languageMode.grammar.scopeNameForScopeId(id)
'open', )
iterator.openTags.map(id => );
this.languageMode.grammar.scopeNameForScopeId(id) console.log(
) 'open',
); iterator.openTags.map(id =>
this.languageMode.grammar.scopeNameForScopeId(id)
)
);
}
} }
} }
} }
@ -987,11 +1079,13 @@ class HighlightIterator {
class LayerHighlightIterator { class LayerHighlightIterator {
constructor(languageLayer, treeCursor) { constructor(languageLayer, treeCursor) {
this.languageLayer = languageLayer; this.languageLayer = languageLayer;
this.depth = this.languageLayer.depth;
// The iterator is always positioned at either the start or the end of some node // The iterator is always positioned at either the start or the end of some node
// in the syntax tree. // in the syntax tree.
this.atEnd = false; this.atEnd = false;
this.treeCursor = treeCursor; this.treeCursor = treeCursor;
this.offset = 0;
// In order to determine which selectors match its current node, the iterator maintains // In order to determine which selectors match its current node, the iterator maintains
// a list of the current node's ancestors. Because the selectors can use the `:nth-child` // a list of the current node's ancestors. Because the selectors can use the `:nth-child`
@ -1010,7 +1104,6 @@ class LayerHighlightIterator {
seek(targetIndex, containingTags, containingTagStartIndices) { seek(targetIndex, containingTags, containingTagStartIndices) {
while (this.treeCursor.gotoParent()) {} while (this.treeCursor.gotoParent()) {}
this.done = false;
this.atEnd = true; this.atEnd = true;
this.closeTags.length = 0; this.closeTags.length = 0;
this.openTags.length = 0; this.openTags.length = 0;
@ -1021,8 +1114,7 @@ class LayerHighlightIterator {
const containingTagEndIndices = []; const containingTagEndIndices = [];
if (targetIndex >= this.treeCursor.endIndex) { if (targetIndex >= this.treeCursor.endIndex) {
this.done = true; return false;
return;
} }
let childIndex = -1; let childIndex = -1;
@ -1055,22 +1147,24 @@ class LayerHighlightIterator {
} }
if (this.atEnd) { if (this.atEnd) {
const currentIndex = this.treeCursor.endIndex; this.offset = this.treeCursor.endIndex;
for (let i = 0, { length } = containingTags; i < length; i++) { for (let i = 0, { length } = containingTags; i < length; i++) {
if (containingTagEndIndices[i] === currentIndex) { if (containingTagEndIndices[i] === this.offset) {
this.closeTags.push(containingTags[i]); this.closeTags.push(containingTags[i]);
} }
} }
} else {
this.offset = this.treeCursor.startIndex;
} }
return containingTags; return true;
} }
moveToSuccessor() { moveToSuccessor() {
this.closeTags.length = 0; this.closeTags.length = 0;
this.openTags.length = 0; this.openTags.length = 0;
while (!this.done && !this.closeTags.length && !this.openTags.length) { while (!this.closeTags.length && !this.openTags.length) {
if (this.atEnd) { if (this.atEnd) {
if (this._moveRight()) { if (this._moveRight()) {
const scopeId = this._currentScopeId(); const scopeId = this._currentScopeId();
@ -1080,7 +1174,7 @@ class LayerHighlightIterator {
} else if (this._moveUp(true)) { } else if (this._moveUp(true)) {
this.atEnd = true; this.atEnd = true;
} else { } else {
this.done = true; return false;
} }
} else if (!this._moveDown()) { } else if (!this._moveDown()) {
const scopeId = this._currentScopeId(); const scopeId = this._currentScopeId();
@ -1089,26 +1183,30 @@ class LayerHighlightIterator {
this._moveUp(false); this._moveUp(false);
} }
} }
if (this.atEnd) {
this.offset = this.treeCursor.endIndex;
} else {
this.offset = this.treeCursor.startIndex;
}
return true;
} }
getPosition() { getPosition() {
if (this.done) { if (this.atEnd) {
return Point.INFINITY;
} else if (this.atEnd) {
return this.treeCursor.endPosition; return this.treeCursor.endPosition;
} else { } else {
return this.treeCursor.startPosition; return this.treeCursor.startPosition;
} }
} }
getIndex() { compare(other) {
if (this.done) { const result = this.offset - other.offset;
return Infinity; if (result !== 0) return result;
} else if (this.atEnd) { if (this.atEnd && !other.atEnd) return -1;
return this.treeCursor.endIndex; if (other.atEnd && !this.atEnd) return 1;
} else { return this.languageLayer.depth - other.languageLayer.depth;
return this.treeCursor.startIndex;
}
} }
getCloseScopeIds() { getCloseScopeIds() {
@ -1120,6 +1218,7 @@ class LayerHighlightIterator {
} }
// Private methods // Private methods
_moveUp(atLastChild) { _moveUp(atLastChild) {
let result = false; let result = false;
const { endIndex } = this.treeCursor; const { endIndex } = this.treeCursor;
@ -1227,10 +1326,10 @@ class NullHighlightIterator {
seek() { seek() {
return []; return [];
} }
moveToSuccessor() {} compare() {
getIndex() { return 1;
return Infinity;
} }
moveToSuccessor() {}
getPosition() { getPosition() {
return Point.INFINITY; return Point.INFINITY;
} }
@ -1243,10 +1342,11 @@ class NullHighlightIterator {
} }
class NodeRangeSet { class NodeRangeSet {
constructor(previous, nodes, newlinesBetween) { constructor(previous, nodes, newlinesBetween, includeChildren) {
this.previous = previous; this.previous = previous;
this.nodes = nodes; this.nodes = nodes;
this.newlinesBetween = newlinesBetween; this.newlinesBetween = newlinesBetween;
this.includeChildren = includeChildren;
} }
getRanges(buffer) { getRanges(buffer) {
@ -1257,18 +1357,20 @@ class NodeRangeSet {
let position = node.startPosition; let position = node.startPosition;
let index = node.startIndex; let index = node.startIndex;
for (const child of node.children) { if (!this.includeChildren) {
const nextIndex = child.startIndex; for (const child of node.children) {
if (nextIndex > index) { const nextIndex = child.startIndex;
this._pushRange(buffer, previousRanges, result, { if (nextIndex > index) {
startIndex: index, this._pushRange(buffer, previousRanges, result, {
endIndex: nextIndex, startIndex: index,
startPosition: position, endIndex: nextIndex,
endPosition: child.startPosition startPosition: position,
}); endPosition: child.startPosition
});
}
position = child.endPosition;
index = child.endIndex;
} }
position = child.endPosition;
index = child.endIndex;
} }
if (node.endIndex > index) { if (node.endIndex > index) {

View File

@ -76,7 +76,7 @@ const ALL_LOCATIONS = ['center', 'left', 'right', 'bottom'];
// Returns a {String} containing a longer version of the title to display in // Returns a {String} containing a longer version of the title to display in
// places like the window title or on tabs their short titles are ambiguous. // places like the window title or on tabs their short titles are ambiguous.
// //
// #### `onDidChangeTitle` // #### `onDidChangeTitle(callback)`
// //
// Called by the workspace so it can be notified when the item's title changes. // Called by the workspace so it can be notified when the item's title changes.
// Must return a {Disposable}. // Must return a {Disposable}.
@ -256,8 +256,6 @@ module.exports = class Workspace extends Model {
}; };
this.incoming = new Map(); this.incoming = new Map();
this.subscribeToEvents();
} }
get paneContainer() { get paneContainer() {
@ -375,9 +373,9 @@ module.exports = class Workspace extends Model {
this.consumeServices(this.packageManager); this.consumeServices(this.packageManager);
} }
subscribeToEvents() { initialize() {
this.originalFontSize = this.config.get('editor.fontSize');
this.project.onDidChangePaths(this.updateWindowTitle); this.project.onDidChangePaths(this.updateWindowTitle);
this.subscribeToFontSize();
this.subscribeToAddedItems(); this.subscribeToAddedItems();
this.subscribeToMovedItems(); this.subscribeToMovedItems();
this.subscribeToDockToggling(); this.subscribeToDockToggling();
@ -1518,6 +1516,10 @@ module.exports = class Workspace extends Model {
// that is already open in a text editor view. You could signal this by calling // that is already open in a text editor view. You could signal this by calling
// {Workspace::open} on the URI `quux-preview://foo/bar/baz.quux`. Then your opener // {Workspace::open} on the URI `quux-preview://foo/bar/baz.quux`. Then your opener
// can check the protocol for quux-preview and only handle those URIs that match. // can check the protocol for quux-preview and only handle those URIs that match.
//
// To defer your package's activation until a specific URL is opened, add a
// `workspaceOpeners` field to your `package.json` containing an array of URL
// strings.
addOpener(opener) { addOpener(opener) {
this.openers.push(opener); this.openers.push(opener);
return new Disposable(() => { return new Disposable(() => {
@ -1749,14 +1751,6 @@ module.exports = class Workspace extends Model {
} }
} }
subscribeToFontSize() {
return this.config.onDidChange('editor.fontSize', () => {
if (this.originalFontSize == null) {
this.originalFontSize = this.config.get('editor.fontSize');
}
});
}
// Removes the item's uri from the list of potential items to reopen. // Removes the item's uri from the list of potential items to reopen.
itemOpened(item) { itemOpened(item) {
let uri; let uri;