diff --git a/README.md b/README.md index 2763ab95f..0aff6e44b 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ ![Atom](https://cloud.githubusercontent.com/assets/72919/2874231/3af1db48-d3dd-11e3-98dc-6066f8bc766f.png) -[![macOS Build Status](https://circleci.com/gh/atom/atom.svg?style=svg)](https://circleci.com/gh/atom/atom) [![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) +[![macOS Build Status](https://circleci.com/gh/atom/atom/tree/master.svg?style=shield)](https://circleci.com/gh/atom/atom) [![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) [![Dependency Status](https://david-dm.org/atom/atom.svg)](https://david-dm.org/atom/atom) [![Join the Atom Community on Slack](http://atom-slack.herokuapp.com/badge.svg)](http://atom-slack.herokuapp.com/) @@ -33,15 +33,14 @@ Atom will automatically update when a new release is available. ### Windows -Download the latest [AtomSetup.exe installer](https://github.com/atom/atom/releases/latest). +Download the latest [Atom installer](https://github.com/atom/atom/releases/latest). AtomSetup.exe is 32-bit, AtomSetup-x64.exe for 64-bit systems. Atom will automatically update when a new release is available. -You can also download an `atom-windows.zip` file from the [releases page](https://github.com/atom/atom/releases/latest). +You can also download `atom-windows.zip` (32-bit) or `atom-x64-windows.zip` (64-bit) from the [releases page](https://github.com/atom/atom/releases/latest). The `.zip` version will not automatically update. -Using [chocolatey](https://chocolatey.org/)? Run `cinst Atom` to install -the latest version of Atom. +Using [chocolatey](https://chocolatey.org/)? Run `cinst Atom` to install the latest version of Atom. ### Debian Linux (Ubuntu) @@ -54,7 +53,7 @@ Atom is only available for 64-bit Linux systems. The Linux version does not currently automatically update so you will need to repeat these steps to upgrade to future releases. -### Red Hat Linux (Fedora 21 and under, CentOS, Red Hat) +### Red Hat Enterprise Linux (RHEL) / CentOS Atom is only available for 64-bit Linux systems. @@ -65,12 +64,12 @@ Atom is only available for 64-bit Linux systems. The Linux version does not currently automatically update so you will need to repeat these steps to upgrade to future releases. -### Fedora 22+ +### Fedora Atom is only available for 64-bit Linux systems. 1. Download `atom.x86_64.rpm` from the [Atom releases page](https://github.com/atom/atom/releases/latest). -2. Run `sudo dnf install ./atom.x86_64.rpm` on the downloaded package. +2. Run `sudo dnf install atom.x86_64.rpm` on the downloaded package. 3. Launch Atom using the installed `atom` command. The Linux version does not currently automatically update so you will need to diff --git a/apm/package.json b/apm/package.json index ea5480db3..732ab208a 100644 --- a/apm/package.json +++ b/apm/package.json @@ -6,6 +6,6 @@ "url": "https://github.com/atom/atom.git" }, "dependencies": { - "atom-package-manager": "1.14.1" + "atom-package-manager": "1.15.1" } } diff --git a/appveyor.yml b/appveyor.yml index f194661c7..a9a0d7920 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -8,13 +8,14 @@ clone_depth: 10 platform: - x86 + - x64 environment: global: ATOM_DEV_RESOURCE_PATH: c:\projects\atom matrix: - - NODE_VERSION: 4.4.5 + - NODE_VERSION: 6.8.0 install: - SET PATH=C:\Program Files\Atom\resources\cli;%PATH% @@ -49,6 +50,4 @@ cache: - '%APPVEYOR_BUILD_FOLDER%\node_modules' - '%APPVEYOR_BUILD_FOLDER%\electron' - '%USERPROFILE%\.atom\.apm' - - '%USERPROFILE%\.atom\.node-gyp\.atom' - - '%USERPROFILE%\.atom\.npm' - '%USERPROFILE%\.atom\compile-cache' diff --git a/atom.sh b/atom.sh index a8c30fa19..47c902ce9 100755 --- a/atom.sh +++ b/atom.sh @@ -55,11 +55,22 @@ if [ $EXPECT_OUTPUT ]; then fi if [ $OS == 'Mac' ]; then + if [ -L "$0" ]; then + SCRIPT="$(readlink "$0")" + else + SCRIPT="$0" + fi + ATOM_APP="$(dirname "$(dirname "$(dirname "$(dirname "$SCRIPT")")")")" + if [ "$ATOM_APP" == . ]; then + unset ATOM_APP + else + ATOM_PATH="$(dirname "$ATOM_APP")" + ATOM_APP_NAME="$(basename "$ATOM_APP")" + fi + if [ -n "$BETA_VERSION" ]; then - ATOM_APP_NAME="Atom Beta.app" ATOM_EXECUTABLE_NAME="Atom Beta" else - ATOM_APP_NAME="Atom.app" ATOM_EXECUTABLE_NAME="Atom" fi diff --git a/docs/build-instructions/build-status.md b/docs/build-instructions/build-status.md index a17923224..86f077639 100644 --- a/docs/build-instructions/build-status.md +++ b/docs/build-instructions/build-status.md @@ -2,111 +2,112 @@ | System | macOS | Windows | Dependencies | |--------|------|---------|--------------| -| Atom | [![macOS 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) | [![Dependency Status](https://david-dm.org/atom/atom.svg)](https://david-dm.org/atom/atom) | -| APM | [![macOS Build Status](https://travis-ci.org/atom/apm.svg?branch=master)](https://travis-ci.org/atom/apm) | [![Windows 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 | [![macOS Build Status](https://travis-ci.org/electron/electron.svg?branch=master)](https://travis-ci.org/electron/electron) | [![Windows 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) +| [Atom](https://github.com/atom/atom) | [![macOS 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) | [![Dependency Status](https://david-dm.org/atom/atom.svg)](https://david-dm.org/atom/atom) | +| [APM](https://github.com/atom/apm) | [![macOS Build Status](https://travis-ci.org/atom/apm.svg?branch=master)](https://travis-ci.org/atom/apm) | [![Windows 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) | [![macOS Build Status](https://travis-ci.org/electron/electron.svg?branch=master)](https://travis-ci.org/electron/electron) | [![Windows 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) ## Packages | Package | macOS | Windows | Dependencies | |---------|------|---------|--------------| -| About | [![macOS Build Status](https://travis-ci.org/atom/about.svg?branch=master)](https://travis-ci.org/atom/about) | [![Windows Build Status](https://ci.appveyor.com/api/projects/status/msprea3vq47l8oce/branch/master?svg=true)](https://ci.appveyor.com/project/atom/about/branch/master) | [![Dependency Status](https://david-dm.org/atom/about.svg)](https://david-dm.org/atom/about) | -| Archive View | [![macOS Build Status](https://travis-ci.org/atom/archive-view.svg?branch=master)](https://travis-ci.org/atom/archive-view) | [![Windows Build status](https://ci.appveyor.com/api/projects/status/u3qfgaod4lhriqlj/branch/master?svg=true)](https://ci.appveyor.com/project/Atom/archive-view/branch/master) | [![Dependency Status](https://david-dm.org/atom/archive-view.svg)](https://david-dm.org/atom/archive-view) | -| AutoComplete Atom API | [![macOS Build Status](https://travis-ci.org/atom/autocomplete-atom-api.svg?branch=master)](https://travis-ci.org/atom/autocomplete-atom-api) | [![Windows Build Status](https://ci.appveyor.com/api/projects/status/1x3uqd9ddchpe555/branch/master?svg=true)](https://ci.appveyor.com/project/Atom/autocomplete-atom-api/branch/master) | [![Dependency Status](https://david-dm.org/atom/autocomplete-atom-api.svg)](https://david-dm.org/atom/autocomplete-atom-api) | -| Atom Space Pen Views | [![macOS Build Status](https://travis-ci.org/atom/atom-space-pen-views.svg?branch=master)](https://travis-ci.org/atom/atom-space-pen-views) | [![Windows Build Status](https://ci.appveyor.com/api/projects/status/5lgv47has6n8uhuv/branch/master?svg=true)](https://ci.appveyor.com/project/Atom/atom-space-pen-views/branch/master) | [![Dependency Status](https://david-dm.org/atom/atom-space-pen-views.svg)](https://david-dm.org/atom/atom-space-pen-views) | -| AutoComplete CSS | [![macOS Build Status](https://travis-ci.org/atom/autocomplete-css.svg?branch=master)](https://travis-ci.org/atom/autocomplete-css) | [![Windows Build Status](https://ci.appveyor.com/api/projects/status/k3e5uvpmpc5bkja9/branch/master?svg=true)](https://ci.appveyor.com/project/Atom/autocomplete-css/branch/master) | [![Dependency Status](https://david-dm.org/atom/autocomplete-css.svg)](https://david-dm.org/atom/autocomplete-css) | -| AutoComplete HTML | [![macOS Build Status](https://travis-ci.org/atom/autocomplete-html.svg?branch=master)](https://travis-ci.org/atom/autocomplete-html) | [![Windows Build Status](https://ci.appveyor.com/api/projects/status/bsaqbg1fljpd9q1b/branch/master?svg=true)](https://ci.appveyor.com/project/Atom/autocomplete-html/branch/master) | [![Dependency Status](https://david-dm.org/atom/autocomplete-html.svg)](https://david-dm.org/atom/autocomplete-html) | -| AutoComplete+ | [![macOS Build Status](https://travis-ci.org/atom/autocomplete-plus.svg?branch=master)](https://travis-ci.org/atom/autocomplete-plus) | [![Windows Build status](https://ci.appveyor.com/api/projects/status/9bpokrud2apgqsq0/branch/master?svg=true)](https://ci.appveyor.com/project/Atom/autocomplete-plus/branch/master) | [![Dependency Status](https://david-dm.org/atom/autocomplete-plus.svg)](https://david-dm.org/atom/autocomplete-plus) | -| AutoComplete Snippets | [![macOS Build Status](https://travis-ci.org/atom/autocomplete-snippets.svg)](https://travis-ci.org/atom/autocomplete-snippets) | [![Windows Build Status](https://ci.appveyor.com/api/projects/status/72kfi83l6cw90joy/branch/master?svg=true)](https://ci.appveyor.com/project/Atom/autocomplete-snippets/branch/master) | [![Dependency Status](https://david-dm.org/atom/autocomplete-snippets.svg)](https://david-dm.org/atom/autocomplete-snippets) | -| AutoFlow | [![macOS Build Status](https://travis-ci.org/atom/autoflow.svg?branch=master)](https://travis-ci.org/atom/autoflow) | [![Windows Build Status](https://ci.appveyor.com/api/projects/status/kpmsnkbooa29x907/branch/master?svg=true)](https://ci.appveyor.com/project/Atom/autoflow/branch/master) | [![Dependency Status](https://david-dm.org/atom/autoflow.svg)](https://david-dm.org/atom/autoflow) | -| AutoSave | [![macOS Build Status](https://travis-ci.org/atom/autosave.svg?branch=master)](https://travis-ci.org/atom/autosave) | [![Windows Build Status](https://ci.appveyor.com/api/projects/status/3aktr9updp722fqx/branch/master?svg=true)](https://ci.appveyor.com/project/Atom/autosave/branch/master) | [![Dependency Status](https://david-dm.org/atom/autosave.svg)](https://david-dm.org/atom/autosave) | -| Background Tips | [![macOS Build Status](https://travis-ci.org/atom/background-tips.svg?branch=master)](https://travis-ci.org/atom/background-tips) | [![Windows Build Status](https://ci.appveyor.com/api/projects/status/2utcugietl5vjc7w/branch/master?svg=true)](https://ci.appveyor.com/project/Atom/background-tips/branch/master) | [![Dependency Status](https://david-dm.org/atom/background-tips.svg)](https://david-dm.org/atom/background-tips) | -| Bookmarks | [![macOS Build Status](https://travis-ci.org/atom/bookmarks.svg?branch=master)](https://travis-ci.org/atom/bookmarks) | [![Windows Build Status](https://ci.appveyor.com/api/projects/status/vjsf78pj4rw6ibcw/branch/master?svg=true)](https://ci.appveyor.com/project/Atom/bookmarks/branch/master) | [![Dependency Status](https://david-dm.org/atom/bookmarks.svg)](https://david-dm.org/atom/bookmarks) | -| Bracket Matcher | [![macOS Build Status](https://travis-ci.org/atom/bracket-matcher.svg?branch=master)](https://travis-ci.org/atom/bracket-matcher) | [![Windows Build status](https://ci.appveyor.com/api/projects/status/rrsl2h7e0od26k54/branch/master?svg=true)](https://ci.appveyor.com/project/Atom/bracket-matcher/branch/master) | [![Dependency Status](https://david-dm.org/atom/bracket-matcher.svg)](https://david-dm.org/atom/bracket-matcher) | -| Command Palette | [![macOS Build Status](https://travis-ci.org/atom/command-palette.svg?branch=master)](https://travis-ci.org/atom/command-palette) | [![Windows Build Status](https://ci.appveyor.com/api/projects/status/jqgwetayr0enorun/branch/master?svg=true)](https://ci.appveyor.com/project/Atom/command-palette/branch/master) | [![Dependency Status](https://david-dm.org/atom/command-palette.svg)](https://david-dm.org/atom/command-palette) | -| Deprecation Cop | [![macOS Build Status](https://travis-ci.org/atom/deprecation-cop.svg?branch=master)](https://travis-ci.org/atom/deprecation-cop) | [![Windows Build Status](https://ci.appveyor.com/api/projects/status/0s870q5fj3vwihjx/branch/master?svg=true)](https://ci.appveyor.com/project/Atom/deprecation-cop/branch/master) | [![Dependency Status](https://david-dm.org/atom/deprecation-cop.svg)](https://david-dm.org/atom/deprecation-cop) | -| Dev Live Reload | [![macOS Build Status](https://travis-ci.org/atom/dev-live-reload.svg?branch=master)](https://travis-ci.org/atom/dev-live-reload) | [![Windows Build Status](https://ci.appveyor.com/api/projects/status/g3sd27ylba1fun1v/branch/master?svg=true)](https://ci.appveyor.com/project/Atom/dev-live-reload/branch/master) | [![Dependency Status](https://david-dm.org/atom/dev-live-reload.svg)](https://david-dm.org/atom/dev-live-reload) | -| Encoding Selector | [![macOS Build Status](https://travis-ci.org/atom/encoding-selector.svg?branch=master)](https://travis-ci.org/atom/encoding-selector) | [![Windows Build Status](https://ci.appveyor.com/api/projects/status/e08x6k2b68wpwxxc/branch/master?svg=true)](https://ci.appveyor.com/project/Atom/encoding-selector/branch/master) | [![Dependency Status](https://david-dm.org/atom/encoding-selector.svg)](https://david-dm.org/atom/encoding-selector) | -| Exception Reporting | [![macOS Build Status](https://travis-ci.org/atom/exception-reporting.svg?branch=master)](https://travis-ci.org/atom/exception-reporting) | [![Windows Build Status](https://ci.appveyor.com/api/projects/status/i0pla7qbpv7celg2/branch/master?svg=true)](https://ci.appveyor.com/project/Atom/exception-reporting/branch/master) | [![Dependency Status](https://david-dm.org/atom/exception-reporting.svg)](https://david-dm.org/atom/exception-reporting) | -| Find and Replace | [![macOS Build Status](https://travis-ci.org/atom/find-and-replace.svg?branch=master)](https://travis-ci.org/atom/find-and-replace) | [![Windows Build Status](https://ci.appveyor.com/api/projects/status/6w4baiiq5mw4nxky/branch/master?svg=true)](https://ci.appveyor.com/project/Atom/find-and-replace/branch/master) | [![Dependency Status](https://david-dm.org/atom/find-and-replace.svg)](https://david-dm.org/atom/find-and-replace) | -| Fuzzy Finder | [![macOS Build Status](https://travis-ci.org/atom/fuzzy-finder.svg?branch=master)](https://travis-ci.org/atom/fuzzy-finder) | [![Windows Build Status](https://ci.appveyor.com/api/projects/status/b4b2dg5n9r1wdqad/branch/master?svg=true)](https://ci.appveyor.com/project/Atom/fuzzy-finder/branch/master) | [![Dependency Status](https://david-dm.org/atom/fuzzy-finder.svg)](https://david-dm.org/atom/fuzzy-finder) | -| Git Diff | [![macOS Build Status](https://travis-ci.org/atom/git-diff.svg?branch=master)](https://travis-ci.org/atom/git-diff) | [![Windows Build Status](https://ci.appveyor.com/api/projects/status/9auj52cs0vso66nv/branch/master?svg=true)](https://ci.appveyor.com/project/Atom/git-diff/branch/master) | [![Dependency Status](https://david-dm.org/atom/git-diff.svg)](https://david-dm.org/atom/git-diff) | -| Go to Line | [![macOS Build Status](https://travis-ci.org/atom/go-to-line.svg?branch=master)](https://travis-ci.org/atom/go-to-line) | [![Windows Build Status](https://ci.appveyor.com/api/projects/status/qf0isc8ulw4wxi0b/branch/master?svg=true)](https://ci.appveyor.com/project/Atom/go-to-line/branch/master) | [![Dependency Status](https://david-dm.org/atom/go-to-line.svg)](https://david-dm.org/atom/go-to-line) | -| Grammar Selector | [![macOS Build Status](https://travis-ci.org/atom/grammar-selector.svg?branch=master)](https://travis-ci.org/atom/grammar-selector) | [![Windows Build Status](https://ci.appveyor.com/api/projects/status/pg8qss03bfh4ngqm/branch/master?svg=true)](https://ci.appveyor.com/project/Atom/grammar-selector/branch/master) | [![Dependency Status](https://david-dm.org/atom/grammar-selector.svg)](https://david-dm.org/atom/grammar-selector) | -| Image View | [![macOS Build Status](https://travis-ci.org/atom/image-view.svg?branch=master)](https://travis-ci.org/atom/image-view) | [![Windows Build Status](https://ci.appveyor.com/api/projects/status/notavaawrswk0g10/branch/master?svg=true)](https://ci.appveyor.com/project/Atom/image-view/branch/master) | [![Dependency Status](https://david-dm.org/atom/image-view.svg)](https://david-dm.org/atom/image-view) | -| Incompatible Packages | [![macOS Build Status](https://travis-ci.org/atom/incompatible-packages.svg?branch=master)](https://travis-ci.org/atom/incompatible-packages) | [![Windows Build Status](https://ci.appveyor.com/api/projects/status/neet595s038x7w70/branch/master?svg=true)](https://ci.appveyor.com/project/Atom/incompatible-packages/branch/master) | [![Dependency Status](https://david-dm.org/atom/incompatible-packages.svg)](https://david-dm.org/atom/incompatible-packages) | -| Keybinding Resolver | [![macOS Build Status](https://travis-ci.org/atom/keybinding-resolver.svg?branch=master)](https://travis-ci.org/atom/keybinding-resolver) | [![Windows Build Status](https://ci.appveyor.com/api/projects/status/9jf31itx01hnn4nh/branch/master?svg=true)](https://ci.appveyor.com/project/Atom/keybinding-resolver/branch/master) | [![Dependency Status](https://david-dm.org/atom/keybinding-resolver.svg)](https://david-dm.org/atom/keybinding-resolver) | -| Line Ending Selector | [![macOS Build Status](https://travis-ci.org/atom/line-ending-selector.svg?branch=master)](https://travis-ci.org/atom/line-ending-selector) | [![Windows Build Status](https://ci.appveyor.com/api/projects/status/b3743n9ojomlpn1g/branch/master?svg=true)](https://ci.appveyor.com/project/Atom/line-ending-selector/branch/master) | [![Dependency Status](https://david-dm.org/atom/line-ending-selector.svg)](https://david-dm.org/atom/line-ending-selector) | -| Link | [![macOS Build Status](https://travis-ci.org/atom/link.svg?branch=master)](https://travis-ci.org/atom/link) | [![Windows Build Status](https://ci.appveyor.com/api/projects/status/1d3cb8ktd48k9vnl/branch/master?svg=true)](https://ci.appveyor.com/project/Atom/link/branch/master) | [![Dependency Status](https://david-dm.org/atom/link.svg)](https://david-dm.org/atom/link) | -| Markdown Preview | [![macOS Build Status](https://travis-ci.org/atom/markdown-preview.svg?branch=master)](https://travis-ci.org/atom/markdown-preview) | [![Windows Build Status](https://ci.appveyor.com/api/projects/status/bvh0evhh4v6w9b29/branch/master?svg=true)](https://ci.appveyor.com/project/Atom/markdown-preview/branch/master) | [![Dependency Status](https://david-dm.org/atom/markdown-preview.svg)](https://david-dm.org/atom/markdown-preview) | -| Metrics | [![macOS Build Status](https://travis-ci.org/atom/metrics.svg?branch=master)](https://travis-ci.org/atom/metrics) | [![Windows Build Status](https://ci.appveyor.com/api/projects/status/b5doi205xl3iex04/branch/master?svg=true)](https://ci.appveyor.com/project/Atom/metrics/branch/master) | [![Dependency Status](https://david-dm.org/atom/metrics.svg)](https://david-dm.org/atom/metrics) | -| Notifications | [![macOS Build Status](https://travis-ci.org/atom/notifications.svg?branch=master)](https://travis-ci.org/atom/notifications) | [![Windows Build Status](https://ci.appveyor.com/api/projects/status/ps3p8tj2okw57x0e/branch/master?svg=true)](https://ci.appveyor.com/project/Atom/notifications/branch/master) | [![Dependency Status](https://david-dm.org/atom/notifications.svg)](https://david-dm.org/atom/notifications) | -| Open on Github | [![macOS Build Status](https://travis-ci.org/atom/open-on-github.svg?branch=master)](https://travis-ci.org/atom/open-on-github) | [![Windows Build Status](https://ci.appveyor.com/api/projects/status/ccl6na4qsna5wncr/branch/master?svg=true)](https://ci.appveyor.com/project/Atom/open-on-github/branch/master) | [![Dependency Status](https://david-dm.org/atom/open-on-github.svg)](https://david-dm.org/atom/open-on-github) | -| Package Generator | [![macOS Build Status](https://travis-ci.org/atom/package-generator.svg?branch=master)](https://travis-ci.org/atom/package-generator)| [![Windows Build Status](https://ci.appveyor.com/api/projects/status/7t1i4hdmljhigp9u/branch/master?svg=true)](https://ci.appveyor.com/project/Atom/package-generator/branch/master) | [![Dependency Status](https://david-dm.org/atom/package-generator.svg)](https://david-dm.org/atom/package-generator) | -| Settings View | [![macOS Build Status](https://travis-ci.org/atom/settings-view.svg?branch=master)](https://travis-ci.org/atom/settings-view) | [![Windows Build Status](https://ci.appveyor.com/api/projects/status/hatgxg6k2g3grafq/branch/master?svg=true)](https://ci.appveyor.com/project/Atom/settings-view/branch/master) | [![Dependency Status](https://david-dm.org/atom/settings-view.svg)](https://david-dm.org/atom/settings-view) | -| Snippets | [![macOS Build Status](https://travis-ci.org/atom/snippets.svg?branch=master)](https://travis-ci.org/atom/snippets) | [![Windows Build Status](https://ci.appveyor.com/api/projects/status/8hlc0onofkgbxw53/branch/master?svg=true)](https://ci.appveyor.com/project/Atom/snippets/branch/master) | [![Dependency Status](https://david-dm.org/atom/snippets.svg)](https://david-dm.org/atom/snippets) | -| Spell Check | [![macOS Build Status](https://travis-ci.org/atom/spell-check.svg?branch=master)](https://travis-ci.org/atom/spell-check) | [![Windows Build Status](https://ci.appveyor.com/api/projects/status/1620a5reqw6kdolv/branch/master?svg=true)](https://ci.appveyor.com/project/Atom/spell-check/branch/master) | [![Dependency Status](https://david-dm.org/atom/spell-check.svg)](https://david-dm.org/atom/spell-check) | -| Status Bar | [![macOS Build Status](https://travis-ci.org/atom/status-bar.svg?branch=master)](https://travis-ci.org/atom/status-bar) | [![Windows Build Status](https://ci.appveyor.com/api/projects/status/gu8tv4h6cnpeesg2/branch/master?svg=true)](https://ci.appveyor.com/project/Atom/status-bar/branch/master) | [![Dependency Status](https://david-dm.org/atom/status-bar.svg)](https://david-dm.org/atom/status-bar) | -| Styleguide | [![macOS Build Status](https://travis-ci.org/atom/styleguide.svg?branch=master)](https://travis-ci.org/atom/styleguide) | [![Windows Build Status](https://ci.appveyor.com/api/projects/status/88dt9jxexkpindhw/branch/master?svg=true)](https://ci.appveyor.com/project/Atom/styleguide/branch/master) | [![Dependency Status](https://david-dm.org/atom/styleguide.svg)](https://david-dm.org/atom/styleguide) | -| Symbols View | [![macOS Build Status](https://travis-ci.org/atom/symbols-view.svg?branch=master)](https://travis-ci.org/atom/symbols-view) | [![Windows Build Status](https://ci.appveyor.com/api/projects/status/al68vtv83x49eu5d/branch/master?svg=true)](https://ci.appveyor.com/project/Atom/symbols-view/branch/master) | [![Dependency Status](https://david-dm.org/atom/symbols-view.svg)](https://david-dm.org/atom/symbols-view) | -| Tabs | [![macOS Build Status](https://travis-ci.org/atom/tabs.svg?branch=master)](https://travis-ci.org/atom/tabs) | [![Windows Build Status](https://ci.appveyor.com/api/projects/status/nf4hdmuk4i9xkfmb/branch/master?svg=true)](https://ci.appveyor.com/project/Atom/tabs/branch/master) | [![Dependency Status](https://david-dm.org/atom/tabs.svg)](https://david-dm.org/atom/tabs) | -| Timecop | [![macOS Build Status](https://travis-ci.org/atom/timecop.svg?branch=master)](https://travis-ci.org/atom/timecop) | [![Windows Build Status](https://ci.appveyor.com/api/projects/status/37fhichmvx90sd97/branch/master?svg=true)](https://ci.appveyor.com/project/Atom/timecop/branch/master) | [![Dependency Status](https://david-dm.org/atom/timecop.svg)](https://david-dm.org/atom/timecop) | -| Tree View | [![macOS Build Status](https://travis-ci.org/atom/tree-view.svg?branch=master)](https://travis-ci.org/atom/tree-view) | [![Windows Build Status](https://ci.appveyor.com/api/projects/status/com793ehi0hajrkd/branch/master?svg=true)](https://ci.appveyor.com/project/Atom/tree-view/branch/master) | [![Dependency Status](https://david-dm.org/atom/tree-view.svg)](https://david-dm.org/atom/tree-view) | -| Update Package Dependencies | [![macOS Build Status](https://travis-ci.org/atom/update-package-dependencies.svg?branch=master)](https://travis-ci.org/atom/update-package-dependencies) | [![Windows Build Status](https://ci.appveyor.com/api/projects/status/5xqtoc3xk1e7lt2y/branch/master?svg=true)](https://ci.appveyor.com/project/Atom/update-package-dependencies/branch/master) | [![Dependency Status](https://david-dm.org/atom/update-package-dependencies.svg)](https://david-dm.org/atom/update-package-dependencies) | -| Welcome | [![macOS Build Status](https://travis-ci.org/atom/welcome.svg?branch=master)](https://travis-ci.org/atom/welcome) | [![Windows Build Status](https://ci.appveyor.com/api/projects/status/c3ssyte35ivvnt62/branch/master?svg=true)](https://ci.appveyor.com/project/Atom/welcome/branch/master) | [![Dependency Status](https://david-dm.org/atom/welcome.svg)](https://david-dm.org/atom/welcome) | -| Whitespace | [![macOS Build Status](https://travis-ci.org/atom/whitespace.svg?branch=master)](https://travis-ci.org/atom/whitespace) | [![Windows Build Status](https://ci.appveyor.com/api/projects/status/sf8pdb3ausdk1vtb/branch/master?svg=true)](https://ci.appveyor.com/project/Atom/whitespace/branch/master) | [![Dependency Status](https://david-dm.org/atom/whitespace.svg)](https://david-dm.org/atom/whitespace) | -| Wrap Guide | [![macOS Build Status](https://travis-ci.org/atom/wrap-guide.svg?branch=master)](https://travis-ci.org/atom/wrap-guide) | [![Windows Build Status](https://ci.appveyor.com/api/projects/status/5qk1io3uar5j8hol/branch/master?svg=true)](https://ci.appveyor.com/project/Atom/wrap-guide/branch/master) | [![Dependency Status](https://david-dm.org/atom/wrap-guide.svg)](https://david-dm.org/atom/wrap-guide) | - +| [About](https://github.com/atom/about) | [![macOS Build Status](https://travis-ci.org/atom/about.svg?branch=master)](https://travis-ci.org/atom/about) | [![Windows Build Status](https://ci.appveyor.com/api/projects/status/msprea3vq47l8oce/branch/master?svg=true)](https://ci.appveyor.com/project/atom/about/branch/master) | [![Dependency Status](https://david-dm.org/atom/about.svg)](https://david-dm.org/atom/about) | +| [Archive View](https://github.com/atom/archive-view) | [![macOS Build Status](https://travis-ci.org/atom/archive-view.svg?branch=master)](https://travis-ci.org/atom/archive-view) | [![Windows Build status](https://ci.appveyor.com/api/projects/status/u3qfgaod4lhriqlj/branch/master?svg=true)](https://ci.appveyor.com/project/Atom/archive-view/branch/master) | [![Dependency Status](https://david-dm.org/atom/archive-view.svg)](https://david-dm.org/atom/archive-view) | +| [AutoComplete Atom API](https://github.com/atom/autocomplete-atom-api) | [![macOS Build Status](https://travis-ci.org/atom/autocomplete-atom-api.svg?branch=master)](https://travis-ci.org/atom/autocomplete-atom-api) | [![Windows Build Status](https://ci.appveyor.com/api/projects/status/1x3uqd9ddchpe555/branch/master?svg=true)](https://ci.appveyor.com/project/Atom/autocomplete-atom-api/branch/master) | [![Dependency Status](https://david-dm.org/atom/autocomplete-atom-api.svg)](https://david-dm.org/atom/autocomplete-atom-api) | +| [AutoComplete CSS](https://github.com/atom/autocomplete-css) | [![macOS Build Status](https://travis-ci.org/atom/autocomplete-css.svg?branch=master)](https://travis-ci.org/atom/autocomplete-css) | [![Windows Build Status](https://ci.appveyor.com/api/projects/status/k3e5uvpmpc5bkja9/branch/master?svg=true)](https://ci.appveyor.com/project/Atom/autocomplete-css/branch/master) | [![Dependency Status](https://david-dm.org/atom/autocomplete-css.svg)](https://david-dm.org/atom/autocomplete-css) | +| [AutoComplete HTML](https://github.com/atom/autocomplete-html) | [![macOS Build Status](https://travis-ci.org/atom/autocomplete-html.svg?branch=master)](https://travis-ci.org/atom/autocomplete-html) | [![Windows Build Status](https://ci.appveyor.com/api/projects/status/bsaqbg1fljpd9q1b/branch/master?svg=true)](https://ci.appveyor.com/project/Atom/autocomplete-html/branch/master) | [![Dependency Status](https://david-dm.org/atom/autocomplete-html.svg)](https://david-dm.org/atom/autocomplete-html) | +| [AutoComplete+](https://github.com/atom/autocomplete-plus) | [![macOS Build Status](https://travis-ci.org/atom/autocomplete-plus.svg?branch=master)](https://travis-ci.org/atom/autocomplete-plus) | [![Windows Build status](https://ci.appveyor.com/api/projects/status/9bpokrud2apgqsq0/branch/master?svg=true)](https://ci.appveyor.com/project/Atom/autocomplete-plus/branch/master) | [![Dependency Status](https://david-dm.org/atom/autocomplete-plus.svg)](https://david-dm.org/atom/autocomplete-plus) | +| [AutoComplete Snippets](https://github.com/atom/autocomplete-snippets) | [![macOS Build Status](https://travis-ci.org/atom/autocomplete-snippets.svg)](https://travis-ci.org/atom/autocomplete-snippets) | [![Windows Build Status](https://ci.appveyor.com/api/projects/status/72kfi83l6cw90joy/branch/master?svg=true)](https://ci.appveyor.com/project/Atom/autocomplete-snippets/branch/master) | [![Dependency Status](https://david-dm.org/atom/autocomplete-snippets.svg)](https://david-dm.org/atom/autocomplete-snippets) | +| [AutoFlow](https://github.com/atom/autoflow) | [![macOS Build Status](https://travis-ci.org/atom/autoflow.svg?branch=master)](https://travis-ci.org/atom/autoflow) | [![Windows Build Status](https://ci.appveyor.com/api/projects/status/kpmsnkbooa29x907/branch/master?svg=true)](https://ci.appveyor.com/project/Atom/autoflow/branch/master) | [![Dependency Status](https://david-dm.org/atom/autoflow.svg)](https://david-dm.org/atom/autoflow) | +| [AutoSave](https://github.com/atom/autosave) | [![macOS Build Status](https://travis-ci.org/atom/autosave.svg?branch=master)](https://travis-ci.org/atom/autosave) | [![Windows Build Status](https://ci.appveyor.com/api/projects/status/3aktr9updp722fqx/branch/master?svg=true)](https://ci.appveyor.com/project/Atom/autosave/branch/master) | [![Dependency Status](https://david-dm.org/atom/autosave.svg)](https://david-dm.org/atom/autosave) | +| [Background Tips](https://github.com/atom/background-tips) | [![macOS Build Status](https://travis-ci.org/atom/background-tips.svg?branch=master)](https://travis-ci.org/atom/background-tips) | [![Windows Build Status](https://ci.appveyor.com/api/projects/status/2utcugietl5vjc7w/branch/master?svg=true)](https://ci.appveyor.com/project/Atom/background-tips/branch/master) | [![Dependency Status](https://david-dm.org/atom/background-tips.svg)](https://david-dm.org/atom/background-tips) | +| [Bookmarks](https://github.com/atom/bookmarks) | [![macOS Build Status](https://travis-ci.org/atom/bookmarks.svg?branch=master)](https://travis-ci.org/atom/bookmarks) | [![Windows Build Status](https://ci.appveyor.com/api/projects/status/vjsf78pj4rw6ibcw/branch/master?svg=true)](https://ci.appveyor.com/project/Atom/bookmarks/branch/master) | [![Dependency Status](https://david-dm.org/atom/bookmarks.svg)](https://david-dm.org/atom/bookmarks) | +| [Bracket Matcher](https://github.com/atom/bracket-matcher) | [![macOS Build Status](https://travis-ci.org/atom/bracket-matcher.svg?branch=master)](https://travis-ci.org/atom/bracket-matcher) | [![Windows Build status](https://ci.appveyor.com/api/projects/status/rrsl2h7e0od26k54/branch/master?svg=true)](https://ci.appveyor.com/project/Atom/bracket-matcher/branch/master) | [![Dependency Status](https://david-dm.org/atom/bracket-matcher.svg)](https://david-dm.org/atom/bracket-matcher) | +| [Command Palette](https://github.com/atom/command-palette) | [![macOS Build Status](https://travis-ci.org/atom/command-palette.svg?branch=master)](https://travis-ci.org/atom/command-palette) | [![Windows Build Status](https://ci.appveyor.com/api/projects/status/jqgwetayr0enorun/branch/master?svg=true)](https://ci.appveyor.com/project/Atom/command-palette/branch/master) | [![Dependency Status](https://david-dm.org/atom/command-palette.svg)](https://david-dm.org/atom/command-palette) | +| [Deprecation Cop](https://github.com/atom/deprecation-cop) | [![macOS Build Status](https://travis-ci.org/atom/deprecation-cop.svg?branch=master)](https://travis-ci.org/atom/deprecation-cop) | [![Windows Build Status](https://ci.appveyor.com/api/projects/status/0s870q5fj3vwihjx/branch/master?svg=true)](https://ci.appveyor.com/project/Atom/deprecation-cop/branch/master) | [![Dependency Status](https://david-dm.org/atom/deprecation-cop.svg)](https://david-dm.org/atom/deprecation-cop) | +| [Dev Live Reload](https://github.com/atom/dev-live-reload) | [![macOS Build Status](https://travis-ci.org/atom/dev-live-reload.svg?branch=master)](https://travis-ci.org/atom/dev-live-reload) | [![Windows Build Status](https://ci.appveyor.com/api/projects/status/g3sd27ylba1fun1v/branch/master?svg=true)](https://ci.appveyor.com/project/Atom/dev-live-reload/branch/master) | [![Dependency Status](https://david-dm.org/atom/dev-live-reload.svg)](https://david-dm.org/atom/dev-live-reload) | +| [Encoding Selector](https://github.com/atom/encoding-selector) | [![macOS Build Status](https://travis-ci.org/atom/encoding-selector.svg?branch=master)](https://travis-ci.org/atom/encoding-selector) | [![Windows Build Status](https://ci.appveyor.com/api/projects/status/e08x6k2b68wpwxxc/branch/master?svg=true)](https://ci.appveyor.com/project/Atom/encoding-selector/branch/master) | [![Dependency Status](https://david-dm.org/atom/encoding-selector.svg)](https://david-dm.org/atom/encoding-selector) | +| [Exception Reporting](https://github.com/atom/exception-reporting) | [![macOS Build Status](https://travis-ci.org/atom/exception-reporting.svg?branch=master)](https://travis-ci.org/atom/exception-reporting) | [![Windows Build Status](https://ci.appveyor.com/api/projects/status/i0pla7qbpv7celg2/branch/master?svg=true)](https://ci.appveyor.com/project/Atom/exception-reporting/branch/master) | [![Dependency Status](https://david-dm.org/atom/exception-reporting.svg)](https://david-dm.org/atom/exception-reporting) | +| [Find and Replace](https://github.com/atom/find-and-replace) | [![macOS Build Status](https://travis-ci.org/atom/find-and-replace.svg?branch=master)](https://travis-ci.org/atom/find-and-replace) | [![Windows Build Status](https://ci.appveyor.com/api/projects/status/6w4baiiq5mw4nxky/branch/master?svg=true)](https://ci.appveyor.com/project/Atom/find-and-replace/branch/master) | [![Dependency Status](https://david-dm.org/atom/find-and-replace.svg)](https://david-dm.org/atom/find-and-replace) | +| [Fuzzy Finder](https://github.com/atom/fuzzy-finder) | [![macOS Build Status](https://travis-ci.org/atom/fuzzy-finder.svg?branch=master)](https://travis-ci.org/atom/fuzzy-finder) | [![Windows Build Status](https://ci.appveyor.com/api/projects/status/b4b2dg5n9r1wdqad/branch/master?svg=true)](https://ci.appveyor.com/project/Atom/fuzzy-finder/branch/master) | [![Dependency Status](https://david-dm.org/atom/fuzzy-finder.svg)](https://david-dm.org/atom/fuzzy-finder) | +| [Git Diff](https://github.com/atom/git-diff) | [![macOS Build Status](https://travis-ci.org/atom/git-diff.svg?branch=master)](https://travis-ci.org/atom/git-diff) | [![Windows Build Status](https://ci.appveyor.com/api/projects/status/9auj52cs0vso66nv/branch/master?svg=true)](https://ci.appveyor.com/project/Atom/git-diff/branch/master) | [![Dependency Status](https://david-dm.org/atom/git-diff.svg)](https://david-dm.org/atom/git-diff) | +| [Go to Line](https://github.com/atom/go-to-line) | [![macOS Build Status](https://travis-ci.org/atom/go-to-line.svg?branch=master)](https://travis-ci.org/atom/go-to-line) | [![Windows Build Status](https://ci.appveyor.com/api/projects/status/qf0isc8ulw4wxi0b/branch/master?svg=true)](https://ci.appveyor.com/project/Atom/go-to-line/branch/master) | [![Dependency Status](https://david-dm.org/atom/go-to-line.svg)](https://david-dm.org/atom/go-to-line) | +| [Grammar Selector](https://github.com/atom/grammar-selector) | [![macOS Build Status](https://travis-ci.org/atom/grammar-selector.svg?branch=master)](https://travis-ci.org/atom/grammar-selector) | [![Windows Build Status](https://ci.appveyor.com/api/projects/status/pg8qss03bfh4ngqm/branch/master?svg=true)](https://ci.appveyor.com/project/Atom/grammar-selector/branch/master) | [![Dependency Status](https://david-dm.org/atom/grammar-selector.svg)](https://david-dm.org/atom/grammar-selector) | +| [Image View](https://github.com/atom/image-view) | [![macOS Build Status](https://travis-ci.org/atom/image-view.svg?branch=master)](https://travis-ci.org/atom/image-view) | [![Windows Build Status](https://ci.appveyor.com/api/projects/status/notavaawrswk0g10/branch/master?svg=true)](https://ci.appveyor.com/project/Atom/image-view/branch/master) | [![Dependency Status](https://david-dm.org/atom/image-view.svg)](https://david-dm.org/atom/image-view) | +| [Incompatible Packages](https://github.com/atom/incompatible-packages) | [![macOS Build Status](https://travis-ci.org/atom/incompatible-packages.svg?branch=master)](https://travis-ci.org/atom/incompatible-packages) | [![Windows Build Status](https://ci.appveyor.com/api/projects/status/neet595s038x7w70/branch/master?svg=true)](https://ci.appveyor.com/project/Atom/incompatible-packages/branch/master) | [![Dependency Status](https://david-dm.org/atom/incompatible-packages.svg)](https://david-dm.org/atom/incompatible-packages) | +| [Keybinding Resolver](https://github.com/atom/keybinding-resolver) | [![macOS Build Status](https://travis-ci.org/atom/keybinding-resolver.svg?branch=master)](https://travis-ci.org/atom/keybinding-resolver) | [![Windows Build Status](https://ci.appveyor.com/api/projects/status/9jf31itx01hnn4nh/branch/master?svg=true)](https://ci.appveyor.com/project/Atom/keybinding-resolver/branch/master) | [![Dependency Status](https://david-dm.org/atom/keybinding-resolver.svg)](https://david-dm.org/atom/keybinding-resolver) | +| [Line Ending Selector](https://github.com/atom/line-ending-selector) | [![macOS Build Status](https://travis-ci.org/atom/line-ending-selector.svg?branch=master)](https://travis-ci.org/atom/line-ending-selector) | [![Windows Build Status](https://ci.appveyor.com/api/projects/status/b3743n9ojomlpn1g/branch/master?svg=true)](https://ci.appveyor.com/project/Atom/line-ending-selector/branch/master) | [![Dependency Status](https://david-dm.org/atom/line-ending-selector.svg)](https://david-dm.org/atom/line-ending-selector) | +| [Link](https://github.com/atom/link) | [![macOS Build Status](https://travis-ci.org/atom/link.svg?branch=master)](https://travis-ci.org/atom/link) | [![Windows Build Status](https://ci.appveyor.com/api/projects/status/1d3cb8ktd48k9vnl/branch/master?svg=true)](https://ci.appveyor.com/project/Atom/link/branch/master) | [![Dependency Status](https://david-dm.org/atom/link.svg)](https://david-dm.org/atom/link) | +| [Markdown Preview](https://github.com/atom/markdown-preview) | [![macOS Build Status](https://travis-ci.org/atom/markdown-preview.svg?branch=master)](https://travis-ci.org/atom/markdown-preview) | [![Windows Build Status](https://ci.appveyor.com/api/projects/status/bvh0evhh4v6w9b29/branch/master?svg=true)](https://ci.appveyor.com/project/Atom/markdown-preview/branch/master) | [![Dependency Status](https://david-dm.org/atom/markdown-preview.svg)](https://david-dm.org/atom/markdown-preview) | +| [Metrics](https://github.com/atom/metrics) | [![macOS Build Status](https://travis-ci.org/atom/metrics.svg?branch=master)](https://travis-ci.org/atom/metrics) | [![Windows Build Status](https://ci.appveyor.com/api/projects/status/b5doi205xl3iex04/branch/master?svg=true)](https://ci.appveyor.com/project/Atom/metrics/branch/master) | [![Dependency Status](https://david-dm.org/atom/metrics.svg)](https://david-dm.org/atom/metrics) | +| [Notifications](https://github.com/atom/notifications) | [![macOS Build Status](https://travis-ci.org/atom/notifications.svg?branch=master)](https://travis-ci.org/atom/notifications) | [![Windows Build Status](https://ci.appveyor.com/api/projects/status/ps3p8tj2okw57x0e/branch/master?svg=true)](https://ci.appveyor.com/project/Atom/notifications/branch/master) | [![Dependency Status](https://david-dm.org/atom/notifications.svg)](https://david-dm.org/atom/notifications) | +| [Open on Github](https://github.com/atom/open-on-github) | [![macOS Build Status](https://travis-ci.org/atom/open-on-github.svg?branch=master)](https://travis-ci.org/atom/open-on-github) | [![Windows Build Status](https://ci.appveyor.com/api/projects/status/ccl6na4qsna5wncr/branch/master?svg=true)](https://ci.appveyor.com/project/Atom/open-on-github/branch/master) | [![Dependency Status](https://david-dm.org/atom/open-on-github.svg)](https://david-dm.org/atom/open-on-github) | +| [Package Generator](https://github.com/atom/package-generator) | [![macOS Build Status](https://travis-ci.org/atom/package-generator.svg?branch=master)](https://travis-ci.org/atom/package-generator)| [![Windows Build Status](https://ci.appveyor.com/api/projects/status/7t1i4hdmljhigp9u/branch/master?svg=true)](https://ci.appveyor.com/project/Atom/package-generator/branch/master) | [![Dependency Status](https://david-dm.org/atom/package-generator.svg)](https://david-dm.org/atom/package-generator) | +| [Settings View](https://github.com/atom/settings-view) | [![macOS Build Status](https://travis-ci.org/atom/settings-view.svg?branch=master)](https://travis-ci.org/atom/settings-view) | [![Windows Build Status](https://ci.appveyor.com/api/projects/status/hatgxg6k2g3grafq/branch/master?svg=true)](https://ci.appveyor.com/project/Atom/settings-view/branch/master) | [![Dependency Status](https://david-dm.org/atom/settings-view.svg)](https://david-dm.org/atom/settings-view) | +| [Snippets](https://github.com/atom/snippets) | [![macOS Build Status](https://travis-ci.org/atom/snippets.svg?branch=master)](https://travis-ci.org/atom/snippets) | [![Windows Build Status](https://ci.appveyor.com/api/projects/status/8hlc0onofkgbxw53/branch/master?svg=true)](https://ci.appveyor.com/project/Atom/snippets/branch/master) | [![Dependency Status](https://david-dm.org/atom/snippets.svg)](https://david-dm.org/atom/snippets) | +| [Spell Check](https://github.com/atom/spell-check) | [![macOS Build Status](https://travis-ci.org/atom/spell-check.svg?branch=master)](https://travis-ci.org/atom/spell-check) | [![Windows Build Status](https://ci.appveyor.com/api/projects/status/1620a5reqw6kdolv/branch/master?svg=true)](https://ci.appveyor.com/project/Atom/spell-check/branch/master) | [![Dependency Status](https://david-dm.org/atom/spell-check.svg)](https://david-dm.org/atom/spell-check) | +| [Status Bar](https://github.com/atom/status-bar) | [![macOS Build Status](https://travis-ci.org/atom/status-bar.svg?branch=master)](https://travis-ci.org/atom/status-bar) | [![Windows Build Status](https://ci.appveyor.com/api/projects/status/gu8tv4h6cnpeesg2/branch/master?svg=true)](https://ci.appveyor.com/project/Atom/status-bar/branch/master) | [![Dependency Status](https://david-dm.org/atom/status-bar.svg)](https://david-dm.org/atom/status-bar) | +| [Styleguide](https://github.com/atom/styleguide) | [![macOS Build Status](https://travis-ci.org/atom/styleguide.svg?branch=master)](https://travis-ci.org/atom/styleguide) | [![Windows Build Status](https://ci.appveyor.com/api/projects/status/88dt9jxexkpindhw/branch/master?svg=true)](https://ci.appveyor.com/project/Atom/styleguide/branch/master) | [![Dependency Status](https://david-dm.org/atom/styleguide.svg)](https://david-dm.org/atom/styleguide) | +| [Symbols View](https://github.com/atom/symbols-view) | [![macOS Build Status](https://travis-ci.org/atom/symbols-view.svg?branch=master)](https://travis-ci.org/atom/symbols-view) | [![Windows Build Status](https://ci.appveyor.com/api/projects/status/al68vtv83x49eu5d/branch/master?svg=true)](https://ci.appveyor.com/project/Atom/symbols-view/branch/master) | [![Dependency Status](https://david-dm.org/atom/symbols-view.svg)](https://david-dm.org/atom/symbols-view) | +| [Tabs](https://github.com/atom/tabs) | [![macOS Build Status](https://travis-ci.org/atom/tabs.svg?branch=master)](https://travis-ci.org/atom/tabs) | [![Windows Build Status](https://ci.appveyor.com/api/projects/status/nf4hdmuk4i9xkfmb/branch/master?svg=true)](https://ci.appveyor.com/project/Atom/tabs/branch/master) | [![Dependency Status](https://david-dm.org/atom/tabs.svg)](https://david-dm.org/atom/tabs) | +| [Timecop](https://github.com/atom/timecop) | [![macOS Build Status](https://travis-ci.org/atom/timecop.svg?branch=master)](https://travis-ci.org/atom/timecop) | [![Windows Build Status](https://ci.appveyor.com/api/projects/status/37fhichmvx90sd97/branch/master?svg=true)](https://ci.appveyor.com/project/Atom/timecop/branch/master) | [![Dependency Status](https://david-dm.org/atom/timecop.svg)](https://david-dm.org/atom/timecop) | +| [Tree View](https://github.com/atom/tree-view) | [![macOS Build Status](https://travis-ci.org/atom/tree-view.svg?branch=master)](https://travis-ci.org/atom/tree-view) | [![Windows Build Status](https://ci.appveyor.com/api/projects/status/com793ehi0hajrkd/branch/master?svg=true)](https://ci.appveyor.com/project/Atom/tree-view/branch/master) | [![Dependency Status](https://david-dm.org/atom/tree-view.svg)](https://david-dm.org/atom/tree-view) | +| [Update Package Dependencies](https://github.com/atom/update-package-dependencies) | [![macOS Build Status](https://travis-ci.org/atom/update-package-dependencies.svg?branch=master)](https://travis-ci.org/atom/update-package-dependencies) | [![Windows Build Status](https://ci.appveyor.com/api/projects/status/5xqtoc3xk1e7lt2y/branch/master?svg=true)](https://ci.appveyor.com/project/Atom/update-package-dependencies/branch/master) | [![Dependency Status](https://david-dm.org/atom/update-package-dependencies.svg)](https://david-dm.org/atom/update-package-dependencies) | +| [Welcome](https://github.com/atom/welcome) | [![macOS Build Status](https://travis-ci.org/atom/welcome.svg?branch=master)](https://travis-ci.org/atom/welcome) | [![Windows Build Status](https://ci.appveyor.com/api/projects/status/c3ssyte35ivvnt62/branch/master?svg=true)](https://ci.appveyor.com/project/Atom/welcome/branch/master) | [![Dependency Status](https://david-dm.org/atom/welcome.svg)](https://david-dm.org/atom/welcome) | +| [Whitespace](https://github.com/atom/whitespace) | [![macOS Build Status](https://travis-ci.org/atom/whitespace.svg?branch=master)](https://travis-ci.org/atom/whitespace) | [![Windows Build Status](https://ci.appveyor.com/api/projects/status/sf8pdb3ausdk1vtb/branch/master?svg=true)](https://ci.appveyor.com/project/Atom/whitespace/branch/master) | [![Dependency Status](https://david-dm.org/atom/whitespace.svg)](https://david-dm.org/atom/whitespace) | +| [Wrap Guide](https://github.com/atom/wrap-guide) | [![macOS Build Status](https://travis-ci.org/atom/wrap-guide.svg?branch=master)](https://travis-ci.org/atom/wrap-guide) | [![Windows Build Status](https://ci.appveyor.com/api/projects/status/5qk1io3uar5j8hol/branch/master?svg=true)](https://ci.appveyor.com/project/Atom/wrap-guide/branch/master) | [![Dependency Status](https://david-dm.org/atom/wrap-guide.svg)](https://david-dm.org/atom/wrap-guide) | ## Libraries | Library | macOS | Windows | Dependencies | |---------|------|---------|--------------| -| Clear Cut | [![macOS Build Status](https://travis-ci.org/atom/clear-cut.svg?branch=master)](https://travis-ci.org/atom/clear-cut) | [![Windows Build Status](https://ci.appveyor.com/api/projects/status/civ54x89l06286m9/branch/master?svg=true)](https://ci.appveyor.com/project/Atom/clear-cut/branch/master) | [![Dependency Status](https://david-dm.org/atom/clear-cut.svg)](https://david-dm.org/atom/clear-cut) | -| Event Kit | [![macOS Build Status](https://travis-ci.org/atom/event-kit.svg?branch=master)](https://travis-ci.org/atom/event-kit) | [![Windows Build Status](https://ci.appveyor.com/api/projects/status/lb32q70204lpmlxo/branch/master?svg=true)](https://ci.appveyor.com/project/Atom/event-kit/branch/master) | [![Dependency Status](https://david-dm.org/atom/event-kit.svg)](https://david-dm.org/atom/event-kit) | -| Fs Plus | [![macOS Build Status](https://travis-ci.org/atom/fs-plus.svg?branch=master)](https://travis-ci.org/atom/fs-plus) | [![Windows Build Status](https://ci.appveyor.com/api/projects/status/gf2tleqp0hdek3o3/branch/master?svg=true)](https://ci.appveyor.com/project/Atom/fs-plus/branch/master) | [![Dependency Status](https://david-dm.org/atom/fs-plus.svg)](https://david-dm.org/atom/fs-plus) | -| Grim | [![macOS Build Status](https://travis-ci.org/atom/grim.svg)](https://travis-ci.org/atom/grim) | [![Windows Build Status](https://ci.appveyor.com/api/projects/status/i4m37pol77vygrvb/branch/master?svg=true)](https://ci.appveyor.com/project/Atom/grim/branch/master) | [![Dependency Status](https://david-dm.org/atom/grim.svg)](https://david-dm.org/atom/grim) | -| Jasmine Focused | [![macOS Build Status](https://travis-ci.org/atom/grim.svg)](https://travis-ci.org/atom/grim) | [![Windows Build Status](https://ci.appveyor.com/api/projects/status/af0ipfqqxn7aygoe/branch/master?svg=true)](https://ci.appveyor.com/project/Atom/jasmine-focused/branch/master) | [![Dependency Status](https://david-dm.org/atom/jasmine-focused.svg)](https://david-dm.org/atom/jasmine-focused) | -| Property Accessors | [![macOS Build Status](https://travis-ci.org/atom/property-accessors.svg?branch=master)](https://travis-ci.org/atom/property-accessors) | [![Windows Build Status](https://ci.appveyor.com/api/projects/status/ww4d10hi4v5h7kbp/branch/master?svg=true)](https://ci.appveyor.com/project/Atom/property-accessors/branch/master) | [![Dependency Status](https://david-dm.org/atom/property-accessors.svg)](https://david-dm.org/atom/property-accessors) | -| TextBuffer | [![macOS Build Status](https://travis-ci.org/atom/text-buffer.svg?branch=master)](https://travis-ci.org/atom/text-buffer) | [![Windows Build Status](https://ci.appveyor.com/api/projects/status/48xl8do1sm2thf5p/branch/master?svg=true)](https://ci.appveyor.com/project/Atom/text-buffer/branch/master) | [![Dependency Status](https://david-dm.org/atom/text-buffer.svg)](https://david-dm.org/atom/text-buffer) | -| Underscore-Plus | [![macOS Build Status](https://travis-ci.org/atom/underscore-plus.svg?branch=master)](https://travis-ci.org/atom/underscore-plus) | [![Windows Build Status](https://ci.appveyor.com/api/projects/status/c7l8009vgpaojxcd/branch/master?svg=true)](https://ci.appveyor.com/project/Atom/underscore-plus/branch/master) | [![Dependency Status](https://david-dm.org/atom/underscore-plus.svg)](https://david-dm.org/atom/underscore-plus) | - +| [Clear Cut](https://github.com/atom/clear-cut) | [![macOS Build Status](https://travis-ci.org/atom/clear-cut.svg?branch=master)](https://travis-ci.org/atom/clear-cut) | [![Windows Build Status](https://ci.appveyor.com/api/projects/status/civ54x89l06286m9/branch/master?svg=true)](https://ci.appveyor.com/project/Atom/clear-cut/branch/master) | [![Dependency Status](https://david-dm.org/atom/clear-cut.svg)](https://david-dm.org/atom/clear-cut) | +| [Event Kit](https://github.com/atom/event-kit) | [![macOS Build Status](https://travis-ci.org/atom/event-kit.svg?branch=master)](https://travis-ci.org/atom/event-kit) | [![Windows Build Status](https://ci.appveyor.com/api/projects/status/lb32q70204lpmlxo/branch/master?svg=true)](https://ci.appveyor.com/project/Atom/event-kit/branch/master) | [![Dependency Status](https://david-dm.org/atom/event-kit.svg)](https://david-dm.org/atom/event-kit) | +| [First Mate](https://github.com/atom/first-mate) | [![macOS Build Status](https://travis-ci.org/atom/first-mate.svg?branch=master)](https://travis-ci.org/atom/first-mate) | [![Windows Build Status](https://ci.appveyor.com/api/projects/status/p5im21uq22cwgb6d/branch/master?svg=true)](https://ci.appveyor.com/project/Atom/first-mate) | [![Dependency Status](https://david-dm.org/atom/first-mate/status.svg)](https://david-dm.org/atom/first-mate) | +| [Fs Plus](https://github.com/atom/fs-plus) | [![macOS Build Status](https://travis-ci.org/atom/fs-plus.svg?branch=master)](https://travis-ci.org/atom/fs-plus) | [![Windows Build Status](https://ci.appveyor.com/api/projects/status/gf2tleqp0hdek3o3/branch/master?svg=true)](https://ci.appveyor.com/project/Atom/fs-plus/branch/master) | [![Dependency Status](https://david-dm.org/atom/fs-plus.svg)](https://david-dm.org/atom/fs-plus) | +| [Grim](https://github.com/atom/grim) | [![macOS Build Status](https://travis-ci.org/atom/grim.svg)](https://travis-ci.org/atom/grim) | [![Windows Build Status](https://ci.appveyor.com/api/projects/status/i4m37pol77vygrvb/branch/master?svg=true)](https://ci.appveyor.com/project/Atom/grim/branch/master) | [![Dependency Status](https://david-dm.org/atom/grim.svg)](https://david-dm.org/atom/grim) | +| [Jasmine Focused](https://github.com/atom/jasmine-focused) | [![macOS Build Status](https://travis-ci.org/atom/grim.svg)](https://travis-ci.org/atom/grim) | [![Windows Build Status](https://ci.appveyor.com/api/projects/status/af0ipfqqxn7aygoe/branch/master?svg=true)](https://ci.appveyor.com/project/Atom/jasmine-focused/branch/master) | [![Dependency Status](https://david-dm.org/atom/jasmine-focused.svg)](https://david-dm.org/atom/jasmine-focused) | +| [Keyboard Layout](https://github.com/atom/keyboard-layout) | [![macOS Build Status](https://travis-ci.org/atom/keyboard-layout.svg?branch=master)](https://travis-ci.org/atom/keyboard-layout) | [![Windows Build status](https://ci.appveyor.com/api/projects/status/rk8wooeyh689apgd/branch/master?svg=true)](https://ci.appveyor.com/project/Atom/keyboard-layout) | [![Dependency Status](https://david-dm.org/atom/keyboard-layout/status.svg)](https://david-dm.org/atom/keyboard-layout) | +| [Oniguruma](https://github.com/atom/node-oniguruma) | [![macOS Build Status](https://travis-ci.org/atom/node-oniguruma.svg?branch=master)](https://travis-ci.org/atom/node-oniguruma) | [![Windows Build Status](https://ci.appveyor.com/api/projects/status/s9twhi451ef2butr/branch/master?svg=true)](https://ci.appveyor.com/project/Atom/node-oniguruma/branch/master) | [![Dependency Status](https://david-dm.org/atom/node-oniguruma.svg)](https://david-dm.org/atom/node-oniguruma) | +| [PathWatcher](https://github.com/atom/node-pathwatcher) | [![macOS Build Status](https://travis-ci.org/atom/node-pathwatcher.svg?branch=master)](https://travis-ci.org/atom/node-pathwatcher) | [![Windows Build Status](https://ci.appveyor.com/api/projects/status/li8dkoucdrc2ryts/branch/master?svg=true)](https://ci.appveyor.com/project/Atom/node-pathwatcher) | [![Dependency Status](https://david-dm.org/atom/node-pathwatcher/status.svg)](https://david-dm.org/atom/node-pathwatcher) | +| [Property Accessors](https://github.com/atom/property-accessors) | [![macOS Build Status](https://travis-ci.org/atom/property-accessors.svg?branch=master)](https://travis-ci.org/atom/property-accessors) | [![Windows Build Status](https://ci.appveyor.com/api/projects/status/ww4d10hi4v5h7kbp/branch/master?svg=true)](https://ci.appveyor.com/project/Atom/property-accessors/branch/master) | [![Dependency Status](https://david-dm.org/atom/property-accessors.svg)](https://david-dm.org/atom/property-accessors) | +| [TextBuffer](https://github.com/atom/text-buffer) | [![macOS Build Status](https://travis-ci.org/atom/text-buffer.svg?branch=master)](https://travis-ci.org/atom/text-buffer) | [![Windows Build Status](https://ci.appveyor.com/api/projects/status/48xl8do1sm2thf5p/branch/master?svg=true)](https://ci.appveyor.com/project/Atom/text-buffer/branch/master) | [![Dependency Status](https://david-dm.org/atom/text-buffer.svg)](https://david-dm.org/atom/text-buffer) | +| [Underscore-Plus](https://github.com/atom/underscore-plus) | [![macOS Build Status](https://travis-ci.org/atom/underscore-plus.svg?branch=master)](https://travis-ci.org/atom/underscore-plus) | [![Windows Build Status](https://ci.appveyor.com/api/projects/status/c7l8009vgpaojxcd/branch/master?svg=true)](https://ci.appveyor.com/project/Atom/underscore-plus/branch/master) | [![Dependency Status](https://david-dm.org/atom/underscore-plus.svg)](https://david-dm.org/atom/underscore-plus) | ## Tools | Language | macOS | Windows | Dependencies | |----------|------|---------|--------------| -| AtomDoc | [![macOS Build Status](https://travis-ci.org/atom/atomdoc.svg?branch=master)](https://travis-ci.org/atom/atomdoc) | [![Windows Build Status](https://ci.appveyor.com/api/projects/status/chi2bmaafr3puyq2/branch/master?svg=true)](https://ci.appveyor.com/project/Atom/atomdoc/branch/master) | [![Dependency Status](https://david-dm.org/atom/atomdoc.svg)](https://david-dm.org/atom/atomdoc) +| [AtomDoc](https://github.com/atom/atomdoc) | [![macOS Build Status](https://travis-ci.org/atom/atomdoc.svg?branch=master)](https://travis-ci.org/atom/atomdoc) | [![Windows Build Status](https://ci.appveyor.com/api/projects/status/chi2bmaafr3puyq2/branch/master?svg=true)](https://ci.appveyor.com/project/Atom/atomdoc/branch/master) | [![Dependency Status](https://david-dm.org/atom/atomdoc.svg)](https://david-dm.org/atom/atomdoc) ## Languages | Language | macOS | Windows | |----------|------|---------| -| C/C++ | [![macOS Build Status](https://travis-ci.org/atom/language-c.svg?branch=master)](https://travis-ci.org/atom/language-c) | [![Windows Build Status](https://ci.appveyor.com/api/projects/status/8oy1hmp4yrij7c32/branch/master?svg=true)](https://ci.appveyor.com/project/Atom/language-c/branch/master) | -| C# | [![macOS Build Status](https://travis-ci.org/atom/language-csharp.svg?branch=master)](https://travis-ci.org/atom/language-csharp) | [![Windows Build Status](https://ci.appveyor.com/api/projects/status/j1as3753y5t90obn/branch/master?svg=true)](https://ci.appveyor.com/project/Atom/language-csharp/branch/master) | -| Clojure | [![macOS Build Status](https://travis-ci.org/atom/language-clojure.svg?branch=master)](https://travis-ci.org/atom/language-clojure) | [![Windows Build Status](https://ci.appveyor.com/api/projects/status/6kd5fs48y5hixde6/branch/master?svg=true)](https://ci.appveyor.com/project/Atom/language-clojure/branch/master) | -| CoffeeScript | [![macOS Build Status](https://travis-ci.org/atom/language-coffee-script.svg?branch=master)](https://travis-ci.org/atom/language-coffee-script) | [![Windows Build status](https://ci.appveyor.com/api/projects/status/4j9aak7iwn2f2x7a/branch/master?svg=true)](https://ci.appveyor.com/project/Atom/language-coffee-script/branch/master) | -| CSS | [![macOS Build Status](https://travis-ci.org/atom/language-css.svg?branch=master)](https://travis-ci.org/atom/language-css) | [![Windows Build Status](https://ci.appveyor.com/api/projects/status/v8rvm88dxp73ko2y/branch/master?svg=true)](https://ci.appveyor.com/project/Atom/language-css/branch/master) | -| Git | [![macOS Build Status](https://travis-ci.org/atom/language-git.svg?branch=master)](https://travis-ci.org/atom/language-git) | [![Windows Build Status](https://ci.appveyor.com/api/projects/status/481319gyrr1feo8b/branch/master?svg=true)](https://ci.appveyor.com/project/Atom/language-git/branch/master) | -| GitHub Flavored Markdown | [![macOS Build Status](https://travis-ci.org/atom/language-gfm.svg?branch=master)](https://travis-ci.org/atom/language-gfm) | [![Windows Build Status](https://ci.appveyor.com/api/projects/status/rpub8qjyd8lt7wai/branch/master?svg=true)](https://ci.appveyor.com/project/Atom/language-gfm/branch/master) | -| Go | [![macOS Build Status](https://travis-ci.org/atom/language-go.svg?branch=master)](https://travis-ci.org/atom/language-go) | [![Windows Build Status](https://ci.appveyor.com/api/projects/status/3fxxvv05p4hv92pn/branch/master?svg=true)](https://ci.appveyor.com/project/Atom/language-go/branch/master) | -| HTML | [![macOS Build Status](https://travis-ci.org/atom/language-html.svg?branch=master)](https://travis-ci.org/atom/language-html) | [![Windows Build status](https://ci.appveyor.com/api/projects/status/t6pk6mmdgcelfg85/branch/master?svg=true)](https://ci.appveyor.com/project/Atom/language-html/branch/master) | -| Hyperlink | [![macOS Build Status](https://travis-ci.org/atom/language-hyperlink.svg?branch=master)](https://travis-ci.org/atom/language-hyperlink) | [![Windows Build Status](https://ci.appveyor.com/api/projects/status/5tgvhph394r684l8/branch/master?svg=true)](https://ci.appveyor.com/project/Atom/language-hyperlink/branch/master) | -| Java | [![macOS Build Status](https://travis-ci.org/atom/language-java.svg?branch=master)](https://travis-ci.org/atom/language-java) | [![Windows Build Status](https://ci.appveyor.com/api/projects/status/utoftje56n9u5x4h/branch/master?svg=true)](https://ci.appveyor.com/project/Atom/language-java/branch/master) | -| JavaScript | [![macOS Build Status](https://travis-ci.org/atom/language-javascript.svg?branch=master)](https://travis-ci.org/atom/language-javascript) | [![Windows Build Status](https://ci.appveyor.com/api/projects/status/ktooccwna96ssiyr/branch/master?svg=true)](https://ci.appveyor.com/project/Atom/language-javascript-dijf8/branch/master) | -| JSON | [![macOS Build Status](https://travis-ci.org/atom/language-json.svg?branch=master)](https://travis-ci.org/atom/language-json) | [![Windows Build Status](https://ci.appveyor.com/api/projects/status/5rx05vhdikk6c4cl/branch/master?svg=true)](https://ci.appveyor.com/project/Atom/language-json/branch/master) | -| Less | [![macOS Build Status](https://travis-ci.org/atom/language-less.svg?branch=master)](https://travis-ci.org/atom/language-less) | [![Windows Build Sstatus](https://ci.appveyor.com/api/projects/status/aeina4fr4b0i7yay/branch/master?svg=true)](https://ci.appveyor.com/project/Atom/language-less/branch/master) | -| Make | [![macOS Build Status](https://travis-ci.org/atom/language-make.svg?branch=master)](https://travis-ci.org/atom/language-make) | [![Windows Build Status](https://ci.appveyor.com/api/projects/status/vq1aascey21wxjh7/branch/master?svg=true)](https://ci.appveyor.com/project/Atom/language-make/branch/master) | -| Mustache | [![macOS Build Status](https://travis-ci.org/atom/language-mustache.svg?branch=master)](https://travis-ci.org/atom/language-mustache) | [![Windows Build Status](https://ci.appveyor.com/api/projects/status/mbxnxaojqp0g7ldv/branch/master?svg=true)](https://ci.appveyor.com/project/Atom/language-mustache/branch/master) | -| Objective-C | [![macOS Build Status](https://travis-ci.org/atom/language-objective-c.svg?branch=master)](https://travis-ci.org/atom/language-objective-c) | [![Windows Build Status](https://ci.appveyor.com/api/projects/status/27j8vfv5u95fjhkw/branch/master?svg=true)](https://ci.appveyor.com/project/Atom/language-objective-c/branch/master) | -| Perl | [![macOS Build Status](https://travis-ci.org/atom/language-perl.svg?branch=master)](https://travis-ci.org/atom/language-perl) | [![Windows Build Status](https://ci.appveyor.com/api/projects/status/dfs9inkkg40hchf8/branch/master?svg=true)](https://ci.appveyor.com/project/Atom/language-perl/branch/master) | -| PHP | [![macOS Build Status](https://travis-ci.org/atom/language-php.svg?branch=master)](https://travis-ci.org/atom/language-php) | [![Windows Build Status](https://ci.appveyor.com/api/projects/status/y9h45ag4b72726jy/branch/master?svg=true)](https://ci.appveyor.com/project/Atom/language-php/branch/master) | -| Python | [![macOS Build Status](https://travis-ci.org/atom/language-python.svg?branch=master)](https://travis-ci.org/atom/language-python) | [![Windows Build Status](https://ci.appveyor.com/api/projects/status/hmxrb9jttjh41es9/branch/master?svg=true)](https://ci.appveyor.com/project/Atom/language-python/branch/master) | -| Ruby | [![macOS Build Status](https://travis-ci.org/atom/language-ruby.svg?branch=master)](https://travis-ci.org/atom/language-ruby) | [![Windows Build Status](https://ci.appveyor.com/api/projects/status/71as182rm1adf2br/branch/master?svg=true)](https://ci.appveyor.com/project/Atom/language-ruby/branch/master) | -| Ruby on Rails | [![macOS Build Status](https://travis-ci.org/atom/language-ruby-on-rails.svg?branch=master)](https://travis-ci.org/atom/language-ruby-on-rails) | [![Windows Build Status](https://ci.appveyor.com/api/projects/status/5t4pa451fu5e0ghg/branch/master?svg=true)](https://ci.appveyor.com/project/Atom/language-ruby-on-rails/branch/master) | -| Sass | [![macOS Build Status](https://travis-ci.org/atom/language-sass.svg?branch=master)](https://travis-ci.org/atom/language-sass) | [![Windows Build Status](https://ci.appveyor.com/api/projects/status/g7p16vainm4iuoot/branch/master?svg=true)](https://ci.appveyor.com/project/Atom/language-sass/branch/master) | -| ShellScript | [![macOS Build Status](https://travis-ci.org/atom/language-shellscript.svg?branch=master)](https://travis-ci.org/atom/language-shellscript) | [![Windows Build Status](https://ci.appveyor.com/api/projects/status/p4um3lowgrg8y0ty/branch/master?svg=true)](https://ci.appveyor.com/project/Atom/language-shellscript/branch/master) | -| SQL | [![macOS Build Status](https://travis-ci.org/atom/language-sql.svg?branch=master)](https://travis-ci.org/atom/language-sql) | [![Windows Build Status](https://ci.appveyor.com/api/projects/status/ji31ouk5ehs4jdu1/branch/master?svg=true)](https://ci.appveyor.com/project/Atom/language-sql/branch/master) | -| TODO | [![macOS Build Status](https://travis-ci.org/atom/language-todo.svg?branch=master)](https://travis-ci.org/atom/language-todo) | [![Windows Build Status](https://ci.appveyor.com/api/projects/status/gcgb9m7h146lv6qp/branch/master?svg=true)](https://ci.appveyor.com/project/Atom/language-todo/branch/master) | -| TOML | [![macOS Build Status](https://travis-ci.org/atom/language-toml.svg?branch=master)](https://travis-ci.org/atom/language-toml) | [![Windows Build Status](https://ci.appveyor.com/api/projects/status/kohao3fjyk6xv0sc/branch/master?svg=true)](https://ci.appveyor.com/project/Atom/language-toml/branch/master) | -| XML | [![macOS Build Status](https://travis-ci.org/atom/language-xml.svg?branch=master)](https://travis-ci.org/atom/language-xml) | [![Windows Build Status](https://ci.appveyor.com/api/projects/status/m5f6rn74a6h3q5uq/branch/master?svg=true)](https://ci.appveyor.com/project/Atom/language-xml/branch/master) | -| YAML | [![macOS Build Status](https://travis-ci.org/atom/language-yaml.svg?branch=master)](https://travis-ci.org/atom/language-yaml) | [![Windows Build Status](https://ci.appveyor.com/api/projects/status/eaa4ql7kipgphc2n/branch/master?svg=true)](https://ci.appveyor.com/project/Atom/language-yaml/branch/master) | +| [C/C++](https://github.com/atom/language-c) | [![macOS Build Status](https://travis-ci.org/atom/language-c.svg?branch=master)](https://travis-ci.org/atom/language-c) | [![Windows Build Status](https://ci.appveyor.com/api/projects/status/8oy1hmp4yrij7c32/branch/master?svg=true)](https://ci.appveyor.com/project/Atom/language-c/branch/master) | +| [C#](https://github.com/atom/language-csharp) | [![macOS Build Status](https://travis-ci.org/atom/language-csharp.svg?branch=master)](https://travis-ci.org/atom/language-csharp) | [![Windows Build Status](https://ci.appveyor.com/api/projects/status/j1as3753y5t90obn/branch/master?svg=true)](https://ci.appveyor.com/project/Atom/language-csharp/branch/master) | +| [Clojure](https://github.com/atom/language-clojure) | [![macOS Build Status](https://travis-ci.org/atom/language-clojure.svg?branch=master)](https://travis-ci.org/atom/language-clojure) | [![Windows Build Status](https://ci.appveyor.com/api/projects/status/6kd5fs48y5hixde6/branch/master?svg=true)](https://ci.appveyor.com/project/Atom/language-clojure/branch/master) | +| [CoffeeScript](https://github.com/atom/language-coffee-script) | [![macOS Build Status](https://travis-ci.org/atom/language-coffee-script.svg?branch=master)](https://travis-ci.org/atom/language-coffee-script) | [![Windows Build status](https://ci.appveyor.com/api/projects/status/4j9aak7iwn2f2x7a/branch/master?svg=true)](https://ci.appveyor.com/project/Atom/language-coffee-script/branch/master) | +| [CSS](https://github.com/atom/language-css) | [![macOS Build Status](https://travis-ci.org/atom/language-css.svg?branch=master)](https://travis-ci.org/atom/language-css) | [![Windows Build Status](https://ci.appveyor.com/api/projects/status/v8rvm88dxp73ko2y/branch/master?svg=true)](https://ci.appveyor.com/project/Atom/language-css/branch/master) | +| [Git](https://github.com/atom/language-git) | [![macOS Build Status](https://travis-ci.org/atom/language-git.svg?branch=master)](https://travis-ci.org/atom/language-git) | [![Windows Build Status](https://ci.appveyor.com/api/projects/status/481319gyrr1feo8b/branch/master?svg=true)](https://ci.appveyor.com/project/Atom/language-git/branch/master) | +| [GitHub Flavored Markdown](https://github.com/atom/language-gfm) | [![macOS Build Status](https://travis-ci.org/atom/language-gfm.svg?branch=master)](https://travis-ci.org/atom/language-gfm) | [![Windows Build Status](https://ci.appveyor.com/api/projects/status/rpub8qjyd8lt7wai/branch/master?svg=true)](https://ci.appveyor.com/project/Atom/language-gfm/branch/master) | +| [Go](https://github.com/atom/language-go) | [![macOS Build Status](https://travis-ci.org/atom/language-go.svg?branch=master)](https://travis-ci.org/atom/language-go) | [![Windows Build Status](https://ci.appveyor.com/api/projects/status/3fxxvv05p4hv92pn/branch/master?svg=true)](https://ci.appveyor.com/project/Atom/language-go/branch/master) | +| [HTML](https://github.com/atom/language-html) | [![macOS Build Status](https://travis-ci.org/atom/language-html.svg?branch=master)](https://travis-ci.org/atom/language-html) | [![Windows Build status](https://ci.appveyor.com/api/projects/status/t6pk6mmdgcelfg85/branch/master?svg=true)](https://ci.appveyor.com/project/Atom/language-html/branch/master) | +| [Hyperlink](https://github.com/atom/language-hyperlink) | [![macOS Build Status](https://travis-ci.org/atom/language-hyperlink.svg?branch=master)](https://travis-ci.org/atom/language-hyperlink) | [![Windows Build Status](https://ci.appveyor.com/api/projects/status/5tgvhph394r684l8/branch/master?svg=true)](https://ci.appveyor.com/project/Atom/language-hyperlink/branch/master) | +| [Java](https://github.com/atom/language-java) | [![macOS Build Status](https://travis-ci.org/atom/language-java.svg?branch=master)](https://travis-ci.org/atom/language-java) | [![Windows Build Status](https://ci.appveyor.com/api/projects/status/utoftje56n9u5x4h/branch/master?svg=true)](https://ci.appveyor.com/project/Atom/language-java/branch/master) | +| [JavaScript](https://github.com/atom/language-javascript) | [![macOS Build Status](https://travis-ci.org/atom/language-javascript.svg?branch=master)](https://travis-ci.org/atom/language-javascript) | [![Windows Build Status](https://ci.appveyor.com/api/projects/status/ktooccwna96ssiyr/branch/master?svg=true)](https://ci.appveyor.com/project/Atom/language-javascript-dijf8/branch/master) | +| [JSON](https://github.com/atom/language-json) | [![macOS Build Status](https://travis-ci.org/atom/language-json.svg?branch=master)](https://travis-ci.org/atom/language-json) | [![Windows Build Status](https://ci.appveyor.com/api/projects/status/5rx05vhdikk6c4cl/branch/master?svg=true)](https://ci.appveyor.com/project/Atom/language-json/branch/master) | +| [Less](https://github.com/atom/language-less) | [![macOS Build Status](https://travis-ci.org/atom/language-less.svg?branch=master)](https://travis-ci.org/atom/language-less) | [![Windows Build Sstatus](https://ci.appveyor.com/api/projects/status/aeina4fr4b0i7yay/branch/master?svg=true)](https://ci.appveyor.com/project/Atom/language-less/branch/master) | +| [Make](https://github.com/atom/language-make) | [![macOS Build Status](https://travis-ci.org/atom/language-make.svg?branch=master)](https://travis-ci.org/atom/language-make) | [![Windows Build Status](https://ci.appveyor.com/api/projects/status/vq1aascey21wxjh7/branch/master?svg=true)](https://ci.appveyor.com/project/Atom/language-make/branch/master) | +| [Mustache](https://github.com/atom/language-mustache) | [![macOS Build Status](https://travis-ci.org/atom/language-mustache.svg?branch=master)](https://travis-ci.org/atom/language-mustache) | [![Windows Build Status](https://ci.appveyor.com/api/projects/status/mbxnxaojqp0g7ldv/branch/master?svg=true)](https://ci.appveyor.com/project/Atom/language-mustache/branch/master) | +| [Objective-C](https://github.com/atom/language-objective-c) | [![macOS Build Status](https://travis-ci.org/atom/language-objective-c.svg?branch=master)](https://travis-ci.org/atom/language-objective-c) | [![Windows Build Status](https://ci.appveyor.com/api/projects/status/27j8vfv5u95fjhkw/branch/master?svg=true)](https://ci.appveyor.com/project/Atom/language-objective-c/branch/master) | +| [Perl](https://github.com/atom/language-perl) | [![macOS Build Status](https://travis-ci.org/atom/language-perl.svg?branch=master)](https://travis-ci.org/atom/language-perl) | [![Windows Build Status](https://ci.appveyor.com/api/projects/status/dfs9inkkg40hchf8/branch/master?svg=true)](https://ci.appveyor.com/project/Atom/language-perl/branch/master) | +| [PHP](https://github.com/atom/language-php) | [![macOS Build Status](https://travis-ci.org/atom/language-php.svg?branch=master)](https://travis-ci.org/atom/language-php) | [![Windows Build Status](https://ci.appveyor.com/api/projects/status/y9h45ag4b72726jy/branch/master?svg=true)](https://ci.appveyor.com/project/Atom/language-php/branch/master) | +| [Python](https://github.com/atom/language-python) | [![macOS Build Status](https://travis-ci.org/atom/language-python.svg?branch=master)](https://travis-ci.org/atom/language-python) | [![Windows Build Status](https://ci.appveyor.com/api/projects/status/hmxrb9jttjh41es9/branch/master?svg=true)](https://ci.appveyor.com/project/Atom/language-python/branch/master) | +| [Ruby](https://github.com/atom/language-ruby) | [![macOS Build Status](https://travis-ci.org/atom/language-ruby.svg?branch=master)](https://travis-ci.org/atom/language-ruby) | [![Windows Build Status](https://ci.appveyor.com/api/projects/status/71as182rm1adf2br/branch/master?svg=true)](https://ci.appveyor.com/project/Atom/language-ruby/branch/master) | +| [Ruby on Rails](https://github.com/atom/language-ruby-on-rails) | [![macOS Build Status](https://travis-ci.org/atom/language-ruby-on-rails.svg?branch=master)](https://travis-ci.org/atom/language-ruby-on-rails) | [![Windows Build Status](https://ci.appveyor.com/api/projects/status/5t4pa451fu5e0ghg/branch/master?svg=true)](https://ci.appveyor.com/project/Atom/language-ruby-on-rails/branch/master) | +| [Sass](https://github.com/atom/language-sass) | [![macOS Build Status](https://travis-ci.org/atom/language-sass.svg?branch=master)](https://travis-ci.org/atom/language-sass) | [![Windows Build Status](https://ci.appveyor.com/api/projects/status/g7p16vainm4iuoot/branch/master?svg=true)](https://ci.appveyor.com/project/Atom/language-sass/branch/master) | +| [ShellScript](https://github.com/atom/language-shellscript) | [![macOS Build Status](https://travis-ci.org/atom/language-shellscript.svg?branch=master)](https://travis-ci.org/atom/language-shellscript) | [![Windows Build Status](https://ci.appveyor.com/api/projects/status/p4um3lowgrg8y0ty/branch/master?svg=true)](https://ci.appveyor.com/project/Atom/language-shellscript/branch/master) | +| [SQL](https://github.com/atom/language-sql) | [![macOS Build Status](https://travis-ci.org/atom/language-sql.svg?branch=master)](https://travis-ci.org/atom/language-sql) | [![Windows Build Status](https://ci.appveyor.com/api/projects/status/ji31ouk5ehs4jdu1/branch/master?svg=true)](https://ci.appveyor.com/project/Atom/language-sql/branch/master) | +| [TODO](https://github.com/atom/language-todo) | [![macOS Build Status](https://travis-ci.org/atom/language-todo.svg?branch=master)](https://travis-ci.org/atom/language-todo) | [![Windows Build Status](https://ci.appveyor.com/api/projects/status/gcgb9m7h146lv6qp/branch/master?svg=true)](https://ci.appveyor.com/project/Atom/language-todo/branch/master) | +| [TOML](https://github.com/atom/language-toml) | [![macOS Build Status](https://travis-ci.org/atom/language-toml.svg?branch=master)](https://travis-ci.org/atom/language-toml) | [![Windows Build Status](https://ci.appveyor.com/api/projects/status/kohao3fjyk6xv0sc/branch/master?svg=true)](https://ci.appveyor.com/project/Atom/language-toml/branch/master) | +| [XML](https://github.com/atom/language-xml) | [![macOS Build Status](https://travis-ci.org/atom/language-xml.svg?branch=master)](https://travis-ci.org/atom/language-xml) | [![Windows Build Status](https://ci.appveyor.com/api/projects/status/m5f6rn74a6h3q5uq/branch/master?svg=true)](https://ci.appveyor.com/project/Atom/language-xml/branch/master) | +| [YAML](https://github/atom/language-yaml) | [![macOS Build Status](https://travis-ci.org/atom/language-yaml.svg?branch=master)](https://travis-ci.org/atom/language-yaml) | [![Windows Build Status](https://ci.appveyor.com/api/projects/status/eaa4ql7kipgphc2n/branch/master?svg=true)](https://ci.appveyor.com/project/Atom/language-yaml/branch/master) | diff --git a/docs/build-instructions/linux.md b/docs/build-instructions/linux.md index a05bbff16..2a3e76b69 100644 --- a/docs/build-instructions/linux.md +++ b/docs/build-instructions/linux.md @@ -49,9 +49,13 @@ To also install the newly built application, use `--create-debian-package` or `- sudo update-alternatives --config gcc # choose gcc-5 from the list ``` -### Fedora / CentOS / RHEL +### Fedora -* `sudo dnf --assumeyes install make gcc gcc-c++ glibc-devel git-core libgnome-keyring-devel rpmdevtools libX11-devel libxkbfile-devel` +* `sudo dnf install make gcc gcc-c++ glibc-devel git-core libgnome-keyring-devel rpmdevtools libX11-devel libxkbfile-devel` + +### RHEL / CentOS + +* `sudo yum install make gcc gcc-c++ glibc-devel git-core libgnome-keyring-devel rpmdevtools libX11-devel libxkbfile-devel` ### Arch diff --git a/docs/build-instructions/macos.md b/docs/build-instructions/macos.md index f03d0e385..18169435f 100644 --- a/docs/build-instructions/macos.md +++ b/docs/build-instructions/macos.md @@ -26,4 +26,4 @@ To also install the newly built application, use `script/build --install`. ## Troubleshooting ### macOS build error reports in atom/atom -* Use [this search](https://github.com/atom/atom/search?q=label%3Abuild-error+label%3Aos-x&type=Issues) to get a list of reports about build errors on macOS. +* Use [this search](https://github.com/atom/atom/search?q=label%3Abuild-error+label%3Amac&type=Issues) to get a list of reports about build errors on macOS. diff --git a/docs/build-instructions/windows.md b/docs/build-instructions/windows.md index 72656f4a7..4fc51cc56 100644 --- a/docs/build-instructions/windows.md +++ b/docs/build-instructions/windows.md @@ -2,20 +2,21 @@ ## Requirements -* Node.js 4.4.x or later +* Node.js 4.4.x or later (the architecture of node available to the build system will determine whether you build 32-bit or 64-bit Atom) * Python v2.7.x - * The python.exe must be available at `%SystemDrive%\Python27\python.exe`. If it is installed elsewhere, you can create a symbolic link to the directory containing the python.exe using: `mklink /d %SystemDrive%\Python27 D:\elsewhere\Python27` + * The python.exe must be available at `%SystemDrive%\Python27\python.exe`. If it is installed elsewhere create a symbolic link to the directory containing the python.exe using: `mklink /d %SystemDrive%\Python27 D:\elsewhere\Python27` +* 7zip (7z.exe available from the command line) - for unpacking Chromedriver and creating distribution zips * Visual Studio, either: * [Visual C++ Build Tools 2015](http://landinghub.visualstudio.com/visual-cpp-build-tools) * [Visual Studio 2013 Update 5](https://www.visualstudio.com/en-us/downloads/download-visual-studio-vs) (Express Edition or better) * [Visual Studio 2015](https://www.visualstudio.com/en-us/downloads/download-visual-studio-vs) (Community Edition or better) - Whichever version you use, ensure that: + Also ensure that: * The default installation folder is chosen so the build tools can find it * If using Visual Studio make sure Visual C++ support is selected/installed * If using Visual C++ Build Tools make sure Windows 8 SDK is selected/installed * A `git` command is in your path - * Set the `GYP_MSVS_VERSION` environment variable to the Visual Studio/Build Tools version (`2013` or `2015`) e.g. ``[Environment]::SetEnvironmentVariable("GYP_MSVS_VERSION", "2015", "User")`` in PowerShell or set it in Windows advanced system settings control panel. + * Set the `GYP_MSVS_VERSION` environment variable to the Visual Studio/Build Tools version (`2013` or `2015`) e.g. ``[Environment]::SetEnvironmentVariable("GYP_MSVS_VERSION", "2015", "User")`` in PowerShell (or set it in Windows advanced system settings). ## Instructions @@ -32,8 +33,8 @@ To also install the newly built application, use `script\build --create-windows- ### `script\build` Options * `--code-sign`: signs the application with the GitHub certificate specified in `$WIN_P12KEY_URL`. -* `--compress-artifacts`: zips the generated application as `out/atom-windows.zip` (requires 7-zip). -* `--create-windows-installer`: creates an `.msi`, an `.exe` and a `.nupkg` installer in the `out/` directory. +* `--compress-artifacts`: zips the generated application as `out\atom-windows.zip` (requires [7-Zip](http://www.7-zip.org)). +* `--create-windows-installer`: creates an `.msi`, an `.exe` and two `.nupkg` packages in the `out` directory. * `--install`: installs the application in `%LOCALAPPDATA%\Atom\app-dev\`. ### Running tests @@ -53,22 +54,18 @@ When building Atom from source, the `apm` command is not added to the system pat ### Common Errors * `node is not recognized` - * If you just installed Node.js, you'll need to restart Command Prompt before the `node` command is available on your Path. + * If you just installed Node.js, you'll need to restart Command Prompt before the `node` command is available on your path. * `msbuild.exe failed with exit code: 1` - * If you installed Visual Studio, ensure you have Visual C++ support installed. Go into Add/Remove Programs, select Visual Studio, press Modify, and then check the Visual C++ box. - * If you installed Visual C++ Build Tools, ensure you have Windows 8 SDK support installed. Go into Add/Remove Programs, select Visual Studio, press Modify and then check the Windows 8 SDK box. + * If using **Visual Studio**, ensure you have the **Visual C++** component installed. Go into Add/Remove Programs, select Visual Studio, press Modify, and then check the Visual C++ box. + * If using **Visual C++ Build Tools**, ensure you have the **Windows 8 SDK** component installed. Go into Add/Remove Programs, select Visual C++ Build Tools, press Modify and then check the Windows 8 SDK box. -* `script\build` stop with no error or warning shortly after displaying the versions of node, npm and Python +* `script\build` stops with no error or warning shortly after displaying the versions of node, npm and Python * Make sure that the path where you have checked out Atom does not include a space. For example, use `C:\atom` instead of `C:\my stuff\atom`. - -* `script\build` outputs only the Node.js and Python versions before returning - * Try moving the repository to `C:\atom`. Most likely, the path is too long. - See [issue #2200](https://github.com/atom/atom/issues/2200). + * Try moving the repository to `C:\atom`. Most likely, the path is too long. See [issue #2200](https://github.com/atom/atom/issues/2200). * `error MSB4025: The project file could not be loaded. Invalid character in the given encoding.` - * This can occur because your home directory (`%USERPROFILE%`) has non-ASCII - characters in it. This is a bug in [gyp](https://code.google.com/p/gyp/) + * This can occur because your home directory (`%USERPROFILE%`) has non-ASCII characters in it. This is a bug in [gyp](https://code.google.com/p/gyp/) which is used to build native Node.js modules and there is no known workaround. * https://github.com/TooTallNate/node-gyp/issues/297 * https://code.google.com/p/gyp/issues/detail?id=393 @@ -80,14 +77,14 @@ When building Atom from source, the `apm` command is not added to the system pat * See the next item. * `error MSB8020: The build tools for Visual Studio 201? (Platform Toolset = 'v1?0') cannot be found.` - * Try setting the `GYP_MSVS_VERSION` environment variable to 2013 or 2015 depending on what version of Visual Studio/Build Tools is installed and then `script\clean` followed by `script\build` (re-open the Command Prompt if you set the variable using the GUI). + * Try setting the `GYP_MSVS_VERSION` environment variable to **2013** or **2015** depending on what version of Visual Studio/Build Tools is installed and then `script\clean` followed by `script\build` (re-open the Command Prompt if you set the variable using the GUI). * `'node-gyp' is not recognized as an internal or external command, operable program or batch file.` * Try running `npm install -g node-gyp`, and run `script\build` again. * Other `node-gyp` errors on first build attempt, even though the right Node.js and Python versions are installed. - * Do try the build command one more time, as experience shows it often works on second try in many of these cases. + * Do try the build command one more time as experience shows it often works on second try in many cases. ### Windows build error reports in atom/atom * If all fails, use [this search](https://github.com/atom/atom/search?q=label%3Abuild-error+label%3Awindows&type=Issues) to get a list of reports about build errors on Windows, and see if yours has already been reported. -* If it hasn't, please open a new issue with your Windows version, architecture (x86 or amd64), and a screenshot of your build output, including the Node.js and Python versions. +* If it hasn't, please open a new issue with your Windows version, architecture (x86 or x64), and a screenshot of your build output, including the Node.js and Python versions. diff --git a/keymaps/linux.cson b/keymaps/linux.cson index 1f78739a9..189559171 100644 --- a/keymaps/linux.cson +++ b/keymaps/linux.cson @@ -6,11 +6,11 @@ 'down': 'core:move-down' 'left': 'core:move-left' 'right': 'core:move-right' - 'ctrl-alt-r': 'window:reload' + 'ctrl-shift-f5': 'window:reload' 'ctrl-shift-i': 'window:toggle-dev-tools' - 'ctrl-alt-p': 'window:run-package-specs' + 'ctrl-shift-y': 'window:run-package-specs' 'ctrl-shift-o': 'application:open-folder' - 'ctrl-alt-o': 'application:add-project-folder' + 'ctrl-shift-a': 'application:add-project-folder' 'ctrl-shift-pageup': 'pane:move-item-left' 'ctrl-shift-pagedown': 'pane:move-item-right' 'f11': 'window:toggle-full-screen' @@ -70,12 +70,12 @@ 'ctrl-k left': 'pane:split-left-and-copy-active-item' # Atom Specific 'ctrl-k right': 'pane:split-right-and-copy-active-item' # Atom Specific 'ctrl-k ctrl-w': 'pane:close' # Atom Specific - 'ctrl-k alt-ctrl-w': 'pane:close-other-items' # Atom Specific + 'ctrl-k ctrl-alt-w': 'pane:close-other-items' # Atom Specific 'ctrl-k ctrl-p': 'window:focus-previous-pane' 'ctrl-k ctrl-n': 'window:focus-next-pane' - 'ctrl-k ctrl-up': 'window:focus-pane-above' - 'ctrl-k ctrl-down': 'window:focus-pane-below' - 'ctrl-k ctrl-left': 'window:focus-pane-on-left' + 'ctrl-k ctrl-up': 'window:focus-pane-above' + 'ctrl-k ctrl-down': 'window:focus-pane-below' + 'ctrl-k ctrl-left': 'window:focus-pane-on-left' 'ctrl-k ctrl-right': 'window:focus-pane-on-right' 'alt-1': 'pane:show-item-1' 'alt-2': 'pane:show-item-2' @@ -108,16 +108,14 @@ # Sublime Parity 'ctrl-a': 'core:select-all' - 'ctrl-alt-shift-p': 'editor:log-cursor-scope' 'ctrl-k ctrl-u': 'editor:upper-case' 'ctrl-k ctrl-l': 'editor:lower-case' 'ctrl-l': 'editor:select-line' 'atom-workspace atom-text-editor:not([mini])': # Atom specific - 'alt-ctrl-z': 'editor:checkout-head-revision' 'ctrl-<': 'editor:scroll-to-cursor' - 'alt-ctrl-f': 'editor:fold-selection' + 'ctrl-alt-shift-[': 'editor:fold-selection' # Sublime Parity 'ctrl-enter': 'editor:newline-below' diff --git a/keymaps/win32.cson b/keymaps/win32.cson index d43c124d4..b87759b1f 100644 --- a/keymaps/win32.cson +++ b/keymaps/win32.cson @@ -12,11 +12,11 @@ 'ctrl-down': 'core:move-down' 'left': 'core:move-left' 'right': 'core:move-right' - 'ctrl-alt-r': 'window:reload' + 'ctrl-shift-f5': 'window:reload' 'ctrl-shift-i': 'window:toggle-dev-tools' - 'ctrl-alt-p': 'window:run-package-specs' + 'ctrl-shift-y': 'window:run-package-specs' 'ctrl-shift-o': 'application:open-folder' - 'ctrl-alt-o': 'application:add-project-folder' + 'ctrl-shift-a': 'application:add-project-folder' 'ctrl-shift-left': 'pane:move-item-left' 'ctrl-shift-right': 'pane:move-item-right' 'f11': 'window:toggle-full-screen' @@ -75,12 +75,12 @@ 'ctrl-k left': 'pane:split-left-and-copy-active-item' # Atom Specific 'ctrl-k right': 'pane:split-right-and-copy-active-item' # Atom Specific 'ctrl-k ctrl-w': 'pane:close' # Atom Specific - 'ctrl-k alt-ctrl-w': 'pane:close-other-items' # Atom Specific + 'ctrl-k ctrl-alt-w': 'pane:close-other-items' # Atom Specific 'ctrl-k ctrl-p': 'window:focus-previous-pane' 'ctrl-k ctrl-n': 'window:focus-next-pane' - 'ctrl-k ctrl-up': 'window:focus-pane-above' - 'ctrl-k ctrl-down': 'window:focus-pane-below' - 'ctrl-k ctrl-left': 'window:focus-pane-on-left' + 'ctrl-k ctrl-up': 'window:focus-pane-above' + 'ctrl-k ctrl-down': 'window:focus-pane-below' + 'ctrl-k ctrl-left': 'window:focus-pane-on-left' 'ctrl-k ctrl-right': 'window:focus-pane-on-right' 'alt-1': 'pane:show-item-1' 'alt-2': 'pane:show-item-2' @@ -113,16 +113,14 @@ # Sublime Parity 'ctrl-a': 'core:select-all' - 'ctrl-alt-shift-p': 'editor:log-cursor-scope' 'ctrl-k ctrl-u': 'editor:upper-case' 'ctrl-k ctrl-l': 'editor:lower-case' 'ctrl-l': 'editor:select-line' 'atom-workspace atom-text-editor:not([mini])': # Atom specific - 'alt-ctrl-z': 'editor:checkout-head-revision' 'ctrl-<': 'editor:scroll-to-cursor' - 'alt-ctrl-f': 'editor:fold-selection' + 'ctrl-alt-shift-[': 'editor:fold-selection' # Sublime Parity 'ctrl-enter': 'editor:newline-below' diff --git a/menus/darwin.cson b/menus/darwin.cson index f16bfa981..055cd2405 100644 --- a/menus/darwin.cson +++ b/menus/darwin.cson @@ -108,9 +108,9 @@ submenu: [ { label: 'Fold', command: 'editor:fold-current-row' } { label: 'Unfold', command: 'editor:unfold-current-row' } + { label: 'Fold All', command: 'editor:fold-all' } { label: 'Unfold All', command: 'editor:unfold-all' } { type: 'separator' } - { label: 'Fold All', command: 'editor:fold-all' } { label: 'Fold Level 1', command: 'editor:fold-at-indent-level-1' } { label: 'Fold Level 2', command: 'editor:fold-at-indent-level-2' } { label: 'Fold Level 3', command: 'editor:fold-at-indent-level-3' } diff --git a/menus/linux.cson b/menus/linux.cson index c900d3d29..94fb90a30 100644 --- a/menus/linux.cson +++ b/menus/linux.cson @@ -81,9 +81,9 @@ submenu: [ { label: '&Fold', command: 'editor:fold-current-row' } { label: '&Unfold', command: 'editor:unfold-current-row' } + { label: 'Fol&d All', command: 'editor:fold-all' } { label: 'Unfold &All', command: 'editor:unfold-all' } { type: 'separator' } - { label: 'Fol&d All', command: 'editor:fold-all' } { label: 'Fold Level 1', command: 'editor:fold-at-indent-level-1' } { label: 'Fold Level 2', command: 'editor:fold-at-indent-level-2' } { label: 'Fold Level 3', command: 'editor:fold-at-indent-level-3' } diff --git a/menus/win32.cson b/menus/win32.cson index 7897709b7..70bb1487d 100644 --- a/menus/win32.cson +++ b/menus/win32.cson @@ -89,9 +89,9 @@ submenu: [ { label: '&Fold', command: 'editor:fold-current-row' } { label: '&Unfold', command: 'editor:unfold-current-row' } + { label: 'Fol&d All', command: 'editor:fold-all' } { label: 'Unfold &All', command: 'editor:unfold-all' } { type: 'separator' } - { label: 'Fol&d All', command: 'editor:fold-all' } { label: 'Fold Level 1', command: 'editor:fold-at-indent-level-1' } { label: 'Fold Level 2', command: 'editor:fold-at-indent-level-2' } { label: 'Fold Level 3', command: 'editor:fold-at-indent-level-3' } diff --git a/package.json b/package.json index 2564e7bdd..372e2f162 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "atom", "productName": "Atom", - "version": "1.13.0-dev", + "version": "1.14.0-dev", "description": "A hackable text editor for the 21st Century.", "main": "./src/main-process/main.js", "repository": { @@ -12,11 +12,11 @@ "url": "https://github.com/atom/atom/issues" }, "license": "MIT", - "electronVersion": "1.3.6", + "electronVersion": "1.3.13", "dependencies": { "async": "0.2.6", - "atom-keymap": "7.1.1", - "atom-space-pen-views": "^2.0.0", + "atom-keymap": "7.1.15", + "atom-select-list": "0.0.6", "atom-ui": "0.4.1", "babel-core": "5.8.38", "cached-run-in-this-context": "0.4.1", @@ -33,7 +33,7 @@ "fs-plus": "2.9.2", "fstream": "0.1.24", "fuzzaldrin": "^2.1", - "git-utils": "^4.1.2", + "git-utils": "4.1.2", "glob": "^7.1.1", "grim": "1.5.0", "jasmine-json": "~0.0", @@ -45,17 +45,18 @@ "marked": "^0.3.6", "minimatch": "^3.0.3", "mocha": "2.5.1", + "mock-spawn": "^0.2.6", "normalize-package-data": "^2.0.0", "nslog": "^3", "oniguruma": "6.1.0", - "pathwatcher": "~6.5", + "pathwatcher": "^6.7.1", "postcss": "5.2.4", "postcss-selector-parser": "2.2.1", "property-accessors": "^1.1.3", "random-words": "0.0.1", "resolve": "^1.1.6", "runas": "^3.1", - "scandal": "^2.2.1", + "scandal": "2.2.2", "scoped-property-store": "^0.17.0", "scrollbar-style": "^3.2", "season": "^5.4.1", @@ -64,7 +65,7 @@ "sinon": "1.17.4", "source-map-support": "^0.3.2", "temp": "0.8.1", - "text-buffer": "9.4.1", + "text-buffer": "9.4.3", "typescript-simple": "1.0.0", "underscore-plus": "^1.6.6", "winreg": "^1.2.1", @@ -77,88 +78,88 @@ "atom-light-ui": "0.46.0", "base16-tomorrow-dark-theme": "1.4.0", "base16-tomorrow-light-theme": "1.4.0", - "one-dark-ui": "1.8.2", - "one-light-ui": "1.8.2", + "one-dark-ui": "1.9.0", + "one-light-ui": "1.9.0", "one-dark-syntax": "1.6.0", "one-light-syntax": "1.6.0", "solarized-dark-syntax": "1.1.1", "solarized-light-syntax": "1.1.1", "about": "1.7.2", - "archive-view": "0.62.0", + "archive-view": "0.62.2", "autocomplete-atom-api": "0.10.0", "autocomplete-css": "0.14.1", "autocomplete-html": "0.7.2", - "autocomplete-plus": "2.33.1", + "autocomplete-plus": "2.34.2", "autocomplete-snippets": "1.11.0", - "autoflow": "0.27.0", + "autoflow": "0.29.0", "autosave": "0.23.2", "background-tips": "0.26.1", - "bookmarks": "0.43.2", - "bracket-matcher": "0.82.2", - "command-palette": "0.39.1", + "bookmarks": "0.43.4", + "bracket-matcher": "0.85.0", + "command-palette": "0.39.2", "deprecation-cop": "0.55.1", "dev-live-reload": "0.47.0", "encoding-selector": "0.22.0", - "exception-reporting": "0.40.0", - "find-and-replace": "0.204.1", - "fuzzy-finder": "1.4.0", + "exception-reporting": "0.40.1", + "find-and-replace": "0.204.7", + "fuzzy-finder": "1.4.1", "git-diff": "1.2.0", "go-to-line": "0.31.2", "grammar-selector": "0.48.2", "image-view": "0.60.0", "incompatible-packages": "0.26.1", "keybinding-resolver": "0.35.0", - "line-ending-selector": "0.5.0", + "line-ending-selector": "0.5.1", "link": "0.31.2", "markdown-preview": "0.159.1", - "metrics": "1.0.0", - "notifications": "0.65.1", + "metrics": "1.1.2", + "notifications": "0.65.2", "open-on-github": "1.2.1", "package-generator": "1.0.2", "settings-view": "0.244.0", - "snippets": "1.0.3", - "spell-check": "0.68.5", - "status-bar": "1.6.0", + "snippets": "1.0.4", + "spell-check": "0.69.0", + "status-bar": "1.7.0", "styleguide": "0.48.0", - "symbols-view": "0.113.1", + "symbols-view": "0.113.2", "tabs": "0.103.1", "timecop": "0.33.2", "tree-view": "0.211.1", "update-package-dependencies": "0.10.0", - "welcome": "0.35.1", + "welcome": "0.35.2", "whitespace": "0.35.0", "wrap-guide": "0.39.0", "language-c": "0.54.0", "language-clojure": "0.22.1", - "language-coffee-script": "0.48.1", - "language-csharp": "0.12.1", - "language-css": "0.40.1", + "language-coffee-script": "0.48.2", + "language-csharp": "0.13.0", + "language-css": "0.41.0", "language-gfm": "0.88.0", - "language-git": "0.15.0", + "language-git": "0.19.0", "language-go": "0.43.0", - "language-html": "0.46.1", + "language-html": "0.47.1", "language-hyperlink": "0.16.1", "language-java": "0.24.0", - "language-javascript": "0.122.0", + "language-javascript": "0.124.0", "language-json": "0.18.3", - "language-less": "0.29.6", - "language-make": "0.22.2", - "language-mustache": "0.13.0", + "language-less": "0.30.0", + "language-make": "0.22.3", + "language-mustache": "0.13.1", "language-objective-c": "0.15.1", "language-perl": "0.37.0", "language-php": "0.37.3", - "language-property-list": "0.8.0", + "language-property-list": "0.9.0", "language-python": "0.45.1", - "language-ruby": "0.70.2", + "language-ruby": "0.70.3", "language-ruby-on-rails": "0.25.1", - "language-sass": "0.57.0", - "language-shellscript": "0.23.0", + "language-sass": "0.57.1", + "language-shellscript": "0.24.0", "language-source": "0.9.0", - "language-sql": "0.25.0", + "language-sql": "0.25.1", "language-text": "0.7.1", "language-todo": "0.29.1", "language-toml": "0.18.1", - "language-xml": "0.34.12", + "language-xml": "0.34.13", "language-yaml": "0.27.1" }, "private": true, diff --git a/resources/linux/redhat/atom.spec.in b/resources/linux/redhat/atom.spec.in index 0ee120b35..ca9fa290f 100644 --- a/resources/linux/redhat/atom.spec.in +++ b/resources/linux/redhat/atom.spec.in @@ -8,6 +8,11 @@ AutoReqProv: no # Avoid libchromiumcontent.so missing dependency Prefix: <%= installDir %> Requires: lsb-core-noarch +%if 0%{?fedora} || 0%{?rhel} +Requires: libXScrnSaver +%else +Requires: libXss1 +%endif %description <%= description %> diff --git a/resources/win/apm.cmd b/resources/win/apm.cmd index 510168983..371172c43 100644 --- a/resources/win/apm.cmd +++ b/resources/win/apm.cmd @@ -1,3 +1,3 @@ @echo off -"%~dp0\..\app\apm\bin\node.exe" "%~dp0\..\app\apm\lib\cli.js" %* +"%~dp0\..\app\apm\bin\apm.cmd" %* diff --git a/resources/win/apm.sh b/resources/win/apm.sh index b50a70a82..99ccfec69 100644 --- a/resources/win/apm.sh +++ b/resources/win/apm.sh @@ -1,4 +1,3 @@ #!/bin/sh -directory=$(dirname "$0") -"$directory/../app/apm/bin/node.exe" "$directory/../app/apm/lib/cli.js" "$@" +"$(dirname "$0")/../app/apm/apm.sh" "$@" diff --git a/script/deprecated-packages.json b/script/deprecated-packages.json index 08f4d1186..12638967e 100644 --- a/script/deprecated-packages.json +++ b/script/deprecated-packages.json @@ -866,6 +866,10 @@ "hasDeprecations": true, "latestHasDeprecations": true }, + "language-nlf": { + "hasAlternative": true, + "alternative": "language-nsis" + }, "language-rspec": { "version": "<=0.2.1", "hasDeprecations": true, diff --git a/script/lib/compress-artifacts.js b/script/lib/compress-artifacts.js index 5287b64a7..54a637162 100644 --- a/script/lib/compress-artifacts.js +++ b/script/lib/compress-artifacts.js @@ -7,23 +7,7 @@ const spawnSync = require('./spawn-sync') const CONFIG = require('../config') module.exports = function (packagedAppPath) { - let appArchiveName - if (process.platform === 'darwin') { - appArchiveName = 'atom-mac.zip' - } else if (process.platform === 'win32') { - appArchiveName = 'atom-windows.zip' - } else { - let arch - if (process.arch === 'ia32') { - arch = 'i386' - } else if (process.arch === 'x64') { - arch = 'amd64' - } else { - arch = process.arch - } - appArchiveName = `atom-${arch}.tar.gz` - } - const appArchivePath = path.join(CONFIG.buildOutputPath, appArchiveName) + const appArchivePath = path.join(CONFIG.buildOutputPath, getArchiveName()) compress(packagedAppPath, appArchivePath) if (process.platform === 'darwin') { @@ -32,6 +16,22 @@ module.exports = function (packagedAppPath) { } } +function getArchiveName () { + switch (process.platform) { + case 'darwin': return 'atom-mac.zip' + case 'win32': return `atom-windows.zip` + default: return `atom-${getLinuxArchiveArch()}.tar.gz` + } +} + +function getLinuxArchiveArch () { + switch (process.arch) { + case 'ia32': return 'i386' + case 'x64' : return 'amd64' + default: return process.arch + } +} + function compress (inputDirPath, outputArchivePath) { if (fs.existsSync(outputArchivePath)) { console.log(`Deleting "${outputArchivePath}"`) diff --git a/script/lib/create-windows-installer.js b/script/lib/create-windows-installer.js index b8aa560d9..9c1657bfa 100644 --- a/script/lib/create-windows-installer.js +++ b/script/lib/create-windows-installer.js @@ -11,30 +11,36 @@ const spawnSync = require('./spawn-sync') const CONFIG = require('../config') module.exports = function (packagedAppPath, codeSign) { + const archSuffix = process.arch === 'ia32' ? '' : '-' + process.arch const options = { appDirectory: packagedAppPath, authors: 'GitHub Inc.', iconUrl: `https://raw.githubusercontent.com/atom/atom/master/resources/app-icons/${CONFIG.channel}/atom.ico`, loadingGif: path.join(CONFIG.repositoryRootPath, 'resources', 'win', 'loading.gif'), outputDirectory: CONFIG.buildOutputPath, - remoteReleases: `https://atom.io/api/updates?version=${CONFIG.appMetadata.version}`, + remoteReleases: `https://atom.io/api/updates${archSuffix}`, setupIcon: path.join(CONFIG.repositoryRootPath, 'resources', 'app-icons', CONFIG.channel, 'atom.ico') } + // Remove this once an x64 version is published or atom.io is returning blank instead of 404 for RELEASES-X64 + if (process.arch === 'x64') { + options.remoteReleases = null + } + const certPath = path.join(os.tmpdir(), 'win.p12') - const signing = codeSign && process.env.WIN_P12KEY_URL + const signing = codeSign && process.env.ATOM_WIN_CODE_SIGNING_CERT_DOWNLOAD_URL if (signing) { - downloadFileFromGithub(process.env.WIN_P12KEY_URL, certPath) + downloadFileFromGithub(process.env.ATOM_WIN_CODE_SIGNING_CERT_DOWNLOAD_URL, certPath) var signParams = [] signParams.push(`/f ${certPath}`) // Signing cert file - signParams.push(`/p ${process.env.WIN_P12KEY_PASSWORD}`) // Signing cert password + signParams.push(`/p ${process.env.ATOM_WIN_CODE_SIGNING_CERT_PASSWORD}`) // Signing cert password signParams.push('/fd sha256') // File digest algorithm signParams.push('/tr http://timestamp.digicert.com') // Time stamp server signParams.push('/td sha256') // Times stamp algorithm options.signWithParams = signParams.join(' ') } else { - console.log('Skipping code-signing. Specify the --code-sign option and provide a WIN_P12KEY_URL environment variable to perform code-signing'.gray) + console.log('Skipping code-signing. Specify the --code-sign option and provide a ATOM_WIN_CODE_SIGNING_CERT_DOWNLOAD_URL environment variable to perform code-signing'.gray) } const cleanUp = function () { diff --git a/script/lib/dependencies-fingerprint.js b/script/lib/dependencies-fingerprint.js index 650efd99b..52b5d170a 100644 --- a/script/lib/dependencies-fingerprint.js +++ b/script/lib/dependencies-fingerprint.js @@ -22,7 +22,7 @@ module.exports = { // Include the electron minor version in the fingerprint since that changing requires a re-install const electronVersion = CONFIG.appMetadata.electronVersion.replace(/\.\d+$/, '') const apmVersion = CONFIG.apmMetadata.dependencies['atom-package-manager'] - const body = electronVersion + apmVersion + process.platform + process.version + const body = electronVersion + apmVersion + process.platform + process.version + process.arch return crypto.createHash('sha1').update(body).digest('hex') } } diff --git a/script/lib/download-chromedriver.js b/script/lib/download-chromedriver.js index ec52823f9..0c74eefd7 100644 --- a/script/lib/download-chromedriver.js +++ b/script/lib/download-chromedriver.js @@ -11,26 +11,23 @@ const syncRequest = require('sync-request') const CONFIG = require('../config') module.exports = function () { - if (process.platform === 'darwin') { - // Chromedriver is only distributed with the first patch release for any given - // major and minor version of electron. - const electronVersion = semver.parse(CONFIG.appMetadata.electronVersion) - const electronVersionWithChromedriver = `${electronVersion.major}.${electronVersion.minor}.0` - const electronAssets = getElectronAssetsForVersion(electronVersionWithChromedriver) - const chromedriverAssets = electronAssets.filter(e => /chromedriver.*darwin-x64/.test(e.name)) - assert(chromedriverAssets.length === 1, 'Found more than one chrome driver asset to download!') - const chromedriverAsset = chromedriverAssets[0] + // Chromedriver is only distributed with the first patch release for any given + // major and minor version of electron. + const electronVersion = semver.parse(CONFIG.appMetadata.electronVersion) + const electronVersionWithChromedriver = `${electronVersion.major}.${electronVersion.minor}.0` + const electronAssets = getElectronAssetsForVersion(electronVersionWithChromedriver) + const chromeDriverMatch = new RegExp(`^chromedriver-v.*-${process.platform}-${process.arch}`) + const chromedriverAssets = electronAssets.filter(e => chromeDriverMatch.test(e.name)) + assert(chromedriverAssets.length === 1, 'Found more than one chrome driver asset to download!') + const chromedriverAsset = chromedriverAssets[0] - const chromedriverZipPath = path.join(CONFIG.electronDownloadPath, `electron-${electronVersionWithChromedriver}-${chromedriverAsset.name}`) - if (!fs.existsSync(chromedriverZipPath)) { - downloadFileFromGithub(chromedriverAsset.url, chromedriverZipPath) - } - - const chromedriverDirPath = path.join(CONFIG.electronDownloadPath, 'chromedriver') - unzipPath(chromedriverZipPath, chromedriverDirPath) - } else { - console.log('Skipping Chromedriver download because it is used only on macOS'.gray) + const chromedriverZipPath = path.join(CONFIG.electronDownloadPath, `electron-${electronVersionWithChromedriver}-${chromedriverAsset.name}`) + if (!fs.existsSync(chromedriverZipPath)) { + downloadFileFromGithub(chromedriverAsset.url, chromedriverZipPath) } + + const chromedriverDirPath = path.join(CONFIG.electronDownloadPath, 'chromedriver') + unzipPath(chromedriverZipPath, chromedriverDirPath) } function getElectronAssetsForVersion (version) { @@ -52,5 +49,16 @@ function unzipPath (inputPath, outputPath) { } console.log(`Unzipping "${inputPath}" to "${outputPath}"`) - spawnSync('unzip', [inputPath, '-d', outputPath]) + try { + spawnSync('unzip', [inputPath, '-d', outputPath]) + } + catch(err) { + if (err.code === 'ENOENT') { + // Unzip might not be available on Windows even though it comes with git so fall back to 7zip + spawnSync('7z', ['x', inputPath, `-o${outputPath}`]) + } + else { + throw err; + } + } } diff --git a/script/lib/install-atom-dependencies.js b/script/lib/install-atom-dependencies.js index 5a66132f7..5c395a29b 100644 --- a/script/lib/install-atom-dependencies.js +++ b/script/lib/install-atom-dependencies.js @@ -12,10 +12,6 @@ module.exports = function () { // Set our target (Electron) version so that node-pre-gyp can download the // proper binaries. installEnv.npm_config_target = CONFIG.appMetadata.electronVersion; - // Force 32-bit modules on Windows. (Ref.: https://github.com/atom/atom/issues/10450) - if (process.platform === 'win32') { - installEnv.npm_config_target_arch = 'ia32' - } childProcess.execFileSync( CONFIG.getApmBinPath(), ['--loglevel=error', 'install'], diff --git a/script/lib/package-application.js b/script/lib/package-application.js index 8c5ee7a4e..a9cd4372a 100644 --- a/script/lib/package-application.js +++ b/script/lib/package-application.js @@ -18,12 +18,7 @@ module.exports = function () { 'app-bundle-id': 'com.github.atom', 'app-copyright': `Copyright © 2014-${(new Date()).getFullYear()} GitHub, Inc. All rights reserved.`, 'app-version': CONFIG.appMetadata.version, - 'arch': (() => { - if (process.platform === 'linux') { - return process.arch - } else { - return process.platform === 'win32' ? 'ia32' : 'x64' - }})(), + 'arch': process.platform === 'darwin' ? 'x64' : process.arch, // OS X is 64-bit only 'asar': {unpack: buildAsarUnpackGlobExpression()}, 'build-version': CONFIG.appMetadata.version, 'download': {cache: CONFIG.electronDownloadPath}, @@ -174,6 +169,9 @@ function renamePackagedAppDir (packageOutputDirPath) { } else { const appName = CONFIG.channel === 'beta' ? 'Atom Beta' : 'Atom' packagedAppPath = path.join(CONFIG.buildOutputPath, appName) + if (process.platform === 'win32' && process.arch !== 'ia32') { + packagedAppPath += ` ${process.arch}` + } if (fs.existsSync(packagedAppPath)) fs.removeSync(packagedAppPath) fs.renameSync(packageOutputDirPath, packagedAppPath) } diff --git a/script/package.json b/script/package.json index 1f4cf782f..1e56f13c9 100644 --- a/script/package.json +++ b/script/package.json @@ -9,7 +9,7 @@ "csslint": "1.0.2", "donna": "1.0.13", "electron-packager": "7.3.0", - "electron-winstaller": "2.3.4", + "electron-winstaller": "2.5.0", "fs-extra": "0.30.0", "glob": "7.0.3", "joanna": "0.0.6", diff --git a/script/test b/script/test index 38568207f..2e159d09b 100755 --- a/script/test +++ b/script/test @@ -93,11 +93,15 @@ function runBenchmarkTests (callback) { cp.on('close', exitCode => { callback(null, exitCode) }) } -let testSuitesToRun -if (process.platform === 'darwin') { - testSuitesToRun = [runCoreMainProcessTests, runCoreRenderProcessTests, runBenchmarkTests].concat(packageTestSuites) -} else { - testSuitesToRun = [runCoreMainProcessTests] +let testSuitesToRun = testSuitesForPlatform(process.platform) + +function testSuitesForPlatform(platform) { + switch(platform) { + case 'darwin': return [runCoreMainProcessTests, runCoreRenderProcessTests, runBenchmarkTests].concat(packageTestSuites) + case 'win32': return (process.arch === 'x64') ? [runCoreMainProcessTests, runCoreRenderProcessTests] : [runCoreMainProcessTests] + case 'linux': return [runCoreMainProcessTests] + default: return [] + } } async.series(testSuitesToRun, function (err, exitCodes) { diff --git a/spec/atom-environment-spec.coffee b/spec/atom-environment-spec.coffee index 6715d04e2..9b9715a07 100644 --- a/spec/atom-environment-spec.coffee +++ b/spec/atom-environment-spec.coffee @@ -1,10 +1,13 @@ _ = require 'underscore-plus' path = require 'path' -temp = require 'temp' +temp = require('temp').track() AtomEnvironment = require '../src/atom-environment' StorageFolder = require '../src/storage-folder' describe "AtomEnvironment", -> + afterEach -> + temp.cleanupSync() + describe 'window sizing methods', -> describe '::getPosition and ::setPosition', -> originalPosition = null @@ -324,7 +327,7 @@ describe "AtomEnvironment", -> describe "::unloadEditorWindow()", -> it "saves the BlobStore so it can be loaded after reload", -> - configDirPath = temp.mkdirSync() + configDirPath = temp.mkdirSync('atom-spec-environment') fakeBlobStore = jasmine.createSpyObj("blob store", ["save"]) atomEnvironment = new AtomEnvironment({applicationDelegate: atom.applicationDelegate, enablePersistence: true, configDirPath, blobStore: fakeBlobStore, window, document}) @@ -336,7 +339,7 @@ describe "AtomEnvironment", -> describe "::destroy()", -> it "does not throw exceptions when unsubscribing from ipc events (regression)", -> - configDirPath = temp.mkdirSync() + configDirPath = temp.mkdirSync('atom-spec-environment') fakeDocument = { addEventListener: -> removeEventListener: -> @@ -401,6 +404,8 @@ describe "AtomEnvironment", -> subscription?.dispose() it "invokes onUpdateAvailable listeners", -> + return unless process.platform is 'darwin' # Test tied to electron autoUpdater, we use something else on Linux and Win32 + atom.listenForUpdates() updateAvailableHandler = jasmine.createSpy("update-available-handler") diff --git a/spec/atom-paths-spec.js b/spec/atom-paths-spec.js new file mode 100644 index 000000000..4b1fc7902 --- /dev/null +++ b/spec/atom-paths-spec.js @@ -0,0 +1,119 @@ +/** @babel */ + +import {it, fit, ffit, fffit, beforeEach, afterEach} from './async-spec-helpers' +import {app} from 'remote' +import atomPaths from '../src/atom-paths' +import fs from 'fs-plus' +import path from 'path' +const temp = require('temp').track() + +describe("AtomPaths", () => { + const portableAtomHomePath = path.join(atomPaths.getAppDirectory(), '.atom') + console.log(portableAtomHomePath) + + afterEach(() => { + atomPaths.setAtomHome(app.getPath('home')) + }) + + describe('SetAtomHomePath', () => { + describe('when a portable .atom folder exists', () => { + beforeEach(() => { + delete process.env.ATOM_HOME + if (!fs.existsSync(portableAtomHomePath)) + fs.mkdirSync(portableAtomHomePath) + }) + + afterEach(() => { + delete process.env.ATOM_HOME + fs.removeSync(portableAtomHomePath) + }) + + it('sets ATOM_HOME to the portable .atom folder if it has permission', () => { + atomPaths.setAtomHome(app.getPath('home')) + expect(process.env.ATOM_HOME).toEqual(portableAtomHomePath) + }) + + it('uses ATOM_HOME if no write access to portable .atom folder', () => { + if (process.platform === 'win32') return + + const readOnlyPath = temp.mkdirSync('atom-path-spec-no-write-access') + process.env.ATOM_HOME = readOnlyPath + fs.chmodSync(portableAtomHomePath, 444) + atomPaths.setAtomHome(app.getPath('home')) + expect(process.env.ATOM_HOME).toEqual(readOnlyPath) + }) + }) + + describe('when a portable folder does not exist', () => { + beforeEach(() => { + delete process.env.ATOM_HOME + fs.removeSync(portableAtomHomePath) + }) + + afterEach(() => { + delete process.env.ATOM_HOME + }) + + it('leaves ATOM_HOME unmodified if it was already set', () => { + const temporaryHome = temp.mkdirSync('atom-spec-setatomhomepath') + process.env.ATOM_HOME = temporaryHome + atomPaths.setAtomHome(app.getPath('home')) + expect(process.env.ATOM_HOME).toEqual(temporaryHome) + }) + + it('sets ATOM_HOME to a default location if not yet set', () => { + const expectedPath = path.join(app.getPath('home'), '.atom') + atomPaths.setAtomHome(app.getPath('home')) + expect(process.env.ATOM_HOME).toEqual(expectedPath) + }) + }) + }) + + describe('setUserData', () => { + let tempAtomHomePath = null + let electronUserDataPath = null + let defaultElectronUserDataPath = null + + beforeEach(() => { + defaultElectronUserDataPath = app.getPath('userData') + delete process.env.ATOM_HOME + tempAtomHomePath = temp.mkdirSync('atom-paths-specs-userdata-home') + tempAtomConfigPath = path.join(tempAtomHomePath, '.atom') + fs.mkdirSync(tempAtomConfigPath) + electronUserDataPath = path.join(tempAtomConfigPath, 'electronUserData') + atomPaths.setAtomHome(tempAtomHomePath) + }) + + afterEach(() => { + delete process.env.ATOM_HOME + fs.removeSync(electronUserDataPath) + temp.cleanupSync() + app.setPath('userData', defaultElectronUserDataPath) + }) + + describe('when an electronUserData folder exists', () => { + it('sets userData path to the folder if it has permission', () => { + fs.mkdirSync(electronUserDataPath) + atomPaths.setUserData(app) + expect(app.getPath('userData')).toEqual(electronUserDataPath) + }) + + it('leaves userData unchanged if no write access to electronUserData folder', () => { + if (process.platform === 'win32') return + + fs.mkdirSync(electronUserDataPath) + fs.chmodSync(electronUserDataPath, 444) + atomPaths.setUserData(app) + fs.chmodSync(electronUserDataPath, 666) + expect(app.getPath('userData')).toEqual(defaultElectronUserDataPath) + }) + }) + + describe('when an electronUserDataPath folder does not exist', () => { + it('leaves userData app path unchanged', () => { + atomPaths.setUserData(app) + expect(app.getPath('userData')).toEqual(defaultElectronUserDataPath) + }) + }) + }) +}) diff --git a/spec/atom-portable-spec.coffee b/spec/atom-portable-spec.coffee deleted file mode 100644 index aeb71b7c1..000000000 --- a/spec/atom-portable-spec.coffee +++ /dev/null @@ -1,67 +0,0 @@ -path = require 'path' -fs = require 'fs-plus' -AtomPortable = require '../src/main-process/atom-portable' - -portableModeCommonPlatformBehavior = (platform) -> - describe "with ATOM_HOME environment variable", -> - it "returns false", -> - expect(AtomPortable.isPortableInstall(platform, "C:\\some\\path")).toBe false - - describe "without ATOM_HOME environment variable", -> - environmentAtomHome = undefined - portableAtomHomePath = path.join(path.dirname(process.execPath), "..", ".atom") - portableAtomHomeNaturallyExists = fs.existsSync(portableAtomHomePath) - portableAtomHomeBackupPath = "#{portableAtomHomePath}.temp" - - beforeEach -> - fs.renameSync(portableAtomHomePath, portableAtomHomeBackupPath) if fs.existsSync(portableAtomHomePath) - - afterEach -> - if portableAtomHomeNaturallyExists - fs.renameSync(portableAtomHomeBackupPath, portableAtomHomePath) if not fs.existsSync(portableAtomHomePath) - else - fs.removeSync(portableAtomHomePath) if fs.existsSync(portableAtomHomePath) - fs.removeSync(portableAtomHomeBackupPath) if fs.existsSync(portableAtomHomeBackupPath) - - describe "with .atom directory sibling to exec", -> - beforeEach -> - fs.mkdirSync(portableAtomHomePath) if not fs.existsSync(portableAtomHomePath) - - describe "without .atom directory sibling to exec", -> - beforeEach -> - fs.removeSync(portableAtomHomePath) if fs.existsSync(portableAtomHomePath) - - it "returns false", -> - expect(AtomPortable.isPortableInstall(platform, environmentAtomHome)).toBe false - -describe "Set Portable Mode on #win32", -> - portableAtomHomePath = path.join(path.dirname(process.execPath), "..", ".atom") - portableAtomHomeNaturallyExists = fs.existsSync(portableAtomHomePath) - portableAtomHomeBackupPath = "#{portableAtomHomePath}.temp" - - beforeEach -> - fs.renameSync(portableAtomHomePath, portableAtomHomeBackupPath) if fs.existsSync(portableAtomHomePath) - - afterEach -> - if portableAtomHomeNaturallyExists - fs.renameSync(portableAtomHomeBackupPath, portableAtomHomePath) if not fs.existsSync(portableAtomHomePath) - else - fs.removeSync(portableAtomHomePath) if fs.existsSync(portableAtomHomePath) - fs.removeSync(portableAtomHomeBackupPath) if fs.existsSync(portableAtomHomeBackupPath) - - it "creates a portable home directory", -> - expect(fs.existsSync(portableAtomHomePath)).toBe false - - AtomPortable.setPortable(process.env.ATOM_HOME) - expect(fs.existsSync(portableAtomHomePath)).toBe true - -describe "Check for Portable Mode", -> - describe "Windows", -> - portableModeCommonPlatformBehavior "win32" - - describe "Mac", -> - it "returns false", -> - expect(AtomPortable.isPortableInstall("darwin", "darwin")).toBe false - - describe "Linux", -> - portableModeCommonPlatformBehavior "linux" diff --git a/spec/auto-update-manager-spec.js b/spec/auto-update-manager-spec.js index be3a67c84..b38e7827c 100644 --- a/spec/auto-update-manager-spec.js +++ b/spec/auto-update-manager-spec.js @@ -5,6 +5,9 @@ import {remote} from 'electron' const electronAutoUpdater = remote.require('electron').autoUpdater describe('AutoUpdateManager (renderer)', () => { + + if (process.platform !== 'darwin') return // Tests are tied to electron autoUpdater, we use something else on Linux and Win32 + let autoUpdateManager beforeEach(() => { diff --git a/spec/babel-spec.coffee b/spec/babel-spec.coffee index e95b000cb..4e7b2b395 100644 --- a/spec/babel-spec.coffee +++ b/spec/babel-spec.coffee @@ -19,6 +19,7 @@ describe "Babel transpiler support", -> afterEach -> CompileCache.setCacheDirectory(originalCacheDir) + temp.cleanupSync() describe 'when a .js file starts with /** @babel */;', -> it "transpiles it using babel", -> diff --git a/spec/command-installer-spec.coffee b/spec/command-installer-spec.coffee index 84fd77a34..a1cf194a8 100644 --- a/spec/command-installer-spec.coffee +++ b/spec/command-installer-spec.coffee @@ -1,6 +1,6 @@ path = require 'path' fs = require 'fs-plus' -temp = require 'temp' +temp = require('temp').track() CommandInstaller = require '../src/command-installer' describe "CommandInstaller on #darwin", -> @@ -20,6 +20,9 @@ describe "CommandInstaller on #darwin", -> spyOn(CommandInstaller::, 'getResourcesDirectory').andReturn(resourcesPath) spyOn(CommandInstaller::, 'getInstallDirectory').andReturn(installationPath) + afterEach -> + temp.cleanupSync() + it "shows an error dialog when installing commands interactively fails", -> appDelegate = jasmine.createSpyObj("appDelegate", ["confirm"]) installer = new CommandInstaller("2.0.2", appDelegate) diff --git a/spec/compile-cache-spec.coffee b/spec/compile-cache-spec.coffee index bec689c7d..13db6a055 100644 --- a/spec/compile-cache-spec.coffee +++ b/spec/compile-cache-spec.coffee @@ -21,8 +21,9 @@ describe 'CompileCache', -> spyOn(TypeScriptSimple::, 'compile').andReturn 'the-typescript-code' afterEach -> - CSON.setCacheDir(CompileCache.getCacheDirectory()) CompileCache.setAtomHomeDirectory(process.env.ATOM_HOME) + CSON.setCacheDir(CompileCache.getCacheDirectory()) + temp.cleanupSync() describe 'addPathToCache(filePath, atomHome)', -> describe 'when the given file is plain javascript', -> @@ -77,6 +78,8 @@ describe 'CompileCache', -> describe 'overriding Error.prepareStackTrace', -> it 'removes the override on the next tick, and always assigns the raw stack', -> + return if process.platform is 'win32' # Flakey Error.stack contents on Win32 + Error.prepareStackTrace = -> 'a-stack-trace' error = new Error("Oops") diff --git a/spec/config-spec.coffee b/spec/config-spec.coffee index acd9b112b..3134a428f 100644 --- a/spec/config-spec.coffee +++ b/spec/config-spec.coffee @@ -1,5 +1,5 @@ path = require 'path' -temp = require 'temp' +temp = require('temp').track() CSON = require 'season' fs = require 'fs-plus' @@ -9,13 +9,14 @@ describe "Config", -> beforeEach -> spyOn(atom.config, "load") spyOn(atom.config, "save") - dotAtomPath = temp.path('dot-atom-dir') + dotAtomPath = temp.path('atom-spec-config') atom.config.configDirPath = dotAtomPath atom.config.enablePersistence = true atom.config.configFilePath = path.join(atom.config.configDirPath, "atom.config.cson") afterEach -> atom.config.enablePersistence = false + fs.removeSync(dotAtomPath) describe ".get(keyPath, {scope, sources, excludeSources})", -> it "allows a key path's value to be read", -> @@ -486,8 +487,8 @@ describe "Config", -> observeHandler.reset() # clear the initial call atom.config.set('foo.bar.baz', "value 2") expect(observeHandler).toHaveBeenCalledWith("value 2") - observeHandler.reset() + observeHandler.reset() atom.config.set('foo.bar.baz', "value 1") expect(observeHandler).toHaveBeenCalledWith("value 1") advanceClock(100) # complete pending save that was requested in ::set @@ -1079,6 +1080,7 @@ describe "Config", -> describe "when the configDirPath doesn't exist", -> it "copies the contents of dot-atom to ~/.atom", -> + return if process.platform is 'win32' # Flakey test on Win32 initializationDone = false jasmine.unspy(window, "setTimeout") atom.config.initializeConfigDirectory -> diff --git a/spec/default-directory-provider-spec.coffee b/spec/default-directory-provider-spec.coffee index df4f589b5..821c278ee 100644 --- a/spec/default-directory-provider-spec.coffee +++ b/spec/default-directory-provider-spec.coffee @@ -1,20 +1,26 @@ DefaultDirectoryProvider = require '../src/default-directory-provider' path = require 'path' fs = require 'fs-plus' -temp = require 'temp' +temp = require('temp').track() describe "DefaultDirectoryProvider", -> + tmp = null + + beforeEach -> + tmp = temp.mkdirSync('atom-spec-default-dir-provider') + + afterEach -> + temp.cleanupSync() + describe ".directoryForURISync(uri)", -> it "returns a Directory with a path that matches the uri", -> provider = new DefaultDirectoryProvider() - tmp = temp.mkdirSync() directory = provider.directoryForURISync(tmp) expect(directory.getPath()).toEqual tmp it "normalizes its input before creating a Directory for it", -> provider = new DefaultDirectoryProvider() - tmp = temp.mkdirSync() nonNormalizedPath = tmp + path.sep + ".." + path.sep + path.basename(tmp) expect(tmp.includes("..")).toBe false expect(nonNormalizedPath.includes("..")).toBe true @@ -24,7 +30,6 @@ describe "DefaultDirectoryProvider", -> it "creates a Directory for its parent dir when passed a file", -> provider = new DefaultDirectoryProvider() - tmp = temp.mkdirSync() file = path.join(tmp, "example.txt") fs.writeFileSync(file, "data") @@ -40,7 +45,6 @@ describe "DefaultDirectoryProvider", -> describe ".directoryForURI(uri)", -> it "returns a Promise that resolves to a Directory with a path that matches the uri", -> provider = new DefaultDirectoryProvider() - tmp = temp.mkdirSync() waitsForPromise -> provider.directoryForURI(tmp).then (directory) -> diff --git a/spec/file-system-blob-store-spec.coffee b/spec/file-system-blob-store-spec.coffee index 5147e59ee..a2ed39014 100644 --- a/spec/file-system-blob-store-spec.coffee +++ b/spec/file-system-blob-store-spec.coffee @@ -1,4 +1,4 @@ -temp = require 'temp' +temp = require('temp').track() path = require 'path' fs = require 'fs-plus' FileSystemBlobStore = require '../src/file-system-blob-store' @@ -7,9 +7,12 @@ describe "FileSystemBlobStore", -> [storageDirectory, blobStore] = [] beforeEach -> - storageDirectory = temp.path() + storageDirectory = temp.path('atom-spec-filesystemblobstore') blobStore = FileSystemBlobStore.load(storageDirectory) + afterEach -> + fs.removeSync(storageDirectory) + it "is empty when the file doesn't exist", -> expect(blobStore.get("foo", "invalidation-key-1")).toBeUndefined() expect(blobStore.get("bar", "invalidation-key-2")).toBeUndefined() diff --git a/spec/fixtures/packages/package-with-deserializers/index.js b/spec/fixtures/packages/package-with-deserializers/index.js index b9be23854..e653c0e67 100644 --- a/spec/fixtures/packages/package-with-deserializers/index.js +++ b/spec/fixtures/packages/package-with-deserializers/index.js @@ -1,4 +1,5 @@ module.exports = { + initialize() {}, activate () {}, deserializeMethod1 (state) { diff --git a/spec/fixtures/sample.txt b/spec/fixtures/sample.txt index 3e715502b..27d91067e 100644 --- a/spec/fixtures/sample.txt +++ b/spec/fixtures/sample.txt @@ -1 +1 @@ -Some text. +Some textSome text. diff --git a/spec/git-repository-provider-spec.coffee b/spec/git-repository-provider-spec.coffee index bbbfb4b03..6c6a7b4b9 100644 --- a/spec/git-repository-provider-spec.coffee +++ b/spec/git-repository-provider-spec.coffee @@ -1,6 +1,6 @@ path = require 'path' fs = require 'fs-plus' -temp = require 'temp' +temp = require('temp').track() {Directory} = require 'pathwatcher' GitRepository = require '../src/git-repository' GitRepositoryProvider = require '../src/git-repository-provider' @@ -11,6 +11,9 @@ describe "GitRepositoryProvider", -> beforeEach -> provider = new GitRepositoryProvider(atom.project, atom.config, atom.confirm) + afterEach -> + temp.cleanupSync() + describe ".repositoryForDirectory(directory)", -> describe "when specified a Directory with a Git repository", -> it "returns a Promise that resolves to a GitRepository", -> diff --git a/spec/git-repository-spec.coffee b/spec/git-repository-spec.coffee index c9a3badb5..59e8c4c68 100644 --- a/spec/git-repository-spec.coffee +++ b/spec/git-repository-spec.coffee @@ -1,11 +1,11 @@ -temp = require 'temp' +temp = require('temp').track() GitRepository = require '../src/git-repository' fs = require 'fs-plus' path = require 'path' Project = require '../src/project' copyRepository = -> - workingDirPath = temp.mkdirSync('atom-working-dir') + workingDirPath = temp.mkdirSync('atom-spec-git') fs.copySync(path.join(__dirname, 'fixtures', 'git', 'working-dir'), workingDirPath) fs.renameSync(path.join(workingDirPath, 'git.git'), path.join(workingDirPath, '.git')) workingDirPath @@ -19,6 +19,8 @@ describe "GitRepository", -> afterEach -> repo.destroy() if repo?.repo? + try + temp.cleanupSync() # These tests sometimes lag at shutting down resources describe "@open(path)", -> it "returns null when no repository is found", -> @@ -29,10 +31,15 @@ describe "GitRepository", -> expect(-> new GitRepository(path.join(temp.dir, 'nogit.txt'))).toThrow() describe ".getPath()", -> - it "returns the repository path for a .git directory path", -> + it "returns the repository path for a .git directory path with a file", -> + return if process.platform is 'win32' #Win32TestFailures - libgit2 does not detect files in .git folders repo = new GitRepository(path.join(__dirname, 'fixtures', 'git', 'master.git', 'HEAD')) expect(repo.getPath()).toBe path.join(__dirname, 'fixtures', 'git', 'master.git') + it "returns the repository path for a .git directory path with a directory", -> + repo = new GitRepository(path.join(__dirname, 'fixtures', 'git', 'master.git', 'objects')) + expect(repo.getPath()).toBe path.join(__dirname, 'fixtures', 'git', 'master.git') + it "returns the repository path for a repository path", -> repo = new GitRepository(path.join(__dirname, 'fixtures', 'git', 'master.git')) expect(repo.getPath()).toBe path.join(__dirname, 'fixtures', 'git', 'master.git') @@ -137,6 +144,8 @@ describe "GitRepository", -> editor = atom.workspace.getActiveTextEditor() it "displays a confirmation dialog by default", -> + return if process.platform is 'win32' # Permissions issues with this test on Windows + atom.confirm.andCallFake ({buttons}) -> buttons.OK() atom.config.set('editor.confirmCheckoutHeadRevision', true) @@ -145,6 +154,7 @@ describe "GitRepository", -> expect(fs.readFileSync(filePath, 'utf8')).toBe '' it "does not display a dialog when confirmation is disabled", -> + return if process.platform is 'win32' # Flakey EPERM opening a.txt on Win32 atom.config.set('editor.confirmCheckoutHeadRevision', false) repo.checkoutHeadForEditor(editor) @@ -154,7 +164,7 @@ describe "GitRepository", -> describe ".destroy()", -> it "throws an exception when any method is called after it is called", -> - repo = new GitRepository(require.resolve('./fixtures/git/master.git/HEAD')) + repo = new GitRepository(path.join(__dirname, 'fixtures', 'git', 'master.git')) repo.destroy() expect(-> repo.getShortHead()).toThrow() diff --git a/spec/grammars-spec.coffee b/spec/grammars-spec.coffee index 7dcff8bcd..47198a124 100644 --- a/spec/grammars-spec.coffee +++ b/spec/grammars-spec.coffee @@ -1,6 +1,6 @@ path = require 'path' fs = require 'fs-plus' -temp = require 'temp' +temp = require('temp').track() GrammarRegistry = require '../src/grammar-registry' Grim = require 'grim' @@ -24,6 +24,7 @@ describe "the `grammars` global", -> afterEach -> atom.packages.deactivatePackages() atom.packages.unloadPackages() + temp.cleanupSync() describe ".selectGrammar(filePath)", -> it "always returns a grammar", -> @@ -96,6 +97,7 @@ describe "the `grammars` global", -> ) grammar1 = atom.grammars.loadGrammarSync(grammarPath1) expect(atom.grammars.selectGrammar('more.test', '')).toBe grammar1 + fs.removeSync(grammarPath1) grammarPath2 = temp.path(suffix: '.json') fs.writeFileSync grammarPath2, JSON.stringify( @@ -105,6 +107,7 @@ describe "the `grammars` global", -> ) grammar2 = atom.grammars.loadGrammarSync(grammarPath2) expect(atom.grammars.selectGrammar('more.test', '')).toBe grammar2 + fs.removeSync(grammarPath2) it "favors non-bundled packages when breaking scoring ties", -> waitsForPromise -> diff --git a/spec/gutter-container-component-spec.coffee b/spec/gutter-container-component-spec.coffee index 73a9d0f6c..c5efbaa8e 100644 --- a/spec/gutter-container-component-spec.coffee +++ b/spec/gutter-container-component-spec.coffee @@ -139,3 +139,22 @@ describe "GutterContainerComponent", -> expect(expectedCustomGutterNode1).toBe atom.views.getView(customGutter1) expectedCustomGutterNode3 = gutterContainerComponent.getDomNode().children.item(2) expect(expectedCustomGutterNode3).toBe atom.views.getView(customGutter3) + + it "reorders correctly when prepending multiple gutters at once", -> + lineNumberGutter = new Gutter(mockGutterContainer, {name: 'line-number'}) + testState = buildTestState([lineNumberGutter]) + gutterContainerComponent.updateSync(testState) + expect(gutterContainerComponent.getDomNode().children.length).toBe 1 + expectedCustomGutterNode = gutterContainerComponent.getDomNode().children.item(0) + expect(expectedCustomGutterNode).toBe atom.views.getView(lineNumberGutter) + + # Prepend two gutters at once + customGutter1 = new Gutter(mockGutterContainer, {name: 'first', priority: -200}) + customGutter2 = new Gutter(mockGutterContainer, {name: 'second', priority: -100}) + testState = buildTestState([customGutter1, customGutter2, lineNumberGutter]) + gutterContainerComponent.updateSync(testState) + expect(gutterContainerComponent.getDomNode().children.length).toBe 3 + expectedCustomGutterNode1 = gutterContainerComponent.getDomNode().children.item(0) + expect(expectedCustomGutterNode1).toBe atom.views.getView(customGutter1) + expectedCustomGutterNode2 = gutterContainerComponent.getDomNode().children.item(1) + expect(expectedCustomGutterNode2).toBe atom.views.getView(customGutter2) diff --git a/spec/integration/helpers/start-atom.coffee b/spec/integration/helpers/start-atom.coffee index 1eb610a2f..a50a148b0 100644 --- a/spec/integration/helpers/start-atom.coffee +++ b/spec/integration/helpers/start-atom.coffee @@ -16,7 +16,7 @@ ChromedriverPort = 9515 ChromedriverURLBase = "/wd/hub" ChromedriverStatusURL = "http://localhost:#{ChromedriverPort}#{ChromedriverURLBase}/status" -userDataDir = temp.mkdirSync('atom-user-data-dir') +userDataDir = null chromeDriverUp = (done) -> checkStatus = -> @@ -38,6 +38,7 @@ chromeDriverDown = (done) -> setTimeout(checkStatus, 100) buildAtomClient = (args, env) -> + userDataDir = temp.mkdirSync('atom-user-data-dir') client = webdriverio.remote( host: 'localhost' port: ChromedriverPort diff --git a/spec/integration/smoke-spec.coffee b/spec/integration/smoke-spec.coffee index 3f921c4fe..527ed1f8f 100644 --- a/spec/integration/smoke-spec.coffee +++ b/spec/integration/smoke-spec.coffee @@ -5,6 +5,8 @@ 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 -> diff --git a/spec/lines-yardstick-spec.coffee b/spec/lines-yardstick-spec.coffee index a0100f35f..64ac6b569 100644 --- a/spec/lines-yardstick-spec.coffee +++ b/spec/lines-yardstick-spec.coffee @@ -78,9 +78,10 @@ describe "LinesYardstick", -> expect(linesYardstick.pixelPositionForScreenPosition(Point(0, 0))).toEqual({left: 0, top: 0}) expect(linesYardstick.pixelPositionForScreenPosition(Point(0, 1))).toEqual({left: 7, top: 0}) expect(linesYardstick.pixelPositionForScreenPosition(Point(0, 5))).toEqual({left: 38, top: 0}) - expect(linesYardstick.pixelPositionForScreenPosition(Point(1, 6))).toEqual({left: 43, top: 14}) - expect(linesYardstick.pixelPositionForScreenPosition(Point(1, 9))).toEqual({left: 72, top: 14}) - expect(linesYardstick.pixelPositionForScreenPosition(Point(2, Infinity))).toEqual({left: 287.859375, top: 28}) + if process.platform is 'darwin' # One pixel off on left on Win32 + expect(linesYardstick.pixelPositionForScreenPosition(Point(1, 6))).toEqual({left: 43, top: 14}) + expect(linesYardstick.pixelPositionForScreenPosition(Point(1, 9))).toEqual({left: 72, top: 14}) + expect(linesYardstick.pixelPositionForScreenPosition(Point(2, Infinity))).toEqual({left: 287.859375, top: 28}) it "reuses already computed pixel positions unless it is invalidated", -> atom.styles.addStyleSheet """ @@ -133,6 +134,7 @@ describe "LinesYardstick", -> editor.setText(text) + return unless process.platform is 'darwin' # These numbers are 15 higher on win32 and always integer expect(linesYardstick.pixelPositionForScreenPosition(Point(0, 35)).left).toBe 230.90625 expect(linesYardstick.pixelPositionForScreenPosition(Point(0, 36)).left).toBe 237.5 expect(linesYardstick.pixelPositionForScreenPosition(Point(0, 37)).left).toBe 244.09375 @@ -172,8 +174,9 @@ describe "LinesYardstick", -> expect(linesYardstick.screenPositionForPixelPosition({top: 32, left: 24.3})).toEqual([2, 3]) expect(linesYardstick.screenPositionForPixelPosition({top: 46, left: 66.5})).toEqual([3, 9]) expect(linesYardstick.screenPositionForPixelPosition({top: 70, left: 99.9})).toEqual([5, 14]) - expect(linesYardstick.screenPositionForPixelPosition({top: 70, left: 224.2365234375})).toEqual([5, 29]) expect(linesYardstick.screenPositionForPixelPosition({top: 70, left: 225})).toEqual([5, 30]) + return unless process.platform is 'darwin' # Following tests are 1 pixel off on Win32 + expect(linesYardstick.screenPositionForPixelPosition({top: 70, left: 224.2365234375})).toEqual([5, 29]) expect(linesYardstick.screenPositionForPixelPosition({top: 84, left: 247.1})).toEqual([6, 33]) it "overshoots to the nearest character when text nodes are not spatially contiguous", -> diff --git a/spec/main-process/atom-application.test.js b/spec/main-process/atom-application.test.js index 22902d3d8..8af139f21 100644 --- a/spec/main-process/atom-application.test.js +++ b/spec/main-process/atom-application.test.js @@ -22,7 +22,7 @@ describe('AtomApplication', function () { originalAtomHome = process.env.ATOM_HOME process.env.ATOM_HOME = makeTempDir('atom-home') // Symlinking the compile cache into the temporary home dir makes the windows load much faster - fs.symlinkSync(path.join(originalAtomHome, 'compile-cache'), path.join(process.env.ATOM_HOME, 'compile-cache')) + fs.symlinkSync(path.join(originalAtomHome, 'compile-cache'), path.join(process.env.ATOM_HOME, 'compile-cache'), 'junction') season.writeFileSync(path.join(process.env.ATOM_HOME, 'config.cson'), { '*': { welcome: {showOnStartup: false}, @@ -309,7 +309,7 @@ describe('AtomApplication', function () { const packagePath = path.join(__dirname, '..', 'fixtures', 'packages', 'package-with-directory-provider') const packagesDirPath = path.join(process.env.ATOM_HOME, 'packages') fs.mkdirSync(packagesDirPath) - fs.symlinkSync(packagePath, path.join(packagesDirPath, 'package-with-directory-provider')) + fs.symlinkSync(packagePath, path.join(packagesDirPath, 'package-with-directory-provider'), 'junction') const atomApplication = buildAtomApplication() atomApplication.config.set('core.disabledPackages', ['fuzzy-finder']) diff --git a/spec/main-process/file-recovery-service.test.js b/spec/main-process/file-recovery-service.test.js index 19c964be7..862b7f428 100644 --- a/spec/main-process/file-recovery-service.test.js +++ b/spec/main-process/file-recovery-service.test.js @@ -2,19 +2,23 @@ import {dialog} from 'electron' import FileRecoveryService from '../../src/main-process/file-recovery-service' -import temp from 'temp' import fs from 'fs-plus' import sinon from 'sinon' import {escapeRegExp} from 'underscore-plus' +const temp = require('temp').track() describe("FileRecoveryService", () => { let recoveryService, recoveryDirectory beforeEach(() => { - recoveryDirectory = temp.mkdirSync() + recoveryDirectory = temp.mkdirSync('atom-spec-file-recovery') recoveryService = new FileRecoveryService(recoveryDirectory) }) + afterEach(() => { + temp.cleanupSync() + }) + describe("when no crash happens during a save", () => { it("creates a recovery file and deletes it after saving", () => { const mockWindow = {} @@ -28,6 +32,8 @@ describe("FileRecoveryService", () => { recoveryService.didSavePath(mockWindow, filePath) assert.equal(fs.listTreeSync(recoveryDirectory).length, 0) assert.equal(fs.readFileSync(filePath, 'utf8'), "changed") + + fs.removeSync(filePath) }) it("creates only one recovery file when many windows attempt to save the same file, deleting it when the last one finishes saving it", () => { @@ -48,6 +54,8 @@ describe("FileRecoveryService", () => { recoveryService.didSavePath(anotherMockWindow, filePath) assert.equal(fs.listTreeSync(recoveryDirectory).length, 0) assert.equal(fs.readFileSync(filePath, 'utf8'), "changed") + + fs.removeSync(filePath) }) }) @@ -64,6 +72,8 @@ describe("FileRecoveryService", () => { recoveryService.didCrashWindow(mockWindow) assert.equal(fs.listTreeSync(recoveryDirectory).length, 0) assert.equal(fs.readFileSync(filePath, 'utf8'), "some content") + + fs.removeSync(filePath) }) it("restores the created recovery file when many windows attempt to save the same file and one of them crashes", () => { @@ -94,6 +104,8 @@ describe("FileRecoveryService", () => { recoveryService.didCrashWindow(anotherMockWindow) assert.equal(fs.readFileSync(filePath, 'utf8'), "D") assert.equal(fs.listTreeSync(recoveryDirectory).length, 0) + + fs.removeSync(filePath) }) it("emits a warning when a file can't be recovered", sinon.test(function () { @@ -113,6 +125,8 @@ describe("FileRecoveryService", () => { assert.equal(logs.length, 1) assert.match(logs[0], new RegExp(escapeRegExp(filePath))) assert.match(logs[0], new RegExp(escapeRegExp(recoveryFiles[0]))) + + fs.removeSync(filePath) })) }) diff --git a/spec/menu-manager-spec.coffee b/spec/menu-manager-spec.coffee index 5de5ecf92..2db6f35a0 100644 --- a/spec/menu-manager-spec.coffee +++ b/spec/menu-manager-spec.coffee @@ -79,6 +79,7 @@ describe "MenuManager", -> runs -> expect(menu.sendToBrowserProcess.argsForCall[0][1]['b']).toBeUndefined() it "omits key bindings that could conflict with AltGraph characters on macOS", -> + Object.defineProperty process, 'platform', value: 'darwin' spyOn(menu, 'sendToBrowserProcess') menu.add [{label: "A", submenu: [ {label: "B", command: "b"}, diff --git a/spec/module-cache-spec.coffee b/spec/module-cache-spec.coffee index 4c0a549aa..1627ec776 100644 --- a/spec/module-cache-spec.coffee +++ b/spec/module-cache-spec.coffee @@ -1,13 +1,16 @@ path = require 'path' Module = require 'module' fs = require 'fs-plus' -temp = require 'temp' +temp = require('temp').track() ModuleCache = require '../src/module-cache' describe 'ModuleCache', -> beforeEach -> spyOn(Module, '_findPath').andCallThrough() + afterEach -> + temp.cleanupSync() + it 'resolves Electron module paths without hitting the filesystem', -> builtins = ModuleCache.cache.builtins expect(Object.keys(builtins).length).toBeGreaterThan 0 diff --git a/spec/package-manager-spec.coffee b/spec/package-manager-spec.coffee index 62e96f81c..c2e9e11be 100644 --- a/spec/package-manager-spec.coffee +++ b/spec/package-manager-spec.coffee @@ -1,6 +1,6 @@ path = require 'path' Package = require '../src/package' -temp = require 'temp' +temp = require('temp').track() fs = require 'fs-plus' {Disposable} = require 'atom' {buildKeydownEvent} = require '../src/keymap-extensions' @@ -17,6 +17,9 @@ describe "PackageManager", -> beforeEach -> workspaceElement = atom.views.getView(atom.workspace) + afterEach -> + temp.cleanupSync() + describe "::getApmPath()", -> it "returns the path to the apm command", -> apmPath = path.join(process.resourcesPath, "app", "apm", "bin", "apm") @@ -440,11 +443,9 @@ describe "PackageManager", -> spyOn(mainModule, 'activate').andCallThrough() spyOn(Package.prototype, 'requireMainModule').andCallThrough() - promise = atom.packages.activatePackage('package-with-activation-hooks') - it "defers requiring/activating the main module until an triggering of an activation hook occurs", -> + 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() @@ -455,6 +456,7 @@ describe "PackageManager", -> expect(Package.prototype.requireMainModule.callCount).toBe 1 it "does not double register activation hooks when deactivating and reactivating", -> + promise = atom.packages.activatePackage('package-with-activation-hooks') expect(mainModule.activate.callCount).toBe 0 atom.packages.triggerActivationHook('language-fictitious:grammar-used') atom.packages.triggerDeferredActivationHooks() @@ -489,6 +491,17 @@ describe "PackageManager", -> 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", -> + atom.packages.triggerActivationHook('language-fictitious:grammar-used') + atom.packages.triggerDeferredActivationHooks() + expect(Package.prototype.requireMainModule.callCount).toBe 0 + + waitsForPromise -> + atom.packages.activatePackage('package-with-activation-hooks') + + runs -> + expect(Package.prototype.requireMainModule.callCount).toBe 1 + describe "when the package has no main module", -> it "does not throw an exception", -> spyOn(console, "error") @@ -643,7 +656,7 @@ describe "PackageManager", -> [element, events, userKeymapPath] = [] beforeEach -> - userKeymapPath = path.join(temp.path(), "user-keymaps.cson") + userKeymapPath = path.join(temp.mkdirSync(), "user-keymaps.cson") spyOn(atom.keymaps, "getUserKeymapPath").andReturn(userKeymapPath) element = createTestElement('test-1') @@ -660,6 +673,8 @@ describe "PackageManager", -> atom.keymaps.watchSubscriptions[userKeymapPath].dispose() delete atom.keymaps.watchSubscriptions[userKeymapPath] + temp.cleanupSync() + it "doesn't override user-defined keymaps", -> fs.writeFileSync userKeymapPath, """ ".test-1": @@ -740,10 +755,6 @@ describe "PackageManager", -> two = require.resolve("./fixtures/packages/package-with-style-sheets-manifest/styles/2.less") three = require.resolve("./fixtures/packages/package-with-style-sheets-manifest/styles/3.css") - one = atom.themes.stringToId(one) - two = atom.themes.stringToId(two) - three = atom.themes.stringToId(three) - expect(atom.themes.stylesheetElementForId(one)).toBeNull() expect(atom.themes.stylesheetElementForId(two)).toBeNull() expect(atom.themes.stylesheetElementForId(three)).toBeNull() @@ -765,11 +776,6 @@ describe "PackageManager", -> three = require.resolve("./fixtures/packages/package-with-styles/styles/3.test-context.css") four = require.resolve("./fixtures/packages/package-with-styles/styles/4.css") - one = atom.themes.stringToId(one) - two = atom.themes.stringToId(two) - three = atom.themes.stringToId(three) - four = atom.themes.stringToId(four) - expect(atom.themes.stylesheetElementForId(one)).toBeNull() expect(atom.themes.stylesheetElementForId(two)).toBeNull() expect(atom.themes.stylesheetElementForId(three)).toBeNull() diff --git a/spec/package-spec.coffee b/spec/package-spec.coffee index a0e7ffa4d..8119136be 100644 --- a/spec/package-spec.coffee +++ b/spec/package-spec.coffee @@ -205,3 +205,26 @@ describe "Package", -> it "uses the package name defined in package.json", -> expect(metadata.name).toBe 'package-with-a-totally-different-name' + + describe "the initialize() hook", -> + it "gets called when the package is activated", -> + packagePath = atom.project.getDirectories()[0].resolve('packages/package-with-deserializers') + pack = buildPackage(packagePath) + pack.requireMainModule() + mainModule = pack.mainModule + spyOn(mainModule, 'initialize') + expect(mainModule.initialize).not.toHaveBeenCalled() + pack.activate() + expect(mainModule.initialize).toHaveBeenCalled() + expect(mainModule.initialize.callCount).toBe(1) + + it "gets called when a deserializer is used", -> + packagePath = atom.project.getDirectories()[0].resolve('packages/package-with-deserializers') + pack = buildPackage(packagePath) + pack.requireMainModule() + mainModule = pack.mainModule + spyOn(mainModule, 'initialize') + pack.load() + expect(mainModule.initialize).not.toHaveBeenCalled() + atom.deserializers.deserialize({deserializer: 'Deserializer1', a: 'b'}) + expect(mainModule.initialize).toHaveBeenCalled() diff --git a/spec/package-transpilation-registry-spec.js b/spec/package-transpilation-registry-spec.js index 310570c35..bf8f12475 100644 --- a/spec/package-transpilation-registry-spec.js +++ b/spec/package-transpilation-registry-spec.js @@ -44,19 +44,19 @@ describe("PackageTranspilationRegistry", () => { }) describe('when a file is contained in a path that has custom transpilation', () => { - const hitPath = '/path/to/lib/file.js' - const hitPathCoffee = '/path/to/file2.coffee' - const missPath = '/path/other/file3.js' - const hitPathMissSubdir = '/path/to/file4.js' - const hitPathMissExt = '/path/to/file5.ts' - const nodeModulesFolder = '/path/to/lib/node_modules/file6.js' - const hitNonStandardExt = '/path/to/file7.omgwhatisthis' + const hitPath = path.join('/path/to/lib/file.js') + const hitPathCoffee = path.join('/path/to/file2.coffee') + const missPath = path.join('/path/other/file3.js') + const hitPathMissSubdir =path.join('/path/to/file4.js') + const hitPathMissExt = path.join('/path/to/file5.ts') + const nodeModulesFolder = path.join('/path/to/lib/node_modules/file6.js') + const hitNonStandardExt = path.join('/path/to/file7.omgwhatisthis') const jsSpec = { glob: "lib/**/*.js", transpiler: './transpiler-js', options: { type: 'js' } } const coffeeSpec = { glob: "*.coffee", transpiler: './transpiler-coffee', options: { type: 'coffee' } } const omgSpec = { glob: "*.omgwhatisthis", transpiler: './transpiler-omg', options: { type: 'omg' } } - const expectedMeta = { name: 'my-package', path: '/path/to', meta: { some: 'metadata' } } + const expectedMeta = { name: 'my-package', path: path.join('/path/to'), meta: { some: 'metadata' } } const jsTranspiler = { transpile: (sourceCode, filePath, options) => { @@ -100,7 +100,7 @@ describe("PackageTranspilationRegistry", () => { throw new Error('bad transpiler path ' + spec.transpiler) }) - registry.addTranspilerConfigForPath('/path/to', 'my-package', { some: 'metadata' }, [ + registry.addTranspilerConfigForPath(path.join('/path/to'), 'my-package', { some: 'metadata' }, [ jsSpec, coffeeSpec, omgSpec ]) }) diff --git a/spec/pane-spec.coffee b/spec/pane-spec.coffee index d8f74db53..596b1ecea 100644 --- a/spec/pane-spec.coffee +++ b/spec/pane-spec.coffee @@ -1080,6 +1080,7 @@ describe "Pane", -> expect(eventCount).toBe 1 it "only calls terminate handler once when text is modified twice", -> + originalText = editor1.getText() editor1.insertText('Some text') advanceClock(editor1.getBuffer().stoppedChangingDelay) @@ -1091,6 +1092,10 @@ describe "Pane", -> expect(pane.getPendingItem()).toBeNull() expect(eventCount).toBe 1 + # Reset fixture back to original state + editor1.setText(originalText) + editor1.save() + it "only calls clearPendingItem if there is a pending item to clear", -> spyOn(pane, "clearPendingItem").andCallThrough() diff --git a/spec/project-spec.coffee b/spec/project-spec.coffee index 30415a059..d548255e5 100644 --- a/spec/project-spec.coffee +++ b/spec/project-spec.coffee @@ -1,4 +1,4 @@ -temp = require 'temp' +temp = require('temp').track() Project = require '../src/project' fs = require 'fs-plus' path = require 'path' @@ -12,6 +12,9 @@ describe "Project", -> # Wait for project's service consumers to be asynchronously added waits(1) + afterEach -> + temp.cleanupSync() + describe "serialization", -> deserializedProject = null @@ -51,7 +54,7 @@ describe "Project", -> it "does not deserialize buffers when their path is a directory that exists", -> - pathToOpen = path.join(temp.mkdirSync(), 'file.txt') + pathToOpen = path.join(temp.mkdirSync('atom-spec-project'), 'file.txt') waitsForPromise -> atom.workspace.open(pathToOpen) @@ -64,7 +67,8 @@ describe "Project", -> expect(deserializedProject.getBuffers().length).toBe 0 it "does not deserialize buffers when their path is inaccessible", -> - pathToOpen = path.join(temp.mkdirSync(), 'file.txt') + return if process.platform is 'win32' # chmod not supported on win32 + pathToOpen = path.join(temp.mkdirSync('atom-spec-project'), 'file.txt') fs.writeFileSync(pathToOpen, '') waitsForPromise -> @@ -151,7 +155,7 @@ describe "Project", -> expect(notification.getType()).toBe 'warning' expect(notification.getDetail()).toBe 'SomeError' expect(notification.getMessage()).toContain '`resurrect`' - expect(notification.getMessage()).toContain 'fixtures/dir/a' + expect(notification.getMessage()).toContain path.join('fixtures', 'dir', 'a') describe "when a custom repository-provider service is provided", -> [fakeRepositoryProvider, fakeRepository] = [] diff --git a/spec/squirrel-update-spec.coffee b/spec/squirrel-update-spec.coffee index 083b1f78d..4c7e796ac 100644 --- a/spec/squirrel-update-spec.coffee +++ b/spec/squirrel-update-spec.coffee @@ -1,7 +1,7 @@ {EventEmitter} = require 'events' fs = require 'fs-plus' path = require 'path' -temp = require 'temp' +temp = require('temp').track() SquirrelUpdate = require '../src/main-process/squirrel-update' Spawner = require '../src/main-process/spawner' WinShell = require '../src/main-process/win-shell' @@ -36,6 +36,9 @@ describe "Windows Squirrel Update", -> WinShell.folderContextMenu = new FakeShellOption() WinShell.folderBackgroundContextMenu = new FakeShellOption() + afterEach -> + temp.cleanupSync() + it "quits the app on all squirrel events", -> app = quit: jasmine.createSpy('quit') diff --git a/spec/style-manager-spec.js b/spec/style-manager-spec.js index 120eb1394..88baac160 100644 --- a/spec/style-manager-spec.js +++ b/spec/style-manager-spec.js @@ -1,4 +1,4 @@ -const temp = require('temp') +const temp = require('temp').track() const StyleManager = require('../src/style-manager') describe('StyleManager', () => { @@ -14,6 +14,10 @@ describe('StyleManager', () => { styleManager.onDidUpdateStyleElement((event) => { updateEvents.push(event) }) }) + afterEach(() => { + temp.cleanupSync() + }) + describe('::addStyleSheet(source, params)', () => { it('adds a style sheet based on the given source and returns a disposable allowing it to be removed', () => { const disposable = styleManager.addStyleSheet('a {color: red}') diff --git a/spec/text-editor-component-spec.js b/spec/text-editor-component-spec.js index 4478df532..3be378a34 100644 --- a/spec/text-editor-component-spec.js +++ b/spec/text-editor-component-spec.js @@ -2291,7 +2291,9 @@ describe('TextEditorComponent', function () { let position = wrapperNode.pixelPositionForBufferPosition([0, 26]) let overlay = component.getTopmostDOMNode().querySelector('atom-overlay') - expect(overlay.style.left).toBe(Math.round(position.left + gutterWidth) + 'px') + if (process.platform == 'darwin') { // Result is 359px on win32, expects 375px + expect(overlay.style.left).toBe(Math.round(position.left + gutterWidth) + 'px') + } expect(overlay.style.top).toBe(position.top + editor.getLineHeightInPixels() + 'px') editor.insertText('a') @@ -3846,6 +3848,40 @@ describe('TextEditorComponent', function () { }) }) + describe('when the mousewheel event\'s target is an SVG element inside a block decoration', function () { + it('keeps the block decoration on the DOM if it is scrolled off-screen', function () { + wrapperNode.style.height = 4.5 * lineHeightInPixels + 'px' + wrapperNode.style.width = 20 * charWidth + 'px' + editor.update({autoHeight: false}) + component.measureDimensions() + runAnimationFrames() + + const item = document.createElement('div') + const svgElement = document.createElementNS("http://www.w3.org/2000/svg", "svg") + item.appendChild(svgElement) + editor.decorateMarker( + editor.markScreenPosition([0, 0], {invalidate: "never"}), + {type: "block", item: item} + ) + + runAnimationFrames() + + let wheelEvent = new WheelEvent('mousewheel', { + wheelDeltaX: 0, + wheelDeltaY: -500 + }) + Object.defineProperty(wheelEvent, 'target', { + get: function () { + return svgElement + } + }) + componentNode.dispatchEvent(wheelEvent) + runAnimationFrames() + + expect(component.getTopmostDOMNode().contains(item)).toBe(true) + }) + }) + it('only prevents the default action of the mousewheel event if it actually lead to scrolling', function () { spyOn(WheelEvent.prototype, 'preventDefault').andCallThrough() wrapperNode.style.height = 4.5 * lineHeightInPixels + 'px' diff --git a/spec/text-editor-element-spec.coffee b/spec/text-editor-element-spec.coffee index 7ed4a106f..468adaf04 100644 --- a/spec/text-editor-element-spec.coffee +++ b/spec/text-editor-element-spec.coffee @@ -78,6 +78,19 @@ describe "TextEditorElement", -> jasmine.attachToDOM(element) expect(element.querySelectorAll('.decoration').length).toBe initialDecorationCount + it "can be re-focused using the previous `document.activeElement`", -> + editorElement = document.createElement('atom-text-editor') + jasmine.attachToDOM(editorElement) + editorElement.focus() + + activeElement = document.activeElement + + editorElement.remove() + jasmine.attachToDOM(editorElement) + activeElement.focus() + + expect(editorElement.hasFocus()).toBe(true) + describe "focus and blur handling", -> it "proxies focus/blur events to/from the hidden input", -> element = new TextEditorElement diff --git a/spec/text-editor-presenter-spec.coffee b/spec/text-editor-presenter-spec.coffee index 8af2f9abd..12aba8eee 100644 --- a/spec/text-editor-presenter-spec.coffee +++ b/spec/text-editor-presenter-spec.coffee @@ -165,23 +165,6 @@ describe "TextEditorPresenter", -> expect(stateFn(presenter).tiles[10]).toBeUndefined() expect(stateFn(presenter).tiles[12]).toBeUndefined() - it "excludes invalid tiles for screen rows to measure", -> - presenter = buildPresenter(explicitHeight: 6, scrollTop: 0, lineHeight: 1, tileSize: 2) - presenter.setScreenRowsToMeasure([20, 30]) # unexisting rows - - expect(stateFn(presenter).tiles[0]).toBeDefined() - expect(stateFn(presenter).tiles[2]).toBeDefined() - expect(stateFn(presenter).tiles[4]).toBeDefined() - expect(stateFn(presenter).tiles[6]).toBeDefined() - expect(stateFn(presenter).tiles[8]).toBeUndefined() - expect(stateFn(presenter).tiles[10]).toBeUndefined() - expect(stateFn(presenter).tiles[12]).toBeUndefined() - - presenter.setScreenRowsToMeasure([12]) - buffer.deleteRows(12, 13) - - expect(stateFn(presenter).tiles[12]).toBeUndefined() - describe "when there are block decorations", -> it "computes each tile's height and scrollTop based on block decorations' height", -> presenter = buildPresenter(explicitHeight: 120, scrollTop: 0, lineHeight: 10, tileSize: 2) @@ -2045,6 +2028,27 @@ describe "TextEditorPresenter", -> expect(stateForHighlightInTile(presenter, highlight, 0)).toBeUndefined() + it "handles highlights that extend to the left of the visible area (regression)", -> + editor.setSelectedBufferRanges([ + [[0, 2], [1, 4]], + ]) + + presenter = buildPresenter(explicitHeight: 20, scrollLeft: 0, tileSize: 2) + expectValues stateForSelectionInTile(presenter, 0, 0), { + regions: [ + {top: 0 * 10, height: 10, left: 2 * 10, right: 0 * 10}, + {top: 1 * 10, height: 10, left: 0 * 10, width: 4 * 10} + ] + } + + presenter = buildPresenter(explicitHeight: 20, scrollLeft: 20, tileSize: 2) + expectValues stateForSelectionInTile(presenter, 0, 0), { + regions: [ + {top: 0 * 10, height: 10, left: 2 * 10, right: 0 * 10}, + {top: 1 * 10, height: 10, left: 0 * 10, width: 4 * 10} + ] + } + it "updates when ::scrollTop changes", -> editor.setSelectedBufferRanges([ [[6, 2], [6, 4]], @@ -2518,13 +2522,13 @@ describe "TextEditorPresenter", -> pixelPosition: {top: 1 * 10, left: 26 * 10 + gutterWidth - scrollLeft} } - expectStateUpdate presenter, -> editor.insertText('a') + expectStateUpdate presenter, -> editor.insertText('abc', autoscroll: false) expectValues stateForOverlay(presenter, decoration), { item: item pixelPosition: {top: 1 * 10, left: windowWidth - itemWidth} } - expectStateUpdate presenter, -> editor.insertText('b') + expectStateUpdate presenter, -> editor.insertText('d', autoscroll: false) expectValues stateForOverlay(presenter, decoration), { item: item pixelPosition: {top: 1 * 10, left: windowWidth - itemWidth} @@ -2545,14 +2549,55 @@ describe "TextEditorPresenter", -> } expectStateUpdate presenter, -> - editor.insertNewline() - presenter.setScrollTop(scrollTop) # I'm fighting the editor + editor.insertNewline(autoscroll: false) expectValues stateForOverlay(presenter, decoration), { item: item pixelPosition: {top: 6 * 10 - scrollTop - itemHeight, left: gutterWidth} } + it "when avoidOverflow is false, does not move horizontally when overflowing the editor's scrollView horizontally", -> + scrollLeft = 20 + marker = editor.markBufferPosition([0, 26], invalidate: 'never') + decoration = editor.decorateMarker(marker, {type: 'overlay', item, avoidOverflow: false}) + + presenter = buildPresenter({scrollLeft, windowWidth, windowHeight, contentFrameWidth, boundingClientRect, gutterWidth}) + expectStateUpdate presenter, -> + presenter.setOverlayDimensions(decoration.id, itemWidth, itemHeight, contentMargin) + + expectValues stateForOverlay(presenter, decoration), { + item: item + pixelPosition: {top: 1 * 10, left: 26 * 10 + gutterWidth - scrollLeft} + } + + expectStateUpdate presenter, -> editor.insertText('a', autoscroll: false) + expectValues stateForOverlay(presenter, decoration), { + item: item + pixelPosition: {top: 1 * 10, left: 27 * 10 + gutterWidth - scrollLeft} + } + + it "when avoidOverflow is false, does not flip vertically when overflowing the editor's scrollView vertically", -> + scrollTop = 10 + marker = editor.markBufferPosition([5, 0], invalidate: 'never') + decoration = editor.decorateMarker(marker, {type: 'overlay', item, avoidOverflow: false}) + + presenter = buildPresenter({scrollTop, windowWidth, windowHeight, contentFrameWidth, boundingClientRect, gutterWidth}) + expectStateUpdate presenter, -> + presenter.setOverlayDimensions(decoration.id, itemWidth, itemHeight, contentMargin) + + expectValues stateForOverlay(presenter, decoration), { + item: item + pixelPosition: {top: 6 * 10 - scrollTop, left: gutterWidth} + } + + expectStateUpdate presenter, -> + editor.insertNewline(autoscroll: false) + + expectValues stateForOverlay(presenter, decoration), { + item: item + pixelPosition: {top: 7 * 10 - scrollTop, left: gutterWidth} + } + describe "when the overlay item has a margin", -> beforeEach -> itemWidth = 12 * 10 diff --git a/spec/theme-manager-spec.coffee b/spec/theme-manager-spec.coffee index 68693dddc..40a3160da 100644 --- a/spec/theme-manager-spec.coffee +++ b/spec/theme-manager-spec.coffee @@ -1,6 +1,6 @@ path = require 'path' fs = require 'fs-plus' -temp = require 'temp' +temp = require('temp').track() describe "atom.themes", -> beforeEach -> @@ -8,6 +8,7 @@ describe "atom.themes", -> afterEach -> atom.themes.deactivateThemes() + temp.cleanupSync() describe "theme getters and setters", -> beforeEach -> @@ -170,7 +171,7 @@ describe "atom.themes", -> expect(styleElementAddedHandler).toHaveBeenCalled() element = document.querySelector('head style[source-path*="css.css"]') - expect(element.getAttribute('source-path')).toEqualPath atom.themes.stringToId(cssPath) + expect(element.getAttribute('source-path')).toEqualPath cssPath expect(element.textContent).toBe fs.readFileSync(cssPath, 'utf8') # doesn't append twice @@ -189,7 +190,7 @@ describe "atom.themes", -> expect(document.querySelectorAll('head style').length).toBe lengthBefore + 1 element = document.querySelector('head style[source-path*="sample.less"]') - expect(element.getAttribute('source-path')).toEqualPath atom.themes.stringToId(lessPath) + expect(element.getAttribute('source-path')).toEqualPath lessPath expect(element.textContent).toBe """ #header { color: #4d926f; @@ -208,9 +209,9 @@ describe "atom.themes", -> it "supports requiring css and less stylesheets without an explicit extension", -> atom.themes.requireStylesheet path.join(__dirname, 'fixtures', 'css') - expect(document.querySelector('head style[source-path*="css.css"]').getAttribute('source-path')).toEqualPath atom.themes.stringToId(atom.project.getDirectories()[0]?.resolve('css.css')) + expect(document.querySelector('head style[source-path*="css.css"]').getAttribute('source-path')).toEqualPath atom.project.getDirectories()[0]?.resolve('css.css') atom.themes.requireStylesheet path.join(__dirname, 'fixtures', 'sample') - expect(document.querySelector('head style[source-path*="sample.less"]').getAttribute('source-path')).toEqualPath atom.themes.stringToId(atom.project.getDirectories()[0]?.resolve('sample.less')) + expect(document.querySelector('head style[source-path*="sample.less"]').getAttribute('source-path')).toEqualPath atom.project.getDirectories()[0]?.resolve('sample.less') document.querySelector('head style[source-path*="css.css"]').remove() document.querySelector('head style[source-path*="sample.less"]').remove() diff --git a/spec/update-process-env-spec.js b/spec/update-process-env-spec.js index 8c9db2b16..f730ae632 100644 --- a/spec/update-process-env-spec.js +++ b/spec/update-process-env-spec.js @@ -1,28 +1,38 @@ /** @babel */ /* eslint-env jasmine */ +import {it, fit, ffit, fffit, beforeEach, afterEach} from './async-spec-helpers' import path from 'path' -import temp from 'temp' -import child_process from 'child_process' +import childProcess from 'child_process' import {updateProcessEnv, shouldGetEnvFromShell} from '../src/update-process-env' import dedent from 'dedent' +import {EventEmitter} from 'events' +import mockSpawn from 'mock-spawn' +const temp = require('temp').track() describe('updateProcessEnv(launchEnv)', function () { - let originalProcessEnv, originalProcessPlatform + let originalProcessEnv, originalProcessPlatform, originalSpawn, spawn beforeEach(function () { + originalSpawn = childProcess.spawn + spawn = mockSpawn() + childProcess.spawn = spawn originalProcessEnv = process.env originalProcessPlatform = process.platform process.env = {} }) afterEach(function () { + if (originalSpawn) { + childProcess.spawn = originalSpawn + } process.env = originalProcessEnv process.platform = originalProcessPlatform + temp.cleanupSync() }) describe('when the launch environment appears to come from a shell', function () { - it('updates process.env to match the launch environment', function () { + it('updates process.env to match the launch environment', async function () { process.env = { WILL_BE_DELETED: 'hi', NODE_ENV: 'the-node-env', @@ -32,7 +42,7 @@ describe('updateProcessEnv(launchEnv)', function () { const initialProcessEnv = process.env - updateProcessEnv({ATOM_DISABLE_SHELLING_OUT_FOR_ENVIRONMENT: 'true', PWD: '/the/dir', TERM: 'xterm-something', KEY1: 'value1', KEY2: 'value2'}) + await updateProcessEnv({ATOM_DISABLE_SHELLING_OUT_FOR_ENVIRONMENT: 'true', PWD: '/the/dir', TERM: 'xterm-something', KEY1: 'value1', KEY2: 'value2'}) expect(process.env).toEqual({ ATOM_DISABLE_SHELLING_OUT_FOR_ENVIRONMENT: 'true', PWD: '/the/dir', @@ -50,7 +60,7 @@ describe('updateProcessEnv(launchEnv)', function () { expect(process.env).toBe(initialProcessEnv) }) - it('allows ATOM_HOME to be overwritten only if the new value is a valid path', function () { + it('allows ATOM_HOME to be overwritten only if the new value is a valid path', async function () { let newAtomHomePath = temp.mkdirSync('atom-home') process.env = { @@ -60,7 +70,7 @@ describe('updateProcessEnv(launchEnv)', function () { ATOM_HOME: '/the/atom/home' } - updateProcessEnv({ATOM_DISABLE_SHELLING_OUT_FOR_ENVIRONMENT: 'true', PWD: '/the/dir'}) + await updateProcessEnv({ATOM_DISABLE_SHELLING_OUT_FOR_ENVIRONMENT: 'true', PWD: '/the/dir'}) expect(process.env).toEqual({ PWD: '/the/dir', ATOM_DISABLE_SHELLING_OUT_FOR_ENVIRONMENT: 'true', @@ -69,7 +79,7 @@ describe('updateProcessEnv(launchEnv)', function () { ATOM_HOME: '/the/atom/home' }) - updateProcessEnv({ATOM_DISABLE_SHELLING_OUT_FOR_ENVIRONMENT: 'true', PWD: '/the/dir', ATOM_HOME: path.join(newAtomHomePath, 'non-existent')}) + await updateProcessEnv({ATOM_DISABLE_SHELLING_OUT_FOR_ENVIRONMENT: 'true', PWD: '/the/dir', ATOM_HOME: path.join(newAtomHomePath, 'non-existent')}) expect(process.env).toEqual({ ATOM_DISABLE_SHELLING_OUT_FOR_ENVIRONMENT: 'true', PWD: '/the/dir', @@ -78,7 +88,7 @@ describe('updateProcessEnv(launchEnv)', function () { ATOM_HOME: '/the/atom/home' }) - updateProcessEnv({ATOM_DISABLE_SHELLING_OUT_FOR_ENVIRONMENT: 'true', PWD: '/the/dir', ATOM_HOME: newAtomHomePath}) + await updateProcessEnv({ATOM_DISABLE_SHELLING_OUT_FOR_ENVIRONMENT: 'true', PWD: '/the/dir', ATOM_HOME: newAtomHomePath}) expect(process.env).toEqual({ ATOM_DISABLE_SHELLING_OUT_FOR_ENVIRONMENT: 'true', PWD: '/the/dir', @@ -88,7 +98,7 @@ describe('updateProcessEnv(launchEnv)', function () { }) }) - it('allows ATOM_DISABLE_SHELLING_OUT_FOR_ENVIRONMENT to be preserved if set', function () { + it('allows ATOM_DISABLE_SHELLING_OUT_FOR_ENVIRONMENT to be preserved if set', async function () { process.env = { WILL_BE_DELETED: 'hi', NODE_ENV: 'the-node-env', @@ -96,7 +106,7 @@ describe('updateProcessEnv(launchEnv)', function () { ATOM_HOME: '/the/atom/home' } - updateProcessEnv({ATOM_DISABLE_SHELLING_OUT_FOR_ENVIRONMENT: 'true', PWD: '/the/dir', NODE_ENV: 'the-node-env', NODE_PATH: '/the/node/path', ATOM_HOME: '/the/atom/home'}) + await updateProcessEnv({ATOM_DISABLE_SHELLING_OUT_FOR_ENVIRONMENT: 'true', PWD: '/the/dir', NODE_ENV: 'the-node-env', NODE_PATH: '/the/node/path', ATOM_HOME: '/the/atom/home'}) expect(process.env).toEqual({ ATOM_DISABLE_SHELLING_OUT_FOR_ENVIRONMENT: 'true', PWD: '/the/dir', @@ -105,7 +115,7 @@ describe('updateProcessEnv(launchEnv)', function () { ATOM_HOME: '/the/atom/home' }) - updateProcessEnv({PWD: '/the/dir', NODE_ENV: 'the-node-env', NODE_PATH: '/the/node/path', ATOM_HOME: '/the/atom/home'}) + await updateProcessEnv({PWD: '/the/dir', NODE_ENV: 'the-node-env', NODE_PATH: '/the/node/path', ATOM_HOME: '/the/atom/home'}) expect(process.env).toEqual({ ATOM_DISABLE_SHELLING_OUT_FOR_ENVIRONMENT: 'true', PWD: '/the/dir', @@ -115,7 +125,7 @@ describe('updateProcessEnv(launchEnv)', function () { }) }) - it('allows an existing env variable to be updated', function () { + it('allows an existing env variable to be updated', async function () { process.env = { WILL_BE_UPDATED: 'old-value', NODE_ENV: 'the-node-env', @@ -123,7 +133,7 @@ describe('updateProcessEnv(launchEnv)', function () { ATOM_HOME: '/the/atom/home' } - updateProcessEnv(process.env) + await updateProcessEnv(process.env) expect(process.env).toEqual(process.env) let updatedEnv = { @@ -135,27 +145,27 @@ describe('updateProcessEnv(launchEnv)', function () { PWD: '/the/dir' } - updateProcessEnv(updatedEnv) + await updateProcessEnv(updatedEnv) expect(process.env).toEqual(updatedEnv) }) }) describe('when the launch environment does not come from a shell', function () { - describe('on osx', function () { - it('updates process.env to match the environment in the user\'s login shell', function () { + describe('on macOS', function () { + it('updates process.env to match the environment in the user\'s login shell', async function () { + if (process.platform === 'win32') return // TestsThatFailOnWin32 + process.platform = 'darwin' process.env.SHELL = '/my/custom/bash' - - spyOn(child_process, 'spawnSync').andReturn({ - stdout: dedent` - FOO=BAR=BAZ=QUUX - TERM=xterm-something - PATH=/usr/bin:/bin:/usr/sbin:/sbin:/crazy/path - ` - }) - - updateProcessEnv(process.env) - expect(child_process.spawnSync.mostRecentCall.args[0]).toBe('/my/custom/bash') + spawn.setDefault(spawn.simple(0, dedent` + FOO=BAR=BAZ=QUUX + TERM=xterm-something + PATH=/usr/bin:/bin:/usr/sbin:/sbin:/crazy/path + `)) + await updateProcessEnv(process.env) + expect(spawn.calls.length).toBe(1) + expect(spawn.calls[0].command).toBe('/my/custom/bash') + expect(spawn.calls[0].args).toEqual(['-ilc', 'command env']) expect(process.env).toEqual({ FOO: 'BAR=BAZ=QUUX', TERM: 'xterm-something', @@ -163,25 +173,25 @@ describe('updateProcessEnv(launchEnv)', function () { }) // Doesn't error - updateProcessEnv(null) + await updateProcessEnv(null) }) }) describe('on linux', function () { - it('updates process.env to match the environment in the user\'s login shell', function () { + it('updates process.env to match the environment in the user\'s login shell', async function () { + if (process.platform === 'win32') return // TestsThatFailOnWin32 + process.platform = 'linux' process.env.SHELL = '/my/custom/bash' - - spyOn(child_process, 'spawnSync').andReturn({ - stdout: dedent` - FOO=BAR=BAZ=QUUX - TERM=xterm-something - PATH=/usr/bin:/bin:/usr/sbin:/sbin:/crazy/path - ` - }) - - updateProcessEnv(process.env) - expect(child_process.spawnSync.mostRecentCall.args[0]).toBe('/my/custom/bash') + spawn.setDefault(spawn.simple(0, dedent` + FOO=BAR=BAZ=QUUX + TERM=xterm-something + PATH=/usr/bin:/bin:/usr/sbin:/sbin:/crazy/path + `)) + await updateProcessEnv(process.env) + expect(spawn.calls.length).toBe(1) + expect(spawn.calls[0].command).toBe('/my/custom/bash') + expect(spawn.calls[0].args).toEqual(['-ilc', 'command env']) expect(process.env).toEqual({ FOO: 'BAR=BAZ=QUUX', TERM: 'xterm-something', @@ -189,24 +199,26 @@ describe('updateProcessEnv(launchEnv)', function () { }) // Doesn't error - updateProcessEnv(null) + await updateProcessEnv(null) }) }) describe('on windows', function () { - it('does not update process.env', function () { + it('does not update process.env', async function () { process.platform = 'win32' - spyOn(child_process, 'spawnSync') + spyOn(childProcess, 'spawn') process.env = {FOO: 'bar'} - updateProcessEnv(process.env) - expect(child_process.spawnSync).not.toHaveBeenCalled() + await updateProcessEnv(process.env) + expect(childProcess.spawn).not.toHaveBeenCalled() expect(process.env).toEqual({FOO: 'bar'}) }) }) describe('shouldGetEnvFromShell()', function () { it('indicates when the environment should be fetched from the shell', function () { + if (process.platform === 'win32') return // TestsThatFailOnWin32 + process.platform = 'darwin' expect(shouldGetEnvFromShell({SHELL: '/bin/sh'})).toBe(true) expect(shouldGetEnvFromShell({SHELL: '/usr/local/bin/sh'})).toBe(true) diff --git a/spec/window-event-handler-spec.coffee b/spec/window-event-handler-spec.coffee index 8e08fec35..e9a7894c3 100644 --- a/spec/window-event-handler-spec.coffee +++ b/spec/window-event-handler-spec.coffee @@ -23,6 +23,7 @@ describe "WindowEventHandler", -> describe "when the window is loaded", -> it "doesn't have .is-blurred on the body tag", -> + return if process.platform is 'win32' #Win32TestFailures - can not steal focus expect(document.body.className).not.toMatch("is-blurred") describe "when the window is blurred", -> diff --git a/spec/workspace-element-spec.coffee b/spec/workspace-element-spec.coffee index 9ffa3621a..6bcb24eed 100644 --- a/spec/workspace-element-spec.coffee +++ b/spec/workspace-element-spec.coffee @@ -4,6 +4,9 @@ temp = require('temp').track() {Disposable} = require 'event-kit' describe "WorkspaceElement", -> + afterEach -> + temp.cleanupSync() + describe "when the workspace element is focused", -> it "transfers focus to the active pane", -> workspaceElement = atom.views.getView(atom.workspace) diff --git a/spec/workspace-spec.coffee b/spec/workspace-spec.coffee index 61f1e8266..023c3c970 100644 --- a/spec/workspace-spec.coffee +++ b/spec/workspace-spec.coffee @@ -1,5 +1,5 @@ path = require 'path' -temp = require 'temp' +temp = require('temp').track() TextEditor = require '../src/text-editor' Workspace = require '../src/workspace' Project = require '../src/project' @@ -19,6 +19,9 @@ describe "Workspace", -> atom.project.setPaths([atom.project.getDirectories()[0]?.resolve('dir')]) waits(1) + afterEach -> + temp.cleanupSync() + describe "serialization", -> simulateReload = -> workspaceState = atom.workspace.serialize() @@ -489,6 +492,7 @@ describe "Workspace", -> expect(item).toEqual {bar: "bar://baz"} it "adds the file to the application's recent documents list", -> + return unless process.platform is 'darwin' # Feature only supported on macOS spyOn(atom.applicationDelegate, 'addRecentDocument') waitsForPromise -> @@ -1139,6 +1143,7 @@ describe "Workspace", -> range: [[2, 6], [2, 11]] it "works on evil filenames", -> + atom.config.set('core.excludeVcsIgnoredPaths', false) platform.generateEvilFiles() atom.project.setPaths([path.join(__dirname, 'fixtures', 'evil-files')]) paths = [] @@ -1224,7 +1229,7 @@ describe "Workspace", -> expect(matches.length).toBe 1 it "includes files and folders that begin with a '.'", -> - projectPath = temp.mkdirSync() + projectPath = temp.mkdirSync('atom-spec-workspace') filePath = path.join(projectPath, '.text') fs.writeFileSync(filePath, 'match this') atom.project.setPaths([projectPath]) diff --git a/src/atom-environment.coffee b/src/atom-environment.coffee index 848e6c6e8..02bbf8b22 100644 --- a/src/atom-environment.coffee +++ b/src/atom-environment.coffee @@ -13,6 +13,7 @@ StateStore = require './state-store' StorageFolder = require './storage-folder' {getWindowLoadSettings} = require './window-load-settings-helpers' registerDefaultCommands = require './register-default-commands' +{updateProcessEnv} = require './update-process-env' DeserializerManager = require './deserializer-manager' ViewRegistry = require './view-registry' @@ -239,16 +240,6 @@ class AtomEnvironment extends Model new ReopenProjectMenuManager({@menu, @commands, @history, @config, open: (paths) => @open(pathsToOpen: paths)}) - checkPortableHomeWritable = => - responseChannel = "check-portable-home-writable-response" - ipcRenderer.on responseChannel, (event, response) -> - ipcRenderer.removeAllListeners(responseChannel) - @notifications.addWarning("#{response.message.replace(/([\\\.+\\-_#!])/g, '\\$1')}") if not response.writable - @disposables.add new Disposable -> ipcRenderer.removeAllListeners(responseChannel) - ipcRenderer.send('check-portable-home-writable', responseChannel) - - checkPortableHomeWritable() - attachSaveStateListeners: -> saveState = _.debounce((=> window.requestIdleCallback => @saveState({isUnloading: false}) unless @unloaded @@ -675,7 +666,11 @@ class AtomEnvironment extends Model # Call this method when establishing a real application window. startEditorWindow: -> @unloaded = false - @loadState().then (state) => + updateProcessEnvPromise = updateProcessEnv(@getLoadSettings().env) + updateProcessEnvPromise.then => + @packages.triggerActivationHook('core:loaded-shell-environment') + + loadStatePromise = @loadState().then (state) => @windowDimensions = state?.windowDimensions @displayWindow().then => @commandInstaller.installAtomCommand false, (error) -> @@ -716,6 +711,8 @@ class AtomEnvironment extends Model @openInitialEmptyEditorIfNecessary() + Promise.all([loadStatePromise, updateProcessEnvPromise]) + serialize: (options) -> version: @constructor.version project: @project.serialize(options) diff --git a/src/atom-paths.js b/src/atom-paths.js new file mode 100644 index 000000000..6a5c107b3 --- /dev/null +++ b/src/atom-paths.js @@ -0,0 +1,62 @@ +/** @babel */ + +const fs = require('fs-plus') +const path = require('path') + +const hasWriteAccess = (dir) => { + const testFilePath = path.join(dir, 'write.test') + try { + fs.writeFileSync(testFilePath, new Date().toISOString(), { flag: 'w+' }) + fs.unlinkSync(testFilePath) + return true + } catch (err) { + return false + } +} + +const getAppDirectory = () => { + switch (process.platform) { + case 'darwin': + return path.join(process.execPath.substring(0, process.execPath.indexOf('.app')), '..') + case 'linux': + case 'win32': + return path.join(process.execPath, '..') + } +} + +module.exports = { + setAtomHome: (homePath) => { + // When a read-writeable .atom folder exists above app use that + const portableHomePath = path.join(getAppDirectory(), '.atom') + if (fs.existsSync(portableHomePath)) { + if (hasWriteAccess(portableHomePath)) { + process.env.ATOM_HOME = portableHomePath + } else { + // A path exists so it was intended to be used but we didn't have rights, so warn. + console.log(`Insufficient permission to portable Atom home "${portableHomePath}".`) + } + } + + // Check ATOM_HOME environment variable next + if (process.env.ATOM_HOME !== undefined) { + return + } + + // Fall back to default .atom folder in users home folder + process.env.ATOM_HOME = path.join(homePath, '.atom') + }, + + setUserData: (app) => { + const electronUserDataPath = path.join(process.env.ATOM_HOME, 'electronUserData') + if (fs.existsSync(electronUserDataPath)) { + if (hasWriteAccess(electronUserDataPath)) { + app.setPath('userData', electronUserDataPath) + } else { + // A path exists so it was intended to be used but we didn't have rights, so warn. + console.log(`Insufficient permission to Electron user data "${electronUserDataPath}".`) + } + } + }, + + getAppDirectory: getAppDirectory +} diff --git a/src/buffered-process.js b/src/buffered-process.js index 4cc7d40d5..bfad041df 100644 --- a/src/buffered-process.js +++ b/src/buffered-process.js @@ -50,33 +50,8 @@ export default class BufferedProcess { this.emitter = new Emitter() this.command = command // Related to joyent/node#2318 - if (process.platform === 'win32' && !options.shell) { - let cmdArgs = [] - - // Quote all arguments and escapes inner quotes - if (args) { - cmdArgs = args.filter((arg) => arg != null) - .map((arg) => { - if (this.isExplorerCommand(command) && /^\/[a-zA-Z]+,.*$/.test(arg)) { - // Don't wrap /root,C:\folder style arguments to explorer calls in - // quotes since they will not be interpreted correctly if they are - return arg - } else { - return `\"${arg.toString().replace(/"/g, '\\"')}\"` - } - }) - } - - if (/\s/.test(command)) { - cmdArgs.unshift(`\"${command}\"`) - } else { - cmdArgs.unshift(command) - } - - cmdArgs = ['/s', '/d', '/c', `\"${cmdArgs.join(' ')}\"`] - const cmdOptions = _.clone(options) - cmdOptions.windowsVerbatimArguments = true - this.spawn(this.getCmdPath(), cmdArgs, cmdOptions) + if (process.platform === 'win32' && options.shell === undefined) { + this.spawnWithEscapedWindowsArgs(command, args, options) } else { this.spawn(command, args, options) } @@ -85,6 +60,33 @@ export default class BufferedProcess { this.handleEvents(stdout, stderr, exit) } + // Windows has a bunch of special rules that node still doesn't take care of for you + spawnWithEscapedWindowsArgs (command, args, options) { + let cmdArgs = [] + // Quote all arguments and escapes inner quotes + if (args) { + cmdArgs = args.filter((arg) => arg != null) + .map((arg) => { + if (this.isExplorerCommand(command) && /^\/[a-zA-Z]+,.*$/.test(arg)) { + // Don't wrap /root,C:\folder style arguments to explorer calls in + // quotes since they will not be interpreted correctly if they are + return arg + } else { + // Escape double quotes by putting a backslash in front of them + return `\"${arg.toString().replace(/"/g, '\\"')}\"` + } + }) + } + + // The command itself is quoted if it contains spaces, &, ^ or | chars + cmdArgs.unshift(/\s|&|\^|\|/.test(command) ? `\"${command}\"` : command) + + const cmdOptions = _.clone(options) + cmdOptions.windowsVerbatimArguments = true + + this.spawn(this.getCmdPath(), ['/s', '/d', '/c', `\"${cmdArgs.join(' ')}\"`], cmdOptions) + } + /* Section: Event Subscription */ diff --git a/src/config-schema.js b/src/config-schema.js index 63be1273f..0445d5970 100644 --- a/src/config-schema.js +++ b/src/config-schema.js @@ -12,7 +12,7 @@ const configSchema = { properties: { ignoredNames: { type: 'array', - default: ['.git', '.hg', '.svn', '.DS_Store', '._*', 'Thumbs.db'], + default: ['.git', '.hg', '.svn', '.DS_Store', '._*', 'Thumbs.db', 'desktop.ini'], items: { type: 'string' }, @@ -85,6 +85,8 @@ const configSchema = { default: 'utf8', enum: [ 'cp437', + 'cp850', + 'cp866', 'eucjp', 'euckr', 'gbk', @@ -117,12 +119,16 @@ const configSchema = { 'windows1255', 'windows1256', 'windows1257', - 'windows1258', - 'windows866' + 'windows1258' ] }, openEmptyEditorOnStart: { - description: 'Automatically open an empty editor on startup.', + description: 'When checked opens an untitled editor when loading a blank environment (such as with _File > New Window_ or when "Restore Previous Windows On Start" is unchecked); otherwise no editor is opened when loading a blank environment. This setting has no effect when restoring a previous state.', + type: 'boolean', + default: true + }, + restorePreviousWindowsOnStart: { + description: 'When checked restores the last state of all Atom windows when started from the icon or `atom` by itself from the command line; otherwise a blank environment is loaded.', type: 'boolean', default: true }, diff --git a/src/git-repository.coffee b/src/git-repository.coffee index d47b2e37c..423a5ce2f 100644 --- a/src/git-repository.coffee +++ b/src/git-repository.coffee @@ -238,6 +238,7 @@ class GitRepository # Public: Returns the git configuration value specified by the key. # + # * `key` The {String} key for the configuration to lookup. # * `path` An optional {String} path in the repository to get this information # for, only needed if the repository has submodules. getConfigValue: (key, path) -> @getRepo(path).getConfigValue(key) diff --git a/src/gutter-container-component.coffee b/src/gutter-container-component.coffee index 56b0fea84..ebb2d8597 100644 --- a/src/gutter-container-component.coffee +++ b/src/gutter-container-component.coffee @@ -103,6 +103,7 @@ class GutterContainerComponent @domNode.appendChild(gutterComponent.getDomNode()) else @domNode.insertBefore(gutterComponent.getDomNode(), @domNode.children[indexInOldGutters]) + indexInOldGutters += 1 # Remove any gutters that were not present in the new gutters state. for gutterComponentDescription in @gutterComponents diff --git a/src/history-manager.js b/src/history-manager.js index 657beed97..c5117d00f 100644 --- a/src/history-manager.js +++ b/src/history-manager.js @@ -47,6 +47,8 @@ export class HistoryManager { } addProject (paths, lastOpened) { + if (paths.length === 0) return + let project = this.getProject(paths) if (!project) { project = new HistoryProject(paths) @@ -60,9 +62,8 @@ export class HistoryManager { } getProject (paths) { - const pathsString = paths.toString() for (var i = 0; i < this.projects.length; i++) { - if (this.projects[i].paths.toString() === pathsString) { + if (arrayEquivalent(paths, this.projects[i].paths)) { return this.projects[i] } } @@ -98,6 +99,14 @@ export class HistoryManager { } } +function arrayEquivalent (a, b) { + if (a.length !== b.length) return false + for (var i = 0; i < a.length; i++) { + if (a[i] !== b[i]) return false + } + return true +} + export class HistoryProject { constructor (paths, lastOpened) { this.paths = paths diff --git a/src/initialize-application-window.coffee b/src/initialize-application-window.coffee index 2dbd85dcb..7d3a23db7 100644 --- a/src/initialize-application-window.coffee +++ b/src/initialize-application-window.coffee @@ -8,8 +8,6 @@ module.exports = ({blobStore}) -> {resourcePath, devMode, env} = getWindowLoadSettings() require './electron-shims' - updateProcessEnv(env) - # Add application-specific exports to module search path. exportsPath = path.join(resourcePath, 'exports') require('module').globalPaths.push(exportsPath) diff --git a/src/input-component.coffee b/src/input-component.coffee index b8081b0d6..27543a2fd 100644 --- a/src/input-component.coffee +++ b/src/input-component.coffee @@ -1,15 +1,6 @@ module.exports = class InputComponent - constructor: -> - @domNode = document.createElement('input') - @domNode.classList.add('hidden-input') - @domNode.setAttribute('tabindex', -1) - @domNode.setAttribute('data-react-skip-selection-restoration', true) - @domNode.style['-webkit-transform'] = 'translateZ(0)' - @domNode.addEventListener 'paste', (event) -> event.preventDefault() - - getDomNode: -> - @domNode + constructor: (@domNode) -> updateSync: (state) -> @oldState ?= {} diff --git a/src/main-process/atom-application.coffee b/src/main-process/atom-application.coffee index 440b1af99..1f064da6e 100644 --- a/src/main-process/atom-application.coffee +++ b/src/main-process/atom-application.coffee @@ -34,7 +34,7 @@ class AtomApplication unless options.socketPath? if process.platform is 'win32' userNameSafe = new Buffer(process.env.USERNAME).toString('base64') - options.socketPath = "\\\\.\\pipe\\atom-#{options.version}-#{userNameSafe}-sock" + options.socketPath = "\\\\.\\pipe\\atom-#{options.version}-#{userNameSafe}-#{process.arch}-sock" else options.socketPath = path.join(os.tmpdir(), "atom-#{options.version}-#{process.env.USER}.sock") @@ -63,7 +63,7 @@ class AtomApplication exit: (status) -> app.exit(status) constructor: (options) -> - {@resourcePath, @devResourcePath, @version, @devMode, @safeMode, @socketPath, @logFile, @setPortable, @userDataDir} = options + {@resourcePath, @devResourcePath, @version, @devMode, @safeMode, @socketPath, @logFile, @userDataDir} = options @socketPath = null if options.test or options.benchmark or options.benchmarkTest @pidsToOpenWindows = {} @windows = [] @@ -509,7 +509,7 @@ class AtomApplication openPaths: ({initialPaths, pathsToOpen, executedFrom, pidToKillWhenClosed, newWindow, devMode, safeMode, windowDimensions, profileStartup, window, clearWindowState, addToLastWindow, env}={}) -> if not pathsToOpen? or pathsToOpen.length is 0 return - + env = process.env unless env? devMode = Boolean(devMode) safeMode = Boolean(safeMode) clearWindowState = Boolean(clearWindowState) @@ -796,7 +796,6 @@ class AtomApplication restart: -> args = [] args.push("--safe") if @safeMode - args.push("--portable") if @setPortable args.push("--log-file=#{@logFile}") if @logFile? args.push("--socket-path=#{@socketPath}") if @socketPath? args.push("--user-data-dir=#{@userDataDir}") if @userDataDir? diff --git a/src/main-process/atom-portable.js b/src/main-process/atom-portable.js deleted file mode 100644 index 7d395c0e7..000000000 --- a/src/main-process/atom-portable.js +++ /dev/null @@ -1,58 +0,0 @@ -const fs = require('fs-plus') -const path = require('path') -const {ipcMain} = require('electron') - -module.exports = class AtomPortable { - static getPortableAtomHomePath () { - const execDirectoryPath = path.dirname(process.execPath) - return path.join(execDirectoryPath, '..', '.atom') - } - - static setPortable (existingAtomHome) { - fs.copySync(existingAtomHome, this.getPortableAtomHomePath()) - } - - static isPortableInstall (platform, environmentAtomHome, defaultHome) { - if (!['linux', 'win32'].includes(platform)) { - return false - } - - if (environmentAtomHome) { - return false - } - - if (!fs.existsSync(this.getPortableAtomHomePath())) { - return false - } - - // Currently checking only that the directory exists and is writable, - // probably want to do some integrity checks on contents in future. - return this.isPortableAtomHomePathWritable(defaultHome) - } - - static isPortableAtomHomePathWritable (defaultHome) { - let writable = false - let message = '' - try { - const writePermissionTestFile = path.join(this.getPortableAtomHomePath(), 'write.test') - - if (!fs.existsSync(writePermissionTestFile)) { - fs.writeFileSync(writePermissionTestFile, 'test') - } - - fs.removeSync(writePermissionTestFile) - writable = true - } catch (error) { - message = `Failed to use portable Atom home directory (${this.getPortableAtomHomePath()}). Using the default instead (${defaultHome}). ${error.message}.` - } - - ipcMain.on('check-portable-home-writable', function (event) { - event.sender.send('check-portable-home-writable-response', { - writable: writable, - message: message - }) - }) - - return writable - } -} diff --git a/src/main-process/auto-update-manager.coffee b/src/main-process/auto-update-manager.coffee index a4a45ce73..8fdba844d 100644 --- a/src/main-process/auto-update-manager.coffee +++ b/src/main-process/auto-update-manager.coffee @@ -17,13 +17,15 @@ class AutoUpdateManager constructor: (@version, @testMode, resourcePath, @config) -> @state = IdleState @iconPath = path.resolve(__dirname, '..', '..', 'resources', 'atom.png') - @feedUrl = "https://atom.io/api/updates?version=#{@version}" process.nextTick => @setupAutoUpdater() setupAutoUpdater: -> if process.platform is 'win32' + archSuffix = if process.arch is 'ia32' then '' else '-' + process.arch + @feedUrl = "https://atom.io/api/updates#{archSuffix}" autoUpdater = require './auto-updater-win32' else + @feedUrl = "https://atom.io/api/updates?version=#{@version}" {autoUpdater} = require 'electron' autoUpdater.on 'error', (event, message) => diff --git a/src/main-process/parse-command-line.js b/src/main-process/parse-command-line.js index 68a18fa30..4227b63ba 100644 --- a/src/main-process/parse-command-line.js +++ b/src/main-process/parse-command-line.js @@ -41,10 +41,6 @@ module.exports = function parseCommandLine (processArgs) { 'safe', 'Do not load packages from ~/.atom/packages or ~/.atom/dev/packages.' ) - options.boolean('portable').describe( - 'portable', - 'Set portable mode. Copies the ~/.atom folder to be a sibling of the installed Atom location if a .atom folder is not already there.' - ) options.boolean('benchmark').describe('benchmark', 'Open a new window that runs the specified benchmarks.') options.boolean('benchmark-test').describe('benchmark--test', 'Run a faster version of the benchmarks in headless mode.') options.alias('t', 'test').boolean('t').describe('t', 'Run the specified specs and exit with error code on failures.') @@ -104,7 +100,6 @@ module.exports = function parseCommandLine (processArgs) { const profileStartup = args['profile-startup'] const clearWindowState = args['clear-window-state'] const urlsToOpen = [] - const setPortable = args.portable let devMode = args['dev'] let devResourcePath = process.env.ATOM_DEV_RESOURCE_PATH || path.join(app.getPath('home'), 'github', 'atom') let resourcePath = null @@ -152,7 +147,6 @@ module.exports = function parseCommandLine (processArgs) { userDataDir, profileStartup, timeout, - setPortable, clearWindowState, addToLastWindow, mainProcess, diff --git a/src/main-process/start.js b/src/main-process/start.js index 84ae9b8c2..f54d263e0 100644 --- a/src/main-process/start.js +++ b/src/main-process/start.js @@ -1,10 +1,10 @@ const {app} = require('electron') -const fs = require('fs-plus') const nslog = require('nslog') const path = require('path') const temp = require('temp') const parseCommandLine = require('./parse-command-line') const startCrashReporter = require('../crash-reporter-start') +const atomPaths = require('../atom-paths') module.exports = function start (resourcePath, startTime) { global.shellStartTime = startTime @@ -23,7 +23,8 @@ module.exports = function start (resourcePath, startTime) { console.log = nslog const args = parseCommandLine(process.argv.slice(1)) - setupAtomHome(args) + atomPaths.setAtomHome(app.getPath('home')) + atomPaths.setUserData() setupCompileCache() if (handleStartupEventWithSquirrel()) { @@ -39,7 +40,7 @@ module.exports = function start (resourcePath, startTime) { } // NB: This prevents Win10 from showing dupe items in the taskbar - app.setAppUserModelId('com.squirrel.atom.atom') + app.setAppUserModelId('com.squirrel.atom.' + process.arch) function addPathToOpen (event, pathToOpen) { event.preventDefault() @@ -79,36 +80,6 @@ function handleStartupEventWithSquirrel () { return SquirrelUpdate.handleStartupEvent(app, squirrelCommand) } -function setupAtomHome ({setPortable}) { - if (process.env.ATOM_HOME) { - return - } - - let atomHome = path.join(app.getPath('home'), '.atom') - const AtomPortable = require('./atom-portable') - - if (setPortable && !AtomPortable.isPortableInstall(process.platform, process.env.ATOM_HOME, atomHome)) { - try { - AtomPortable.setPortable(atomHome) - } catch (error) { - console.log(`Failed copying portable directory '${atomHome}' to '${AtomPortable.getPortableAtomHomePath()}'`) - console.log(`${error.message} ${error.stack}`) - } - } - - if (AtomPortable.isPortableInstall(process.platform, process.env.ATOM_HOME, atomHome)) { - atomHome = AtomPortable.getPortableAtomHomePath() - } - - try { - atomHome = fs.realpathSync(atomHome) - } catch (e) { - // Don't throw an error if atomHome doesn't exist. - } - - process.env.ATOM_HOME = atomHome -} - function setupCompileCache () { const CompileCache = require('../compile-cache') CompileCache.setAtomHomeDirectory(process.env.ATOM_HOME) diff --git a/src/package-manager.coffee b/src/package-manager.coffee index 84a36dd78..fb4f7a658 100644 --- a/src/package-manager.coffee +++ b/src/package-manager.coffee @@ -39,6 +39,7 @@ class PackageManager @activationHookEmitter = new Emitter @packageDirPaths = [] @deferredActivationHooks = [] + @triggeredActivationHooks = new Set() if configDirPath? and not safeMode if @devMode @packageDirPaths.push(path.join(configDirPath, "dev", "packages")) @@ -67,6 +68,7 @@ class PackageManager @deactivatePackages() @loadedPackages = {} @packageStates = {} + @triggeredActivationHooks.clear() ### Section: Event Subscription @@ -460,12 +462,17 @@ class PackageManager Promise.resolve(pack) else if pack = @loadPackage(name) @activatingPackages[pack.name] = pack - pack.activate().then => + activationPromise = pack.activate().then => if @activatingPackages[pack.name]? delete @activatingPackages[pack.name] @activePackages[pack.name] = pack @emitter.emit 'did-activate-package', pack pack + + unless @deferredActivationHooks? + @triggeredActivationHooks.forEach((hook) => @activationHookEmitter.emit(hook)) + + activationPromise else Promise.reject(new Error("Failed to load package '#{name}'")) @@ -476,6 +483,7 @@ class PackageManager triggerActivationHook: (hook) -> return new Error("Cannot trigger an empty activation hook") unless hook? and _.isString(hook) and hook.length > 0 + @triggeredActivationHooks.add(hook) if @deferredActivationHooks? @deferredActivationHooks.push hook else diff --git a/src/package-transpilation-registry.js b/src/package-transpilation-registry.js index 1e41d8f8b..b8e81ccad 100644 --- a/src/package-transpilation-registry.js +++ b/src/package-transpilation-registry.js @@ -96,7 +96,7 @@ class PackageTranspilationRegistry { } lastPath = thisPath - thisPath = path.resolve(thisPath, '..') + thisPath = path.join(thisPath, '..') } this.specByFilePath[filePath] = null diff --git a/src/package.coffee b/src/package.coffee index 20236930b..9fa2dbe63 100644 --- a/src/package.coffee +++ b/src/package.coffee @@ -24,6 +24,7 @@ class Package mainModulePath: null resolvedMainModulePath: false mainModule: null + mainInitialized: false mainActivated: false ### @@ -114,8 +115,24 @@ class Package @menus = [] @grammars = [] @settings = [] + @mainInitialized = false @mainActivated = false + initializeIfNeeded: -> + return if @mainInitialized + @measure 'initializeTime', => + try + # The main module's `initialize()` method is guaranteed to be called + # before its `activate()`. This gives you a chance to handle the + # serialized package state before the package's derserializers and view + # providers are used. + @requireMainModule() unless @mainModule? + @mainModule.initialize?(@packageManager.getPackageState(@name) ? {}) + @mainInitialized = true + catch error + @handleError("Failed to initialize the #{@name} package", error) + return + activate: -> @grammarsPromise ?= @loadGrammars() @activationPromise ?= @@ -140,10 +157,13 @@ class Package @registerViewProviders() @activateStylesheets() if @mainModule? and not @mainActivated + @initializeIfNeeded() @mainModule.activateConfig?() @mainModule.activate?(@packageManager.getPackageState(@name) ? {}) @mainActivated = true @activateServices() + @activationCommandSubscriptions?.dispose() + @activationHookSubscriptions?.dispose() catch error @handleError("Failed to activate the #{@name} package", error) @@ -301,6 +321,7 @@ class Package deserialize: (state, atomEnvironment) => @registerViewProviders() @requireMainModule() + @initializeIfNeeded() @mainModule[methodName](state, atomEnvironment) return @@ -318,6 +339,7 @@ class Package @requireMainModule() @metadata.viewProviders.forEach (methodName) => @viewRegistry.addViewProvider (model) => + @initializeIfNeeded() @mainModule[methodName](model) @registeredViewProviders = true @@ -420,6 +442,7 @@ class Package @mainModule?.deactivate?() @mainModule?.deactivateConfig?() @mainActivated = false + @mainInitialized = false catch e console.error "Error deactivating package '#{@name}'", e.stack @emitter.emit 'did-deactivate' diff --git a/src/pane.coffee b/src/pane.coffee index 268b728ec..c55c9f043 100644 --- a/src/pane.coffee +++ b/src/pane.coffee @@ -234,6 +234,39 @@ class Pane extends Model onDidChangeActiveItem: (callback) -> @emitter.on 'did-change-active-item', callback + # Public: Invoke the given callback when {::activateNextRecentlyUsedItem} + # has been called, either initiating or continuing a forward MRU traversal of + # pane items. + # + # * `callback` {Function} to be called with when the active item changes. + # * `nextRecentlyUsedItem` The next MRU item, now being set active + # + # Returns a {Disposable} on which `.dispose()` can be called to unsubscribe. + onChooseNextMRUItem: (callback) -> + @emitter.on 'choose-next-mru-item', callback + + # Public: Invoke the given callback when {::activatePreviousRecentlyUsedItem} + # has been called, either initiating or continuing a reverse MRU traversal of + # pane items. + # + # * `callback` {Function} to be called with when the active item changes. + # * `previousRecentlyUsedItem` The previous MRU item, now being set active + # + # Returns a {Disposable} on which `.dispose()` can be called to unsubscribe. + onChooseLastMRUItem: (callback) -> + @emitter.on 'choose-last-mru-item', callback + + # Public: Invoke the given callback when {::moveActiveItemToTopOfStack} + # has been called, terminating an MRU traversal of pane items and moving the + # current active item to the top of the stack. Typically bound to a modifier + # (e.g. CTRL) key up event. + # + # * `callback` {Function} to be called with when the MRU traversal is done. + # + # Returns a {Disposable} on which `.dispose()` can be called to unsubscribe. + onDoneChoosingMRUItem: (callback) -> + @emitter.on 'done-choosing-mru-item', callback + # Public: Invoke the given callback with the current and future values of # {::getActiveItem}. # @@ -334,6 +367,7 @@ class Pane extends Model @itemStackIndex = @itemStack.length if @itemStackIndex is 0 @itemStackIndex = @itemStackIndex - 1 nextRecentlyUsedItem = @itemStack[@itemStackIndex] + @emitter.emit 'choose-next-mru-item', nextRecentlyUsedItem @setActiveItem(nextRecentlyUsedItem, modifyStack: false) # Makes the previous item in the itemStack active. @@ -343,12 +377,15 @@ class Pane extends Model @itemStackIndex = -1 @itemStackIndex = @itemStackIndex + 1 previousRecentlyUsedItem = @itemStack[@itemStackIndex] + @emitter.emit 'choose-last-mru-item', previousRecentlyUsedItem @setActiveItem(previousRecentlyUsedItem, modifyStack: false) # Moves the active item to the end of the itemStack once the ctrl key is lifted moveActiveItemToTopOfStack: -> delete @itemStackIndex @addItemToStack(@activeItem) + @emitter.emit 'done-choosing-mru-item' + # Public: Makes the next item active. activateNextItem: -> diff --git a/src/reopen-project-list-view.js b/src/reopen-project-list-view.js index 0774c8db7..f08ee725a 100644 --- a/src/reopen-project-list-view.js +++ b/src/reopen-project-list-view.js @@ -1,59 +1,71 @@ /** @babel */ -import { SelectListView } from 'atom-space-pen-views' +import SelectListView from 'atom-select-list' -export default class ReopenProjectListView extends SelectListView { - initialize (callback) { +export default class ReopenProjectListView { + constructor (callback) { this.callback = callback - super.initialize() - this.addClass('reopen-project') - this.list.addClass('mark-active') + this.selectListView = new SelectListView({ + emptyMessage: 'No projects in history.', + itemsClassList: ['mark-active'], + items: [], + filterKeyForItem: (project) => project.name, + elementForItem: (project) => { + let element = document.createElement('li') + if (project.name === this.currentProjectName) { + element.classList.add('active') + } + element.textContent = project.name + return element + }, + didConfirmSelection: (project) => { + this.cancel() + this.callback(project.value) + }, + didCancelSelection: () => { + this.cancel() + } + }) + this.selectListView.element.classList.add('reopen-project') } - getFilterKey () { - return 'name' + get element () { + return this.selectListView.element } - destroy () { + dispose () { this.cancel() + return this.selectListView.destroy() } - viewForItem (project) { - let element = document.createElement('li') - if (project.name === this.currentProjectName) { - element.classList.add('active') - } - element.textContent = project.name - return element - } - - cancelled () { + cancel () { if (this.panel != null) { this.panel.destroy() } this.panel = null this.currentProjectName = null - } - - confirmed (project) { - this.cancel() - this.callback(project.value) + if (this.previouslyFocusedElement) { + this.previouslyFocusedElement.focus() + this.previouslyFocusedElement = null + } } attach () { - this.storeFocusedElement() + this.previouslyFocusedElement = document.activeElement if (this.panel == null) { this.panel = atom.workspace.addModalPanel({item: this}) } - this.focusFilterEditor() + this.selectListView.focus() + this.selectListView.reset() } - toggle () { + async toggle () { if (this.panel != null) { this.cancel() } else { this.currentProjectName = atom.project != null ? this.makeName(atom.project.getPaths()) : null - this.setItems(atom.history.getProjects().map(p => ({ name: this.makeName(p.paths), value: p.paths }))) + const projects = atom.history.getProjects().map(p => ({ name: this.makeName(p.paths), value: p.paths })) + await this.selectListView.update({items: projects}) this.attach() } } diff --git a/src/reopen-project-menu-manager.js b/src/reopen-project-menu-manager.js index 50c42e115..35d802e7d 100644 --- a/src/reopen-project-menu-manager.js +++ b/src/reopen-project-menu-manager.js @@ -46,6 +46,32 @@ export default class ReopenProjectMenuManager { this.projects = this.historyManager.getProjects().slice(0, this.config.get('core.reopenProjectMenuCount')) const newMenu = ReopenProjectMenuManager.createProjectsMenu(this.projects) this.lastProjectMenu = this.menuManager.add([newMenu]) + this.updateWindowsJumpList() + } + + updateWindowsJumpList () { + if (process.platform !== 'win32') return + + if (this.app === undefined) { + this.app = require('remote').app + } + + this.app.setJumpList([ + { + type: 'custom', + name: 'Recent Projects', + items: this.projects.map(project => ({ + type: 'task', + title: project.paths.map(ReopenProjectMenuManager.betterBaseName).join(', '), + description: project.paths.map(path => `${ReopenProjectMenuManager.betterBaseName(path)} (${path})`).join(' '), + program: process.execPath, + args: project.paths.map(path => `"${path}"`).join(' ') })) + }, + { type: 'recent' }, + { items: [ + {type: 'task', title: 'New Window', program: process.execPath, args: '--new-window', description: 'Opens a new Atom window'} + ]} + ]) } dispose () { diff --git a/src/selection.coffee b/src/selection.coffee index 5eaa9c8dd..8aa86157e 100644 --- a/src/selection.coffee +++ b/src/selection.coffee @@ -366,7 +366,7 @@ class Selection extends Model insertText: (text, options={}) -> oldBufferRange = @getBufferRange() wasReversed = @isReversed() - @clear() + @clear(options) autoIndentFirstLine = false precedingText = @editor.getTextInRange([[oldBufferRange.start.row, 0], oldBufferRange.start]) @@ -403,7 +403,7 @@ class Selection extends Model else if options.autoDecreaseIndent and NonWhitespaceRegExp.test(text) @editor.autoDecreaseIndentForBufferRow(newBufferRange.start.row) - @autoscroll() if @isLastSelection() + @autoscroll() if options.autoscroll ? @isLastSelection() newBufferRange diff --git a/src/text-editor-component.coffee b/src/text-editor-component.coffee index cccd2f4c8..e8591819f 100644 --- a/src/text-editor-component.coffee +++ b/src/text-editor-component.coffee @@ -42,7 +42,7 @@ class TextEditorComponent @assert domNode?, "TextEditorComponent::domNode was set to null." @domNodeValue = domNode - constructor: ({@editor, @hostElement, tileSize, @views, @themes, @styles, @assert}) -> + constructor: ({@editor, @hostElement, tileSize, @views, @themes, @styles, @assert, hiddenInputElement}) -> @tileSize = tileSize if tileSize? @disposables = new CompositeDisposable @@ -70,8 +70,12 @@ class TextEditorComponent @scrollViewNode.classList.add('scroll-view') @domNode.appendChild(@scrollViewNode) - @hiddenInputComponent = new InputComponent - @scrollViewNode.appendChild(@hiddenInputComponent.getDomNode()) + @hiddenInputComponent = new InputComponent(hiddenInputElement) + @scrollViewNode.appendChild(hiddenInputElement) + # Add a getModel method to the hidden input component to make it easy to + # access the editor in response to DOM events or when using + # document.activeElement. + hiddenInputElement.getModel = => @editor @linesComponent = new LinesComponent({@presenter, @domElementPool, @assert, @grammars, @views}) @scrollViewNode.appendChild(@linesComponent.getDomNode()) @@ -342,7 +346,6 @@ class TextEditorComponent focused: -> if @mounted @presenter.setFocused(true) - @hiddenInputComponent.getDomNode().focus() blurred: -> if @mounted @@ -416,7 +419,6 @@ class TextEditorComponent onScrollViewScroll: => if @mounted - console.warn "TextEditorScrollView scrolled when it shouldn't have." @scrollViewNode.scrollTop = 0 @scrollViewNode.scrollLeft = 0 @@ -905,7 +907,7 @@ class TextEditorComponent screenRowForNode: (node) -> while node? - if screenRow = node.dataset.screenRow + if screenRow = node.dataset?.screenRow return parseInt(screenRow) node = node.parentElement null diff --git a/src/text-editor-element.coffee b/src/text-editor-element.coffee index 4a7d1598d..8c9792916 100644 --- a/src/text-editor-element.coffee +++ b/src/text-editor-element.coffee @@ -25,8 +25,17 @@ class TextEditorElement extends HTMLElement @emitter = new Emitter @subscriptions = new CompositeDisposable + @hiddenInputElement = document.createElement('input') + @hiddenInputElement.classList.add('hidden-input') + @hiddenInputElement.setAttribute('tabindex', -1) + @hiddenInputElement.setAttribute('data-react-skip-selection-restoration', true) + @hiddenInputElement.style['-webkit-transform'] = 'translateZ(0)' + @hiddenInputElement.addEventListener 'paste', (event) -> event.preventDefault() + @addEventListener 'focus', @focused.bind(this) @addEventListener 'blur', @blurred.bind(this) + @hiddenInputElement.addEventListener 'focus', @focused.bind(this) + @hiddenInputElement.addEventListener 'blur', @inputNodeBlurred.bind(this) @classList.add('editor') @setAttribute('tabindex', -1) @@ -117,12 +126,10 @@ class TextEditorElement extends HTMLElement themes: @themes styles: @styles workspace: @workspace - assert: @assert + assert: @assert, + hiddenInputElement: @hiddenInputElement ) @rootElement.appendChild(@component.getDomNode()) - inputNode = @component.hiddenInputComponent.getDomNode() - inputNode.addEventListener 'focus', @focused.bind(this) - inputNode.addEventListener 'blur', @inputNodeBlurred.bind(this) unmountComponent: -> if @component? @@ -132,16 +139,17 @@ class TextEditorElement extends HTMLElement focused: (event) -> @component?.focused() + @hiddenInputElement.focus() blurred: (event) -> - if event.relatedTarget is @component?.hiddenInputComponent.getDomNode() + if event.relatedTarget is @hiddenInputElement event.stopImmediatePropagation() return @component?.blurred() inputNodeBlurred: (event) -> if event.relatedTarget isnt this - @dispatchEvent(new FocusEvent('blur', bubbles: false)) + @dispatchEvent(new FocusEvent('blur', relatedTarget: event.relatedTarget, bubbles: false)) addGrammarScopeAttribute: -> @dataset.grammar = @model.getGrammar()?.scopeName?.replace(/\./g, ' ') diff --git a/src/text-editor-presenter.coffee b/src/text-editor-presenter.coffee index 22268af18..aa2cede72 100644 --- a/src/text-editor-presenter.coffee +++ b/src/text-editor-presenter.coffee @@ -306,9 +306,6 @@ class TextEditorPresenter getEndTileRow: -> @tileForRow(@endRow ? 0) - isValidScreenRow: (screenRow) -> - screenRow >= 0 and screenRow < @model.getApproximateScreenLineCount() - getScreenRowsToRender: -> startRow = @getStartTileRow() endRow = @getEndTileRow() + @tileSize @@ -320,7 +317,7 @@ class TextEditorPresenter if @screenRowsToMeasure? screenRows.push(@screenRowsToMeasure...) - screenRows = screenRows.filter @isValidScreenRow.bind(this) + screenRows = screenRows.filter (row) -> row >= 0 screenRows.sort (a, b) -> a - b _.uniq(screenRows, true) @@ -395,19 +392,17 @@ class TextEditorPresenter visibleTiles[tileStartRow] = true zIndex++ - if @mouseWheelScreenRow? and 0 <= @mouseWheelScreenRow < @model.getApproximateScreenLineCount() - mouseWheelTile = @tileForRow(@mouseWheelScreenRow) - - unless visibleTiles[mouseWheelTile]? - @lineNumberGutter.tiles[mouseWheelTile].display = "none" - @state.content.tiles[mouseWheelTile].display = "none" - visibleTiles[mouseWheelTile] = true + mouseWheelTileId = @tileForRow(@mouseWheelScreenRow) if @mouseWheelScreenRow? for id, tile of @state.content.tiles continue if visibleTiles.hasOwnProperty(id) - delete @state.content.tiles[id] - delete @lineNumberGutter.tiles[id] + if Number(id) is mouseWheelTileId + @state.content.tiles[id].display = "none" + @lineNumberGutter.tiles[id].display = "none" + else + delete @state.content.tiles[id] + delete @lineNumberGutter.tiles[id] updateLinesState: (tileState, screenRows) -> tileState.lines ?= {} @@ -456,7 +451,7 @@ class TextEditorPresenter for decoration in @model.getOverlayDecorations() continue unless decoration.getMarker().isValid() - {item, position, class: klass} = decoration.getProperties() + {item, position, class: klass, avoidOverflow} = decoration.getProperties() if position is 'tail' screenPosition = decoration.getMarker().getTailScreenPosition() else @@ -471,15 +466,16 @@ class TextEditorPresenter if overlayDimensions = @overlayDimensions[decoration.id] {itemWidth, itemHeight, contentMargin} = overlayDimensions - rightDiff = left + itemWidth + contentMargin - @windowWidth - left -= rightDiff if rightDiff > 0 + if avoidOverflow isnt false + rightDiff = left + itemWidth + contentMargin - @windowWidth + left -= rightDiff if rightDiff > 0 - leftDiff = left + contentMargin - left -= leftDiff if leftDiff < 0 + leftDiff = left + contentMargin + left -= leftDiff if leftDiff < 0 - if top + itemHeight > @windowHeight and - top - (itemHeight + @lineHeight) >= 0 - top -= itemHeight + @lineHeight + if top + itemHeight > @windowHeight and + top - (itemHeight + @lineHeight) >= 0 + top -= itemHeight + @lineHeight pixelPosition.top = top pixelPosition.left = left @@ -1006,8 +1002,7 @@ class TextEditorPresenter @lineHeight? and @baseCharacterWidth? pixelPositionForScreenPosition: (screenPosition) -> - position = - @linesYardstick.pixelPositionForScreenPosition(screenPosition) + position = @linesYardstick.pixelPositionForScreenPosition(screenPosition) position.top -= @getScrollTop() position.left -= @getScrollLeft() @@ -1230,13 +1225,14 @@ class TextEditorPresenter screenRange.end.column = 0 repositionRegionWithinTile: (region, tileStartRow) -> - region.top += @scrollTop - @lineTopIndex.pixelPositionBeforeBlocksForRow(tileStartRow) - region.left += @scrollLeft + region.top += @scrollTop - @lineTopIndex.pixelPositionBeforeBlocksForRow(tileStartRow) buildHighlightRegions: (screenRange) -> lineHeightInPixels = @lineHeight startPixelPosition = @pixelPositionForScreenPosition(screenRange.start) endPixelPosition = @pixelPositionForScreenPosition(screenRange.end) + startPixelPosition.left += @scrollLeft + endPixelPosition.left += @scrollLeft spannedRows = screenRange.end.row - screenRange.start.row + 1 regions = [] diff --git a/src/text-editor.coffee b/src/text-editor.coffee index 9cc7c83a4..f09ca9c2a 100644 --- a/src/text-editor.coffee +++ b/src/text-editor.coffee @@ -222,6 +222,7 @@ class TextEditor extends Model @backgroundWorkHandle = null update: (params) -> + currentSoftWrapColumn = @getSoftWrapColumn() displayLayerParams = {} for param in Object.keys(params) @@ -272,12 +273,16 @@ class TextEditor extends Model when 'softWrapAtPreferredLineLength' if value isnt @softWrapAtPreferredLineLength @softWrapAtPreferredLineLength = value - displayLayerParams.softWrapColumn = @getSoftWrapColumn() if @isSoftWrapped() + softWrapColumn = @getSoftWrapColumn() + if softWrapColumn isnt currentSoftWrapColumn + displayLayerParams.softWrapColumn = softWrapColumn when 'preferredLineLength' if value isnt @preferredLineLength @preferredLineLength = value - displayLayerParams.softWrapColumn = @getSoftWrapColumn() if @isSoftWrapped() + softWrapColumn = @getSoftWrapColumn() + if softWrapColumn isnt currentSoftWrapColumn + displayLayerParams.softWrapColumn = softWrapColumn when 'mini' if value isnt @mini @@ -322,12 +327,16 @@ class TextEditor extends Model when 'editorWidthInChars' if value > 0 and value isnt @editorWidthInChars @editorWidthInChars = value - displayLayerParams.softWrapColumn = @getSoftWrapColumn() if @isSoftWrapped() + softWrapColumn = @getSoftWrapColumn() + if softWrapColumn isnt currentSoftWrapColumn + displayLayerParams.softWrapColumn = softWrapColumn when 'width' if value isnt @width @width = value - displayLayerParams.softWrapColumn = @getSoftWrapColumn() if @isSoftWrapped() + softWrapColumn = @getSoftWrapColumn() + if softWrapColumn isnt currentSoftWrapColumn + displayLayerParams.softWrapColumn = softWrapColumn when 'scrollPastEnd' if value isnt @scrollPastEnd @@ -1076,8 +1085,8 @@ class TextEditor extends Model ) # Essential: For each selection, replace the selected text with a newline. - insertNewline: -> - @insertText('\n') + insertNewline: (options) -> + @insertText('\n', options) # Essential: For each selection, if the selection is empty, delete the character # following the cursor. Otherwise delete the selected text. @@ -1740,10 +1749,14 @@ class TextEditor extends Model # * `onlyNonEmpty` (optional) If `true`, the decoration will only be applied # if the associated `DisplayMarker` is non-empty. Only applicable to the # `gutter`, `line`, and `line-number` types. - # * `position` (optional) Only applicable to decorations of type `overlay` and `block`, - # controls where the view is positioned relative to the `TextEditorMarker`. + # * `position` (optional) Only applicable to decorations of type `overlay` and `block`. + # Controls where the view is positioned relative to the `TextEditorMarker`. # Values can be `'head'` (the default) or `'tail'` for overlay decorations, and # `'before'` (the default) or `'after'` for block decorations. + # * `avoidOverflow` (optional) Only applicable to decorations of type + # `overlay`. Determines whether the decoration adjusts its horizontal or + # vertical position to remain fully visible when it would otherwise + # overflow the editor. Defaults to `true`. # # Returns a {Decoration} object decorateMarker: (marker, decorationParams) -> diff --git a/src/theme-manager.coffee b/src/theme-manager.coffee index 32fabf724..58297b2db 100644 --- a/src/theme-manager.coffee +++ b/src/theme-manager.coffee @@ -178,7 +178,8 @@ class ThemeManager @requireStylesheet(nativeStylesheetPath) stylesheetElementForId: (id) -> - document.head.querySelector("atom-styles style[source-path=\"#{id}\"]") + escapedId = id.replace(/\\/g, '\\\\') + document.head.querySelector("atom-styles style[source-path=\"#{escapedId}\"]") resolveStylesheet: (stylesheetPath) -> if path.extname(stylesheetPath).length > 0 @@ -231,9 +232,6 @@ class ThemeManager applyStylesheet: (path, text) -> @styleSheetDisposablesBySourcePath[path] = @styleManager.addStyleSheet(text, sourcePath: path) - stringToId: (string) -> - string.replace(/\\/g, '/') - activateThemes: -> new Promise (resolve) => # @config.observe runs the callback once, then on subsequent changes. diff --git a/src/update-process-env.js b/src/update-process-env.js index 6544a6612..00bb13927 100644 --- a/src/update-process-env.js +++ b/src/update-process-env.js @@ -1,7 +1,7 @@ /** @babel */ import fs from 'fs' -import {spawnSync} from 'child_process' +import childProcess from 'child_process' const ENVIRONMENT_VARIABLES_TO_PRESERVE = new Set([ 'NODE_ENV', @@ -15,12 +15,14 @@ const PLATFORMS_KNOWN_TO_WORK = new Set([ 'linux' ]) -function updateProcessEnv (launchEnv) { +async function updateProcessEnv (launchEnv) { let envToAssign - if (launchEnv && shouldGetEnvFromShell(launchEnv)) { - envToAssign = getEnvFromShell(launchEnv) - } else if (launchEnv && launchEnv.PWD) { - envToAssign = launchEnv + if (launchEnv) { + if (shouldGetEnvFromShell(launchEnv)) { + envToAssign = await getEnvFromShell(launchEnv) + } else if (launchEnv.PWD) { + envToAssign = launchEnv + } } if (envToAssign) { @@ -58,24 +60,64 @@ function shouldGetEnvFromShell (env) { return true } -function getEnvFromShell (env) { - if (!shouldGetEnvFromShell(env)) { - return - } - - let {stdout} = spawnSync(env.SHELL, ['-ilc', 'command env'], {encoding: 'utf8'}) - if (stdout) { - let result = {} - for (let line of stdout.split('\n')) { - if (line.includes('=')) { - let components = line.split('=') - let key = components.shift() - let value = components.join('=') - result[key] = value +async function getEnvFromShell (env) { + let {stdout, error} = await new Promise((resolve) => { + let child + let error + let stdout = '' + let done = false + const cleanup = () => { + if (!done && child) { + child.kill() + done = true } } - return result + process.once('exit', cleanup) + setTimeout(() => { + cleanup() + }, 5000) + child = childProcess.spawn(env.SHELL, ['-ilc', 'command env'], {encoding: 'utf8', detached: true, stdio: ['ignore', 'pipe', process.stderr]}) + const buffers = [] + child.on('error', (e) => { + done = true + error = e + }) + child.stdout.on('data', (data) => { + buffers.push(data) + }) + child.on('close', (code, signal) => { + done = true + process.removeListener('exit', cleanup) + if (buffers.length) { + stdout = Buffer.concat(buffers).toString('utf8') + } + + resolve({stdout, error}) + }) + }) + + if (error) { + if (error.handle) { + error.handle() + } + console.log('warning: ' + env.SHELL + ' -ilc "command env" failed with signal (' + error.signal + ')') + console.log(error) } + + if (!stdout || stdout.trim() === '') { + return null + } + + let result = {} + for (let line of stdout.split('\n')) { + if (line.includes('=')) { + let components = line.split('=') + let key = components.shift() + let value = components.join('=') + result[key] = value + } + } + return result } export default { updateProcessEnv, shouldGetEnvFromShell } diff --git a/src/workspace.coffee b/src/workspace.coffee index 89c53b678..9c6dc3b80 100644 --- a/src/workspace.coffee +++ b/src/workspace.coffee @@ -441,7 +441,7 @@ class Workspace extends Model # Avoid adding URLs as recent documents to work-around this Spotlight crash: # https://github.com/atom/atom/issues/10071 - if uri? and not url.parse(uri).protocol? + if uri? and (not url.parse(uri).protocol? or process.platform is 'win32') @applicationDelegate.addRecentDocument(uri) pane = @paneContainer.paneForURI(uri) if searchAllPanes diff --git a/static/index.js b/static/index.js index b76477e03..2966eafdf 100644 --- a/static/index.js +++ b/static/index.js @@ -116,14 +116,12 @@ }) } - var currentWindow = require('electron').remote.getCurrentWindow() - if (currentWindow.devToolsWebContents) { + const webContents = require('electron').remote.getCurrentWindow().webContents + if (webContents.devToolsWebContents) { profile() } else { - currentWindow.openDevTools() - currentWindow.once('devtools-opened', function () { - setTimeout(profile, 1000) - }) + webContents.once('devtools-opened', () => { setTimeout(profile, 1000) }) + webContents.openDevTools() } }