Comparar commits
176 Commits
| Autor | SHA1 | Data | |
|---|---|---|---|
| eabad3dcef | |||
| 6ad099260e | |||
| ebfd921807 | |||
| 83c77b6e4b | |||
| 654a4392a4 | |||
| 8457c74f2f | |||
| 88366cb5d4 | |||
| c70c819aa2 | |||
| 4ac8aba31f | |||
| 776e431cc5 | |||
| 5a966240b9 | |||
| 27f0c525ac | |||
| 00170804e5 | |||
| d7e5f05f83 | |||
| 3ce641f53b | |||
| 27ca957629 | |||
| 84d0abc52c | |||
| 41c62e8628 | |||
| 1515690302 | |||
| 2be658b894 | |||
| d3e1c004fb | |||
| 62924dfcd1 | |||
| 770e97efff | |||
| 2704d2f15a | |||
| 957e45944a | |||
| 16fd14d295 | |||
| 20daed176b | |||
| 8c11c4a4c6 | |||
| 7cb44b69ef | |||
| d37cfb9042 | |||
| 986753981d | |||
| 970bde9361 | |||
| 7b55946abf | |||
| c74f6bb615 | |||
| 63f2ab3088 | |||
| 742ec6df0d | |||
| 864f9bc2b4 | |||
| 73896d100e | |||
| 193001d793 | |||
| 052f9580f2 | |||
| 2daf70f0e5 | |||
| fca9ed07e6 | |||
| c6fc0d050d | |||
| 6e913c47ef | |||
| a245624211 | |||
| 8af8caca55 | |||
| bbeb4be5b1 | |||
| 449da91216 | |||
| 521647e8ac | |||
| d863638c24 | |||
| 651df12f9b | |||
| 83706647d1 | |||
| 59fb4a839e | |||
| 04e23f581a | |||
| 4574a9e35d | |||
| a2eb4d9303 | |||
| c0a845bc56 | |||
| 1ace5a313c | |||
| 161eb3c3d2 | |||
| 6632a1c63d | |||
| ce5eff100c | |||
| 1bf9e14f9f | |||
| 94f40f0ed9 | |||
| 640881a15e | |||
| ee6c4d7b65 | |||
| a37aeba909 | |||
| 2449fda01d | |||
| b572594f92 | |||
| fbde059748 | |||
| 6084ef52e7 | |||
| a9f4dfc6b7 | |||
| 8032d6dab2 | |||
| 01ec449fce | |||
| e79d66497c | |||
| a205c6d190 | |||
| 2911b395ee | |||
| 64c25f17df | |||
| 9d3082ec95 | |||
| 034a377c5e | |||
| f0fbdc9842 | |||
| 96804096e9 | |||
| e2c41136f3 | |||
| 8b20e2e031 | |||
| 722d8cb48b | |||
| a73e6e5bd0 | |||
| 4cf68ef017 | |||
| b037395551 | |||
| 7a26a16511 | |||
| 30fc3d9e66 | |||
| 7de2ad34aa | |||
| 1bba631ab7 | |||
| cbf4087a3a | |||
| a3d72f5e6a | |||
| aeaa2fad06 | |||
| a219b90eea | |||
| 7086c60e6b | |||
| 0af4c82f36 | |||
| acf5ab816e | |||
| 6aa8c8bab9 | |||
| b5c939dee1 | |||
| 90d9315d45 | |||
| 7de2f57088 | |||
| 1488867063 | |||
| 59d62d48db | |||
| 97c2fc09f0 | |||
| 16d2e41309 | |||
| 13f66fb2ae | |||
| d6a8217e94 | |||
| 8e649e3008 | |||
| 8dffb45fd7 | |||
| c34ce0d2d0 | |||
| 61daf1cc36 | |||
| 1201fb6a5d | |||
| 7a5a329393 | |||
| f447781e01 | |||
| 070d9d0b46 | |||
| 49b4671076 | |||
| 28a0e94bb9 | |||
| ab2c5bfc35 | |||
| 80c64deb21 | |||
| 69af432965 | |||
| e788612ef4 | |||
| 62803efde0 | |||
| 01696b4d11 | |||
| 2c2dc61fa0 | |||
| 66ce001961 | |||
| 3aa6cc827c | |||
| c2304e1124 | |||
| 07f8f0915c | |||
| 7725c78c5e | |||
| 0624720634 | |||
| 64731bff46 | |||
| 878c393e8e | |||
| 84064a811c | |||
| 3c932d6d91 | |||
| a24d1d1af7 | |||
| edb5b43d64 | |||
| ac496e1fa4 | |||
| 103f3f8597 | |||
| 9842baedce | |||
| aaa916f78d | |||
| b463d9d876 | |||
| 7f6a4cccaf | |||
| d5e30e83f6 | |||
| d16c0e9e41 | |||
| bd8ac3bb32 | |||
| 87edff1e42 | |||
| 96f35d3cde | |||
| 7e45ffa4c3 | |||
| 6af69b0fc7 | |||
| 99e02570d1 | |||
| e1f4b7415a | |||
| 823cfcac57 | |||
| de6ccd8c08 | |||
| 2135d3be83 | |||
| 1c3720c160 | |||
| 6c72b13adc | |||
| 1404904d24 | |||
| db243936b4 | |||
| 6e72627e9e | |||
| 3d36ba7ecc | |||
| a7c0d6073f | |||
| f25b468272 | |||
| 2d0fb8ee6b | |||
| d875becc7a | |||
| cb72af63fd | |||
| f7187f1d5a | |||
| 700acdc5a2 | |||
| 18016ae9df | |||
| a30faa5bea | |||
| 05a113bb7a | |||
| f5d4ece9cd | |||
| 3bda37c56c | |||
| 62b52cb70a | |||
| a4fe594441 | |||
| 9d0e46126b |
+1
-1
@@ -6,6 +6,6 @@
|
||||
"url": "https://github.com/atom/atom.git"
|
||||
},
|
||||
"dependencies": {
|
||||
"atom-package-manager": "0.86.0"
|
||||
"atom-package-manager": "0.91.0"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -144,12 +144,7 @@ module.exports = (grunt) ->
|
||||
|
||||
coffeelint:
|
||||
options:
|
||||
no_empty_param_list:
|
||||
level: 'error'
|
||||
max_line_length:
|
||||
level: 'ignore'
|
||||
indentation:
|
||||
level: 'ignore'
|
||||
configFile: 'coffeelint.json'
|
||||
src: [
|
||||
'dot-atom/**/*.coffee'
|
||||
'exports/**/*.coffee'
|
||||
|
||||
@@ -13,7 +13,7 @@
|
||||
"github-releases": "~0.2.0",
|
||||
"grunt": "~0.4.1",
|
||||
"grunt-cli": "~0.1.9",
|
||||
"grunt-coffeelint": "git+https://github.com/atom/grunt-coffeelint.git",
|
||||
"grunt-coffeelint": "git+https://github.com/atom/grunt-coffeelint.git#cfb99aa99811d52687969532bd5a98011ed95bfe",
|
||||
"grunt-contrib-coffee": "~0.9.0",
|
||||
"grunt-contrib-csslint": "~0.1.2",
|
||||
"grunt-contrib-less": "~0.8.0",
|
||||
|
||||
@@ -148,9 +148,6 @@ module.exports = (grunt) ->
|
||||
grunt.file.copy(sourcePath, path.resolve(appDir, '..', subDirectory, filename))
|
||||
|
||||
if process.platform is 'win32'
|
||||
cp path.join('resources', 'win', 'msvcp100.dll'), path.join(shellAppDir, 'msvcp100.dll')
|
||||
cp path.join('resources', 'win', 'msvcr100.dll'), path.join(shellAppDir, 'msvcr100.dll')
|
||||
|
||||
# Set up chocolatey ignore and gui files
|
||||
fs.writeFileSync path.join(appDir, 'apm', 'node_modules', 'atom-package-manager', 'bin', 'node.exe.ignore'), ''
|
||||
fs.writeFileSync path.join(appDir, 'node_modules', 'symbols-view', 'vendor', 'ctags-win32.exe.ignore'), ''
|
||||
|
||||
@@ -45,8 +45,8 @@ module.exports = (grunt) ->
|
||||
|
||||
strings =
|
||||
CompanyName: 'GitHub, Inc.'
|
||||
FileDescription: 'The hackable editor'
|
||||
LegalCopyright: 'Copyright (C) 2013 GitHub, Inc. All rights reserved'
|
||||
FileDescription: 'Atom'
|
||||
LegalCopyright: 'Copyright (C) 2014 GitHub, Inc. All rights reserved'
|
||||
ProductName: 'Atom'
|
||||
ProductVersion: version
|
||||
|
||||
|
||||
@@ -0,0 +1,14 @@
|
||||
{
|
||||
"indentation": {
|
||||
"level": "ignore"
|
||||
},
|
||||
"max_line_length": {
|
||||
"level": "ignore"
|
||||
},
|
||||
"no_empty_param_list": {
|
||||
"level": "error"
|
||||
},
|
||||
"no_unnecessary_fat_arrows": {
|
||||
"level": "ignore"
|
||||
}
|
||||
}
|
||||
@@ -6,23 +6,26 @@ Ubuntu LTS 12.04 64-bit is the recommended platform.
|
||||
|
||||
* OS with 64-bit or 32-bit architecture
|
||||
* C++ toolchain
|
||||
* git
|
||||
* [node.js](http://nodejs.org/download/) v0.10.x
|
||||
* [npm](http://www.npmjs.org/) v1.4.x (bundled with node.js)
|
||||
* [Git](http://git-scm.com/)
|
||||
* [Node.js](http://nodejs.org/download/) v0.10.x
|
||||
* [npm](http://www.npmjs.org/) v1.4.x (bundled with Node.js)
|
||||
* `npm -v` to check the version.
|
||||
* `npm config set python /usr/bin/python2 -g` to ensure that gyp uses python2.
|
||||
* You might need to run this command as `sudo`, depending on how you have set up [npm](https://github.com/joyent/node/wiki/Installing-Node.js-via-package-manager#ubuntu-mint-elementary-os).
|
||||
* libgnome-keyring-dev
|
||||
* development headers for [GNOME Keyring](https://wiki.gnome.org/Projects/GnomeKeyring)
|
||||
|
||||
### Ubuntu / Debian
|
||||
|
||||
* `sudo apt-get install build-essential git libgnome-keyring-dev`
|
||||
* Instructions for [node.js](https://github.com/joyent/node/wiki/Installing-Node.js-via-package-manager#ubuntu-mint-elementary-os).
|
||||
* Instructions for [Node.js](https://github.com/joyent/node/wiki/Installing-Node.js-via-package-manager#ubuntu-mint-elementary-os).
|
||||
|
||||
### Fedora
|
||||
|
||||
* `sudo yum --assumeyes install make gcc gcc-c++ glibc-devel git-core libgnome-keyring-devel`
|
||||
* Instructions for [node.js](https://github.com/joyent/node/wiki/Installing-Node.js-via-package-manager#fedora).
|
||||
* Instructions for [Node.js](https://github.com/joyent/node/wiki/Installing-Node.js-via-package-manager#fedora).
|
||||
|
||||
### Arch
|
||||
|
||||
* `sudo pacman -S base-devel git nodejs libgnome-keyring`
|
||||
* `export PYTHON=/usr/bin/python2` before building Atom.
|
||||
|
||||
@@ -30,26 +33,41 @@ Ubuntu LTS 12.04 64-bit is the recommended platform.
|
||||
|
||||
If you have problems with permissions don't forget to prefix with `sudo`
|
||||
|
||||
Create the atom application at `$TMPDIR/atom-build/Atom`:
|
||||
From the cloned repository directory:
|
||||
|
||||
```sh
|
||||
script/build
|
||||
```
|
||||
1. Build:
|
||||
|
||||
Install the `atom` and `apm` commands to `/usr/local/bin`:
|
||||
```sh
|
||||
$ script/build
|
||||
```
|
||||
This will create the atom application at `$TMPDIR/atom-build/Atom`.
|
||||
2. Install the `atom` and `apm` commands to `/usr/local/bin` by executing:
|
||||
|
||||
```sh
|
||||
sudo script/grunt install
|
||||
```
|
||||
```sh
|
||||
$ sudo script/grunt install
|
||||
```
|
||||
3. *Optionally*, you may generate a `.deb` package at `$TMPDIR/atom-build`:
|
||||
|
||||
Generate a `.deb` package at `$TMPDIR/atom-build`: (*optional*)
|
||||
|
||||
```sh
|
||||
script/grunt mkdeb
|
||||
```
|
||||
```sh
|
||||
$ script/grunt mkdeb
|
||||
```
|
||||
|
||||
Use the newly installed atom by restarting any running atom instances.
|
||||
|
||||
## Advanced Options
|
||||
|
||||
### Custom install directory
|
||||
|
||||
```sh
|
||||
sudo script/grunt install --install-dir /install/atom/here
|
||||
```
|
||||
|
||||
### Custom build directory
|
||||
|
||||
```sh
|
||||
script/build --build-dir /build/atom/here
|
||||
```
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
### Exception: "TypeError: Unable to watch path"
|
||||
@@ -78,7 +96,7 @@ See also https://github.com/atom/atom/issues/2082.
|
||||
### /usr/bin/env: node: No such file or directory
|
||||
|
||||
If you get this notice when attempting to `script/build`, you either do not
|
||||
have nodejs installed, or node isn't identified as nodejs on your machine.
|
||||
have Node.js installed, or node isn't identified as Node.js on your machine.
|
||||
If it's the latter, entering `sudo ln -s /usr/bin/nodejs /usr/bin/node` into
|
||||
your terminal may fix the issue.
|
||||
|
||||
|
||||
@@ -66,6 +66,19 @@ If none of this works, do install Github for Windows and use its Git shell. Make
|
||||
* https://github.com/TooTallNate/node-gyp/issues/297
|
||||
* https://code.google.com/p/gyp/issues/detail?id=393
|
||||
|
||||
* `script/build` stops at installing runas with 'Failed at the runas@0.5.4 install script.'
|
||||
|
||||
See the next item.
|
||||
|
||||
* `error MSB8020: The build tools for Visual Studio 2010 (Platform Toolset = 'v100') cannot be found.`
|
||||
|
||||
* If you're building atom with Visual Studio 2013 try executing the following
|
||||
command in your Git shell and then re-run `script/build`:
|
||||
|
||||
```
|
||||
$env:GYP_MSVS_VERSION=2013
|
||||
```
|
||||
|
||||
* Other `node-gyp` errors on first build attempt, even though the right node 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.
|
||||
|
||||
|
||||
@@ -12,7 +12,6 @@
|
||||
# Sublime Parity
|
||||
'tab': 'editor:indent'
|
||||
'enter': 'editor:newline'
|
||||
'num-enter': 'editor:newline'
|
||||
'shift-tab': 'editor:outdent-selected-rows'
|
||||
'ctrl-K': 'editor:delete-line'
|
||||
|
||||
@@ -27,7 +26,6 @@
|
||||
'tab': 'core:focus-next'
|
||||
'shift-tab': 'core:focus-previous'
|
||||
'enter': 'native!'
|
||||
'num-enter': 'native!'
|
||||
'backspace': 'native!'
|
||||
'shift-backspace': 'native!'
|
||||
'delete': 'native!'
|
||||
|
||||
@@ -21,7 +21,6 @@
|
||||
'cmd-O': 'application:open-dev'
|
||||
'cmd-alt-ctrl-s': 'application:run-all-specs'
|
||||
'enter': 'core:confirm'
|
||||
'num-enter': 'core:confirm'
|
||||
'escape': 'core:cancel'
|
||||
'up': 'core:move-up'
|
||||
'down': 'core:move-down'
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
'body':
|
||||
# Atom Specific
|
||||
'enter': 'core:confirm'
|
||||
'num-enter': 'core:confirm'
|
||||
'escape': 'core:cancel'
|
||||
'up': 'core:move-up'
|
||||
'down': 'core:move-down'
|
||||
|
||||
@@ -5,7 +5,6 @@
|
||||
|
||||
# Atom Specific
|
||||
'enter': 'core:confirm'
|
||||
'num-enter': 'core:confirm'
|
||||
'escape': 'core:cancel'
|
||||
'up': 'core:move-up'
|
||||
'down': 'core:move-down'
|
||||
|
||||
+35
-35
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "atom",
|
||||
"productName": "Atom",
|
||||
"version": "0.121.0",
|
||||
"version": "0.122.0",
|
||||
"description": "A hackable text editor for the 21st Century.",
|
||||
"main": "./src/browser/main.js",
|
||||
"repository": {
|
||||
@@ -17,22 +17,22 @@
|
||||
"url": "http://github.com/atom/atom/raw/master/LICENSE.md"
|
||||
}
|
||||
],
|
||||
"atomShellVersion": "0.15.0",
|
||||
"atomShellVersion": "0.15.6",
|
||||
"dependencies": {
|
||||
"async": "0.2.6",
|
||||
"atom-keymap": "^1.0.0",
|
||||
"atom-keymap": "^2.0.1",
|
||||
"bootstrap": "git+https://github.com/atom/bootstrap.git#6af81906189f1747fd6c93479e3d998ebe041372",
|
||||
"clear-cut": "0.4.0",
|
||||
"coffee-script": "1.7.0",
|
||||
"coffeestack": "0.7.0",
|
||||
"delegato": "^1",
|
||||
"emissary": "^1.2.1",
|
||||
"emissary": "^1.2.2",
|
||||
"first-mate": "^2.0.1",
|
||||
"fs-plus": "^2.2.6",
|
||||
"fstream": "0.1.24",
|
||||
"fuzzaldrin": "^1.1",
|
||||
"git-utils": "^2.1.3",
|
||||
"grim": "0.11.0",
|
||||
"git-utils": "^2.1.4",
|
||||
"grim": "0.12.0",
|
||||
"guid": "0.0.10",
|
||||
"jasmine-tagged": "^1.1.2",
|
||||
"less-cache": "0.13.0",
|
||||
@@ -50,13 +50,13 @@
|
||||
"runas": "1.0.1",
|
||||
"scandal": "1.0.0",
|
||||
"scoped-property-store": "^0.9.0",
|
||||
"scrollbar-style": "^1.0.1",
|
||||
"scrollbar-style": "^1.0.2",
|
||||
"season": "^1.0.2",
|
||||
"semver": "1.1.4",
|
||||
"serializable": "^1",
|
||||
"space-pen": "3.2.0",
|
||||
"temp": "0.7.0",
|
||||
"text-buffer": "^3.0.0",
|
||||
"text-buffer": "^3.0.1",
|
||||
"theorist": "^1",
|
||||
"underscore-plus": "^1.5.1",
|
||||
"vm-compatibility-layer": "0.1.0"
|
||||
@@ -66,43 +66,43 @@
|
||||
"atom-dark-ui": "0.33.0",
|
||||
"atom-light-syntax": "0.20.0",
|
||||
"atom-light-ui": "0.29.0",
|
||||
"base16-tomorrow-dark-theme": "0.20.0",
|
||||
"base16-tomorrow-dark-theme": "0.21.0",
|
||||
"base16-tomorrow-light-theme": "0.4.0",
|
||||
"solarized-dark-syntax": "0.22.0",
|
||||
"solarized-light-syntax": "0.12.0",
|
||||
"archive-view": "0.35.0",
|
||||
"autocomplete": "0.29.0",
|
||||
"archive-view": "0.36.0",
|
||||
"autocomplete": "0.31.0",
|
||||
"autoflow": "0.17.0",
|
||||
"autosave": "0.14.0",
|
||||
"autosave": "0.15.0",
|
||||
"background-tips": "0.15.0",
|
||||
"bookmarks": "0.27.0",
|
||||
"bracket-matcher": "0.51.0",
|
||||
"bracket-matcher": "0.54.0",
|
||||
"command-palette": "0.24.0",
|
||||
"deprecation-cop": "0.7.0",
|
||||
"dev-live-reload": "0.33.0",
|
||||
"exception-reporting": "0.19.0",
|
||||
"deprecation-cop": "0.9.0",
|
||||
"dev-live-reload": "0.34.0",
|
||||
"exception-reporting": "0.20.0",
|
||||
"feedback": "0.33.0",
|
||||
"find-and-replace": "0.127.0",
|
||||
"find-and-replace": "0.128.0",
|
||||
"fuzzy-finder": "0.57.0",
|
||||
"git-diff": "0.37.0",
|
||||
"go-to-line": "0.23.0",
|
||||
"go-to-line": "0.24.0",
|
||||
"grammar-selector": "0.27.0",
|
||||
"image-view": "0.36.0",
|
||||
"incompatible-packages": "0.3.0",
|
||||
"keybinding-resolver": "0.18.0",
|
||||
"incompatible-packages": "0.8.0",
|
||||
"keybinding-resolver": "0.19.0",
|
||||
"link": "0.25.0",
|
||||
"markdown-preview": "0.94.0",
|
||||
"markdown-preview": "0.99.0",
|
||||
"metrics": "0.33.0",
|
||||
"open-on-github": "0.29.0",
|
||||
"package-generator": "0.31.0",
|
||||
"release-notes": "0.36.0",
|
||||
"settings-view": "0.137.0",
|
||||
"snippets": "0.50.0",
|
||||
"spell-check": "0.40.0",
|
||||
"status-bar": "0.41.0",
|
||||
"settings-view": "0.139.0",
|
||||
"snippets": "0.51.0",
|
||||
"spell-check": "0.41.0",
|
||||
"status-bar": "0.42.0",
|
||||
"styleguide": "0.29.0",
|
||||
"symbols-view": "0.63.0",
|
||||
"tabs": "0.48.0",
|
||||
"tabs": "0.49.0",
|
||||
"timecop": "0.22.0",
|
||||
"tree-view": "0.112.0",
|
||||
"update-package-dependencies": "0.6.0",
|
||||
@@ -110,13 +110,13 @@
|
||||
"whitespace": "0.25.0",
|
||||
"wrap-guide": "0.21.0",
|
||||
|
||||
"language-c": "0.26.0",
|
||||
"language-coffee-script": "0.27.0",
|
||||
"language-c": "0.27.0",
|
||||
"language-coffee-script": "0.29.0",
|
||||
"language-css": "0.17.0",
|
||||
"language-gfm": "0.44.0",
|
||||
"language-gfm": "0.46.0",
|
||||
"language-git": "0.9.0",
|
||||
"language-go": "0.16.0",
|
||||
"language-html": "0.22.0",
|
||||
"language-html": "0.24.0",
|
||||
"language-hyperlink": "0.10.0",
|
||||
"language-java": "0.11.0",
|
||||
"language-javascript": "0.39.0",
|
||||
@@ -128,17 +128,17 @@
|
||||
"language-php": "0.15.0",
|
||||
"language-property-list": "0.7.0",
|
||||
"language-python": "0.18.0",
|
||||
"language-ruby": "0.33.0",
|
||||
"language-ruby": "0.34.0",
|
||||
"language-ruby-on-rails": "0.15.0",
|
||||
"language-sass": "0.14.0",
|
||||
"language-sass": "0.16.0",
|
||||
"language-shellscript": "0.8.0",
|
||||
"language-source": "0.8.0",
|
||||
"language-sql": "0.9.0",
|
||||
"language-sql": "0.10.0",
|
||||
"language-text": "0.6.0",
|
||||
"language-todo": "0.10.0",
|
||||
"language-toml": "0.12.0",
|
||||
"language-xml": "0.17.0",
|
||||
"language-yaml": "0.13.0"
|
||||
"language-xml": "0.18.0",
|
||||
"language-yaml": "0.15.0"
|
||||
},
|
||||
"private": true,
|
||||
"scripts": {
|
||||
|
||||
Arquivo binário não exibido.
Arquivo binário não exibido.
@@ -23,6 +23,18 @@ describe "Config", ->
|
||||
retrievedValue.array[1].b = 2.1
|
||||
expect(atom.config.get('value')).toEqual(array: [1, b: 2, 3])
|
||||
|
||||
it "merges defaults into the returned value if both the assigned value and the default value are objects", ->
|
||||
atom.config.setDefaults("foo", a: 1, b: 2)
|
||||
atom.config.set("foo", a: 3)
|
||||
expect(atom.config.get("foo")).toEqual {a: 3, b: 2}
|
||||
|
||||
atom.config.set("foo", 7)
|
||||
expect(atom.config.get("foo")).toBe 7
|
||||
|
||||
atom.config.set("bar.baz", a: 3)
|
||||
atom.config.setDefaults("bar", baz: 7)
|
||||
expect(atom.config.get("bar.baz")).toEqual {a: 3}
|
||||
|
||||
describe ".set(keyPath, value)", ->
|
||||
it "allows a key path's value to be written", ->
|
||||
expect(atom.config.set("foo.bar.baz", 42)).toBe 42
|
||||
|
||||
@@ -209,25 +209,32 @@ describe "EditorComponent", ->
|
||||
|
||||
atom.config.set("editor.showInvisibles", true)
|
||||
atom.config.set("editor.invisibles", invisibles)
|
||||
nextAnimationFrame()
|
||||
|
||||
it "re-renders the lines when the showInvisibles config option changes", ->
|
||||
editor.setText " a line with tabs\tand spaces "
|
||||
editor.setText " a line with tabs\tand spaces \n"
|
||||
nextAnimationFrame()
|
||||
expect(component.lineNodeForScreenRow(0).textContent).toBe "#{invisibles.space}a line with tabs#{invisibles.tab}and spaces#{invisibles.space}#{invisibles.eol}"
|
||||
|
||||
atom.config.set("editor.showInvisibles", false)
|
||||
nextAnimationFrame()
|
||||
expect(component.lineNodeForScreenRow(0).textContent).toBe " a line with tabs and spaces "
|
||||
|
||||
atom.config.set("editor.showInvisibles", true)
|
||||
expect(component.lineNodeForScreenRow(0).textContent).toBe "#{invisibles.space}a line with tabs#{invisibles.tab}and spaces#{invisibles.space}#{invisibles.eol}"
|
||||
|
||||
it "displays spaces, tabs, and newlines as visible characters", ->
|
||||
editor.setText " a line with tabs\tand spaces "
|
||||
nextAnimationFrame()
|
||||
expect(component.lineNodeForScreenRow(0).textContent).toBe "#{invisibles.space}a line with tabs#{invisibles.tab}and spaces#{invisibles.space}#{invisibles.eol}"
|
||||
|
||||
it "displays leading/trailing spaces, tabs, and newlines as visible characters", ->
|
||||
editor.setText " a line with tabs\tand spaces \n"
|
||||
nextAnimationFrame()
|
||||
expect(component.lineNodeForScreenRow(0).textContent).toBe "#{invisibles.space}a line with tabs#{invisibles.tab}and spaces#{invisibles.space}#{invisibles.eol}"
|
||||
|
||||
leafNodes = getLeafNodes(component.lineNodeForScreenRow(0))
|
||||
expect(leafNodes[0].classList.contains('invisible-character')).toBe true
|
||||
expect(leafNodes[leafNodes.length - 1].classList.contains('invisible-character')).toBe true
|
||||
|
||||
it "displays newlines as their own token outside of the other tokens' scopes", ->
|
||||
editor.setText "var"
|
||||
editor.setText "var\n"
|
||||
nextAnimationFrame()
|
||||
expect(component.lineNodeForScreenRow(0).innerHTML).toBe "<span class=\"source js\"><span class=\"storage modifier js\">var</span></span><span class=\"invisible-character\">#{invisibles.eol}</span>"
|
||||
|
||||
@@ -241,10 +248,12 @@ describe "EditorComponent", ->
|
||||
|
||||
it "renders an nbsp on empty lines when the line-ending character is an empty string", ->
|
||||
atom.config.set("editor.invisibles", eol: '')
|
||||
nextAnimationFrame()
|
||||
expect(component.lineNodeForScreenRow(10).textContent).toBe nbsp
|
||||
|
||||
it "renders an nbsp on empty lines when no line-ending character is defined", ->
|
||||
atom.config.set("editor.invisibles", eol: null)
|
||||
it "renders an nbsp on empty lines when the line-ending character is false", ->
|
||||
atom.config.set("editor.invisibles", eol: false)
|
||||
nextAnimationFrame()
|
||||
expect(component.lineNodeForScreenRow(10).textContent).toBe nbsp
|
||||
|
||||
it "interleaves invisible line-ending characters with indent guides on empty lines", ->
|
||||
@@ -268,7 +277,7 @@ describe "EditorComponent", ->
|
||||
|
||||
describe "when soft wrapping is enabled", ->
|
||||
beforeEach ->
|
||||
editor.setText "a line that wraps "
|
||||
editor.setText "a line that wraps \n"
|
||||
editor.setSoftWrap(true)
|
||||
nextAnimationFrame()
|
||||
componentNode.style.width = 16 * charWidth + editor.getVerticalScrollbarWidth() + 'px'
|
||||
@@ -2103,9 +2112,13 @@ describe "EditorComponent", ->
|
||||
it "adds the 'mini' class to the wrapper view", ->
|
||||
expect(wrapperNode.classList.contains('mini')).toBe true
|
||||
|
||||
it "does not have an opaque background on lines", ->
|
||||
expect(component.refs.lines.getDOMNode().getAttribute('style')).not.toContain 'background-color'
|
||||
|
||||
it "does not render invisible characters", ->
|
||||
component.setInvisibles(eol: 'E')
|
||||
component.setShowInvisibles(true)
|
||||
atom.config.set('editor.invisibles', eol: 'E')
|
||||
atom.config.set('editor.showInvisibles', true)
|
||||
nextAnimationFrame()
|
||||
expect(component.lineNodeForScreenRow(0).textContent).toBe 'var quicksort = function () {'
|
||||
|
||||
it "does not assign an explicit line-height on the editor contents", ->
|
||||
|
||||
@@ -499,6 +499,15 @@ describe "Editor", ->
|
||||
cursor = editor.getCursor()
|
||||
expect(cursor.getBufferPosition()).toEqual [1,0]
|
||||
|
||||
describe "when invisible characters are enabled", ->
|
||||
it "moves to the first character of the current line without being confused by the invisible characters", ->
|
||||
atom.config.set('editor.showInvisibles', true)
|
||||
editor.setCursorScreenPosition [1,7]
|
||||
editor.moveCursorToFirstCharacterOfLine()
|
||||
expect(editor.getCursorBufferPosition()).toEqual [1,2]
|
||||
editor.moveCursorToFirstCharacterOfLine()
|
||||
expect(editor.getCursorBufferPosition()).toEqual [1,0]
|
||||
|
||||
describe ".moveCursorToBeginningOfWord()", ->
|
||||
it "moves the cursor to the beginning of the word", ->
|
||||
editor.setCursorBufferPosition [0, 8]
|
||||
@@ -1470,6 +1479,15 @@ describe "Editor", ->
|
||||
|
||||
describe "buffer manipulation", ->
|
||||
describe ".insertText(text)", ->
|
||||
describe "when there is a single selection", ->
|
||||
beforeEach ->
|
||||
editor.setSelectedBufferRange([[1, 0], [1, 2]])
|
||||
|
||||
it "will-insert-text and did-insert-text events are emitted when inserting text", ->
|
||||
range = editor.insertText('xxx')
|
||||
expect(range).toEqual [ [[1, 0], [1, 3]] ]
|
||||
expect(buffer.lineForRow(1)).toBe 'xxxvar sort = function(items) {'
|
||||
|
||||
describe "when there are multiple empty selections", ->
|
||||
describe "when the cursors are on the same line", ->
|
||||
it "inserts the given text at the location of each cursor and moves the cursors to the end of each cursor's inserted text", ->
|
||||
@@ -1547,6 +1565,48 @@ describe "Editor", ->
|
||||
editor.insertText('holy cow')
|
||||
expect(editor.lineForScreenRow(2).fold).toBeUndefined()
|
||||
|
||||
describe "when will-insert-text and did-insert-text events are used", ->
|
||||
beforeEach ->
|
||||
editor.setSelectedBufferRange([[1, 0], [1, 2]])
|
||||
|
||||
it "will-insert-text and did-insert-text events are emitted when inserting text", ->
|
||||
willInsertSpy = jasmine.createSpy().andCallFake ->
|
||||
expect(buffer.lineForRow(1)).toBe ' var sort = function(items) {'
|
||||
|
||||
didInsertSpy = jasmine.createSpy().andCallFake ->
|
||||
expect(buffer.lineForRow(1)).toBe 'xxxvar sort = function(items) {'
|
||||
|
||||
editor.on('will-insert-text', willInsertSpy)
|
||||
editor.on('did-insert-text', didInsertSpy)
|
||||
|
||||
expect(editor.insertText('xxx')).toBeTruthy()
|
||||
expect(buffer.lineForRow(1)).toBe 'xxxvar sort = function(items) {'
|
||||
|
||||
expect(willInsertSpy).toHaveBeenCalled()
|
||||
expect(didInsertSpy).toHaveBeenCalled()
|
||||
|
||||
options = willInsertSpy.mostRecentCall.args[0]
|
||||
expect(options.text).toBe 'xxx'
|
||||
expect(options.cancel).toBeDefined()
|
||||
|
||||
options = didInsertSpy.mostRecentCall.args[0]
|
||||
expect(options.text).toBe 'xxx'
|
||||
|
||||
it "text insertion is prevented when cancel is called from a will-insert-text handler", ->
|
||||
willInsertSpy = jasmine.createSpy().andCallFake ({cancel}) ->
|
||||
cancel()
|
||||
|
||||
didInsertSpy = jasmine.createSpy()
|
||||
|
||||
editor.on('will-insert-text', willInsertSpy)
|
||||
editor.on('did-insert-text', didInsertSpy)
|
||||
|
||||
expect(editor.insertText('xxx')).toBe false
|
||||
expect(buffer.lineForRow(1)).toBe ' var sort = function(items) {'
|
||||
|
||||
expect(willInsertSpy).toHaveBeenCalled()
|
||||
expect(didInsertSpy).not.toHaveBeenCalled()
|
||||
|
||||
describe ".insertNewline()", ->
|
||||
describe "when there is a single cursor", ->
|
||||
describe "when the cursor is at the beginning of a line", ->
|
||||
@@ -3301,20 +3361,25 @@ describe "Editor", ->
|
||||
expect(editor.getText()).toBe ' '
|
||||
|
||||
describe ".scrollToCursorPosition()", ->
|
||||
it "scrolls the last cursor into view", ->
|
||||
it "scrolls the last cursor into view, centering around the cursor if possible and the 'center' option isn't false", ->
|
||||
editor.setCursorScreenPosition([8, 8])
|
||||
editor.setLineHeightInPixels(10)
|
||||
editor.setDefaultCharWidth(10)
|
||||
editor.setHeight(50)
|
||||
editor.setHeight(60)
|
||||
editor.setWidth(50)
|
||||
editor.setHorizontalScrollbarHeight(0)
|
||||
expect(editor.getScrollTop()).toBe 0
|
||||
expect(editor.getScrollLeft()).toBe 0
|
||||
|
||||
editor.scrollToCursorPosition()
|
||||
expect(editor.getScrollBottom()).toBe (9 + editor.getVerticalScrollMargin()) * 10
|
||||
expect(editor.getScrollTop()).toBe (8.5 * 10) - 30
|
||||
expect(editor.getScrollBottom()).toBe (8.5 * 10) + 30
|
||||
expect(editor.getScrollRight()).toBe (9 + editor.getHorizontalScrollMargin()) * 10
|
||||
|
||||
editor.setScrollTop(0)
|
||||
editor.scrollToCursorPosition(center: false)
|
||||
expect(editor.getScrollBottom()).toBe (9 + editor.getVerticalScrollMargin()) * 10
|
||||
|
||||
describe ".pageUp/Down()", ->
|
||||
it "scrolls one screen height up or down and moves the cursor one page length", ->
|
||||
editor.manageScrollPosition = true
|
||||
|
||||
@@ -2414,37 +2414,6 @@ describe "EditorView", ->
|
||||
expect(editor.getCursor().getScreenPosition().row).toBe(0)
|
||||
expect(editorView.getFirstVisibleScreenRow()).toBe(0)
|
||||
|
||||
describe ".checkoutHead()", ->
|
||||
[filePath] = []
|
||||
|
||||
beforeEach ->
|
||||
workingDirPath = temp.mkdirSync('atom-working-dir')
|
||||
fs.copySync(path.join(__dirname, 'fixtures', 'git', 'working-dir'), workingDirPath)
|
||||
fs.renameSync(path.join(workingDirPath, 'git.git'), path.join(workingDirPath, '.git'))
|
||||
atom.project.setPath(workingDirPath)
|
||||
filePath = atom.project.resolve('file.txt')
|
||||
|
||||
waitsForPromise ->
|
||||
atom.workspace.open(filePath).then (o) -> editor = o
|
||||
|
||||
runs ->
|
||||
editorView.edit(editor)
|
||||
|
||||
it "restores the contents of the editor view to the HEAD revision", ->
|
||||
editor.setText('')
|
||||
editor.save()
|
||||
|
||||
fileChangeHandler = jasmine.createSpy('fileChange')
|
||||
editor.getBuffer().file.on 'contents-changed', fileChangeHandler
|
||||
|
||||
editorView.checkoutHead()
|
||||
|
||||
waitsFor "file to trigger contents-changed event", ->
|
||||
fileChangeHandler.callCount > 0
|
||||
|
||||
runs ->
|
||||
expect(editor.getText()).toBe('undefined')
|
||||
|
||||
describe ".pixelPositionForBufferPosition(position)", ->
|
||||
describe "when the editor view is detached", ->
|
||||
it "returns top and left values of 0", ->
|
||||
@@ -2998,8 +2967,8 @@ describe "EditorView", ->
|
||||
expect(editorView.lineElementForScreenRow(rowNumber).text()).toBe buffer.lineForRow(rowNumber)
|
||||
|
||||
it "correctly calculates the position left for non-monospaced invisibles", ->
|
||||
editorView.setShowInvisibles(true)
|
||||
editorView.setInvisibles tab: '♘'
|
||||
atom.config.set('editor.showInvisibles', true)
|
||||
atom.config.set('editor.invisibles', tab: '♘')
|
||||
editor.setText('\tx')
|
||||
|
||||
editorView.setFontFamily('serif')
|
||||
|
||||
@@ -119,6 +119,38 @@ describe "Git", ->
|
||||
repo.checkoutHead(filePath)
|
||||
expect(statusHandler.callCount).toBe 1
|
||||
|
||||
describe ".checkoutHeadForEditor(editor)", ->
|
||||
[filePath, editor] = []
|
||||
|
||||
beforeEach ->
|
||||
workingDirPath = copyRepository()
|
||||
repo = new Git(workingDirPath)
|
||||
filePath = path.join(workingDirPath, 'a.txt')
|
||||
fs.writeFileSync(filePath, 'ch ch changes')
|
||||
|
||||
waitsForPromise ->
|
||||
atom.workspace.open(filePath)
|
||||
|
||||
runs ->
|
||||
editor = atom.workspace.getActiveEditor()
|
||||
|
||||
it "displays a confirmation dialog by default", ->
|
||||
spyOn(atom, 'confirm').andCallFake ({buttons}) -> buttons.OK()
|
||||
atom.config.set('editor.confirmCheckoutHeadRevision', true)
|
||||
|
||||
repo.checkoutHeadForEditor(editor)
|
||||
|
||||
expect(fs.readFileSync(filePath, 'utf8')).toBe ''
|
||||
|
||||
it "does not display a dialog when confirmation is disabled", ->
|
||||
spyOn(atom, 'confirm')
|
||||
atom.config.set('editor.confirmCheckoutHeadRevision', false)
|
||||
|
||||
repo.checkoutHeadForEditor(editor)
|
||||
|
||||
expect(fs.readFileSync(filePath, 'utf8')).toBe ''
|
||||
expect(atom.confirm).not.toHaveBeenCalled()
|
||||
|
||||
describe ".destroy()", ->
|
||||
it "throws an exception when any method is called after it is called", ->
|
||||
repo = new Git(require.resolve('./fixtures/git/master.git/HEAD'))
|
||||
|
||||
@@ -5,6 +5,9 @@ ThemePackage = require '../src/theme-package'
|
||||
|
||||
describe "Package", ->
|
||||
describe "when the package contains incompatible native modules", ->
|
||||
beforeEach ->
|
||||
spyOn(atom, 'inDevMode').andReturn(false)
|
||||
|
||||
it "does not activate it", ->
|
||||
packagePath = atom.project.resolve('packages/package-with-incompatible-native-module')
|
||||
pack = new Package(packagePath)
|
||||
|
||||
@@ -28,7 +28,7 @@ atom.keymaps.loadBundledKeymaps()
|
||||
keyBindingsToRestore = atom.keymaps.getKeyBindings()
|
||||
|
||||
$(window).on 'core:close', -> window.close()
|
||||
$(window).on 'unload', ->
|
||||
$(window).on 'beforeunload', ->
|
||||
atom.storeWindowDimensions()
|
||||
atom.saveSync()
|
||||
$('html,body').css('overflow', 'auto')
|
||||
@@ -211,6 +211,13 @@ addCustomMatchers = (spec) ->
|
||||
element = element.get(0) if element.jquery
|
||||
element.webkitMatchesSelector(":focus") or element.querySelector(":focus")
|
||||
|
||||
toShow: ->
|
||||
notText = if @isNot then " not" else ""
|
||||
element = @actual
|
||||
element = element.get(0) if element.jquery
|
||||
@message = -> return "Expected element '#{element}' or its descendants #{notText} to show."
|
||||
element.style.display in ['block', 'inline-block', 'static', 'fixed']
|
||||
|
||||
window.keyIdentifierForKey = (key) ->
|
||||
if key.length > 1 # named key
|
||||
key
|
||||
|
||||
@@ -310,3 +310,59 @@ describe "ThemeManager", ->
|
||||
runs ->
|
||||
expect(console.warn.callCount).toBe 1
|
||||
expect(console.warn.argsForCall[0][0].length).toBeGreaterThan 0
|
||||
|
||||
describe "when in safe mode", ->
|
||||
beforeEach ->
|
||||
themeManager = new ThemeManager({packageManager: atom.packages, resourcePath, configDirPath, safeMode: true})
|
||||
|
||||
describe 'when the enabled UI and syntax themes are bundled with Atom', ->
|
||||
beforeEach ->
|
||||
atom.config.set('core.themes', ['atom-light-ui', 'atom-dark-syntax'])
|
||||
|
||||
waitsForPromise ->
|
||||
themeManager.activateThemes()
|
||||
|
||||
it 'uses the enabled themes', ->
|
||||
activeThemeNames = themeManager.getActiveNames()
|
||||
expect(activeThemeNames.length).toBe(2)
|
||||
expect(activeThemeNames).toContain('atom-light-ui')
|
||||
expect(activeThemeNames).toContain('atom-dark-syntax')
|
||||
|
||||
describe 'when the enabled UI and syntax themes are not bundled with Atom', ->
|
||||
beforeEach ->
|
||||
atom.config.set('core.themes', ['installed-dark-ui', 'installed-dark-syntax'])
|
||||
|
||||
waitsForPromise ->
|
||||
themeManager.activateThemes()
|
||||
|
||||
it 'uses the default dark UI and syntax themes', ->
|
||||
activeThemeNames = themeManager.getActiveNames()
|
||||
expect(activeThemeNames.length).toBe(2)
|
||||
expect(activeThemeNames).toContain('atom-dark-ui')
|
||||
expect(activeThemeNames).toContain('atom-dark-syntax')
|
||||
|
||||
describe 'when the enabled UI theme is not bundled with Atom', ->
|
||||
beforeEach ->
|
||||
atom.config.set('core.themes', ['installed-dark-ui', 'atom-light-syntax'])
|
||||
|
||||
waitsForPromise ->
|
||||
themeManager.activateThemes()
|
||||
|
||||
it 'uses the default dark UI theme', ->
|
||||
activeThemeNames = themeManager.getActiveNames()
|
||||
expect(activeThemeNames.length).toBe(2)
|
||||
expect(activeThemeNames).toContain('atom-dark-ui')
|
||||
expect(activeThemeNames).toContain('atom-light-syntax')
|
||||
|
||||
describe 'when the enabled syntax theme is not bundled with Atom', ->
|
||||
beforeEach ->
|
||||
atom.config.set('core.themes', ['atom-light-ui', 'installed-dark-syntax'])
|
||||
|
||||
waitsForPromise ->
|
||||
themeManager.activateThemes()
|
||||
|
||||
it 'uses the default dark syntax theme', ->
|
||||
activeThemeNames = themeManager.getActiveNames()
|
||||
expect(activeThemeNames.length).toBe(2)
|
||||
expect(activeThemeNames).toContain('atom-light-ui')
|
||||
expect(activeThemeNames).toContain('atom-dark-syntax')
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
TokenizedBuffer = require '../src/tokenized-buffer'
|
||||
TextBuffer = require 'text-buffer'
|
||||
_ = require 'underscore-plus'
|
||||
|
||||
describe "TokenizedBuffer", ->
|
||||
@@ -12,6 +13,9 @@ describe "TokenizedBuffer", ->
|
||||
waitsForPromise ->
|
||||
atom.packages.activatePackage('language-javascript')
|
||||
|
||||
afterEach ->
|
||||
tokenizedBuffer?.destroy()
|
||||
|
||||
startTokenizing = (tokenizedBuffer) ->
|
||||
tokenizedBuffer.setVisible(true)
|
||||
|
||||
@@ -584,42 +588,95 @@ describe "TokenizedBuffer", ->
|
||||
atom.config.set('editor.tabLength', 0)
|
||||
expect(tokenizedBuffer.tokenForPosition([0,0]).value).toBe ' '
|
||||
|
||||
describe "when the invisibles value changes", ->
|
||||
beforeEach ->
|
||||
|
||||
it "updates the tokens with the appropriate invisible characters", ->
|
||||
buffer = new TextBuffer(text: " \t a line with tabs\tand \tspaces \t ")
|
||||
tokenizedBuffer = new TokenizedBuffer({buffer})
|
||||
fullyTokenize(tokenizedBuffer)
|
||||
|
||||
tokenizedBuffer.setInvisibles(space: 'S', tab: 'T')
|
||||
fullyTokenize(tokenizedBuffer)
|
||||
|
||||
expect(tokenizedBuffer.lineForScreenRow(0).text).toBe "SST Sa line with tabsTand T spacesSTS"
|
||||
# Also needs to work for copies
|
||||
expect(tokenizedBuffer.lineForScreenRow(0).copy().text).toBe "SST Sa line with tabsTand T spacesSTS"
|
||||
|
||||
it "assigns endOfLineInvisibles to tokenized lines", ->
|
||||
buffer = new TextBuffer(text: "a line that ends in a carriage-return-line-feed \r\na line that ends in just a line-feed\na line with no ending")
|
||||
tokenizedBuffer = new TokenizedBuffer({buffer})
|
||||
|
||||
atom.config.set('editor.showInvisibles', true)
|
||||
tokenizedBuffer.setInvisibles(cr: 'R', eol: 'N')
|
||||
fullyTokenize(tokenizedBuffer)
|
||||
|
||||
expect(tokenizedBuffer.lineForScreenRow(0).endOfLineInvisibles).toEqual ['R', 'N']
|
||||
expect(tokenizedBuffer.lineForScreenRow(1).endOfLineInvisibles).toEqual ['N']
|
||||
|
||||
# Lines ending in soft wraps get no invisibles
|
||||
[left, right] = tokenizedBuffer.lineForScreenRow(0).softWrapAt(20)
|
||||
expect(left.endOfLineInvisibles).toBe null
|
||||
expect(right.endOfLineInvisibles).toEqual ['R', 'N']
|
||||
|
||||
tokenizedBuffer.setInvisibles(cr: 'R', eol: false)
|
||||
expect(tokenizedBuffer.lineForScreenRow(0).endOfLineInvisibles).toEqual ['R']
|
||||
expect(tokenizedBuffer.lineForScreenRow(1).endOfLineInvisibles).toEqual []
|
||||
|
||||
describe "leading and trailing whitespace", ->
|
||||
beforeEach ->
|
||||
buffer = atom.project.bufferForPathSync('sample.js')
|
||||
tokenizedBuffer = new TokenizedBuffer({buffer})
|
||||
fullyTokenize(tokenizedBuffer)
|
||||
|
||||
it "sets ::hasLeadingWhitespace to true on tokens that have leading whitespace", ->
|
||||
it "sets ::hasLeadingWhitespace to true and assigns ::firstNonWhitespaceIndex on tokens that have leading whitespace", ->
|
||||
expect(tokenizedBuffer.lineForScreenRow(0).tokens[0].hasLeadingWhitespace).toBe false
|
||||
expect(tokenizedBuffer.lineForScreenRow(0).tokens[0].firstNonWhitespaceIndex).toBe null
|
||||
|
||||
expect(tokenizedBuffer.lineForScreenRow(1).tokens[0].hasLeadingWhitespace).toBe true
|
||||
expect(tokenizedBuffer.lineForScreenRow(1).tokens[0].firstNonWhitespaceIndex).toBe 2
|
||||
|
||||
expect(tokenizedBuffer.lineForScreenRow(1).tokens[1].hasLeadingWhitespace).toBe false
|
||||
expect(tokenizedBuffer.lineForScreenRow(1).tokens[1].firstNonWhitespaceIndex).toBe null
|
||||
|
||||
expect(tokenizedBuffer.lineForScreenRow(2).tokens[0].hasLeadingWhitespace).toBe true
|
||||
expect(tokenizedBuffer.lineForScreenRow(2).tokens[0].firstNonWhitespaceIndex).toBe 2
|
||||
expect(tokenizedBuffer.lineForScreenRow(2).tokens[1].hasLeadingWhitespace).toBe true
|
||||
expect(tokenizedBuffer.lineForScreenRow(2).tokens[1].firstNonWhitespaceIndex).toBe 2
|
||||
expect(tokenizedBuffer.lineForScreenRow(2).tokens[2].hasLeadingWhitespace).toBe false
|
||||
expect(tokenizedBuffer.lineForScreenRow(2).tokens[2].firstNonWhitespaceIndex).toBe null
|
||||
|
||||
# The 4th token *has* leading whitespace, but isn't entirely whitespace
|
||||
buffer.insert([5, 0], ' ')
|
||||
expect(tokenizedBuffer.lineForScreenRow(5).tokens[3].hasLeadingWhitespace).toBe true
|
||||
expect(tokenizedBuffer.lineForScreenRow(5).tokens[3].firstNonWhitespaceIndex).toBe 1
|
||||
expect(tokenizedBuffer.lineForScreenRow(5).tokens[4].hasLeadingWhitespace).toBe false
|
||||
expect(tokenizedBuffer.lineForScreenRow(5).tokens[4].firstNonWhitespaceIndex).toBe null
|
||||
|
||||
# Lines that are *only* whitespace are not considered to have leading whitespace
|
||||
buffer.insert([10, 0], ' ')
|
||||
expect(tokenizedBuffer.lineForScreenRow(10).tokens[0].hasLeadingWhitespace).toBe false
|
||||
expect(tokenizedBuffer.lineForScreenRow(10).tokens[0].firstNonWhitespaceIndex).toBe null
|
||||
|
||||
it "sets ::hasTrailingWhitespace to true on tokens that have trailing whitespace", ->
|
||||
it "sets ::hasTrailingWhitespace to true and assigns ::firstTrailingWhitespaceIndex on tokens that have trailing whitespace", ->
|
||||
buffer.insert([0, Infinity], ' ')
|
||||
expect(tokenizedBuffer.lineForScreenRow(0).tokens[11].hasTrailingWhitespace).toBe false
|
||||
expect(tokenizedBuffer.lineForScreenRow(0).tokens[11].firstTrailingWhitespaceIndex).toBe null
|
||||
expect(tokenizedBuffer.lineForScreenRow(0).tokens[12].hasTrailingWhitespace).toBe true
|
||||
expect(tokenizedBuffer.lineForScreenRow(0).tokens[12].firstTrailingWhitespaceIndex).toBe 0
|
||||
|
||||
# The last token *has* trailing whitespace, but isn't entirely whitespace
|
||||
buffer.setTextInRange([[2, 39], [2, 40]], ' ')
|
||||
expect(tokenizedBuffer.lineForScreenRow(2).tokens[14].hasTrailingWhitespace).toBe false
|
||||
expect(tokenizedBuffer.lineForScreenRow(2).tokens[14].firstTrailingWhitespaceIndex).toBe null
|
||||
expect(tokenizedBuffer.lineForScreenRow(2).tokens[15].hasTrailingWhitespace).toBe true
|
||||
console.log tokenizedBuffer.lineForScreenRow(2).tokens[15]
|
||||
expect(tokenizedBuffer.lineForScreenRow(2).tokens[15].firstTrailingWhitespaceIndex).toBe 6
|
||||
|
||||
# Lines that are *only* whitespace are considered to have trailing whitespace
|
||||
buffer.insert([10, 0], ' ')
|
||||
expect(tokenizedBuffer.lineForScreenRow(10).tokens[0].hasTrailingWhitespace).toBe true
|
||||
expect(tokenizedBuffer.lineForScreenRow(10).tokens[0].firstTrailingWhitespaceIndex).toBe 0
|
||||
|
||||
it "only marks trailing whitespace on the last segment of a soft-wrapped line", ->
|
||||
buffer.insert([0, Infinity], ' ')
|
||||
@@ -627,8 +684,20 @@ describe "TokenizedBuffer", ->
|
||||
[segment1, segment2] = tokenizedLine.softWrapAt(16)
|
||||
expect(segment1.tokens[5].value).toBe ' '
|
||||
expect(segment1.tokens[5].hasTrailingWhitespace).toBe false
|
||||
expect(segment1.tokens[5].firstTrailingWhitespaceIndex).toBe null
|
||||
expect(segment2.tokens[6].value).toBe ' '
|
||||
expect(segment2.tokens[6].hasTrailingWhitespace).toBe true
|
||||
expect(segment2.tokens[6].firstTrailingWhitespaceIndex).toBe 0
|
||||
|
||||
it "sets leading and trailing whitespace correctly on a line with invisible characters that is copied", ->
|
||||
buffer.setText(" \t a line with tabs\tand \tspaces \t ")
|
||||
|
||||
tokenizedBuffer.setInvisibles(space: 'S', tab: 'T')
|
||||
fullyTokenize(tokenizedBuffer)
|
||||
|
||||
line = tokenizedBuffer.lineForScreenRow(0).copy()
|
||||
expect(line.tokens[0].hasLeadingWhitespace).toBe true
|
||||
expect(line.tokens[line.tokens.length - 1].hasTrailingWhitespace).toBe true
|
||||
|
||||
describe "indent level", ->
|
||||
beforeEach ->
|
||||
|
||||
@@ -113,6 +113,7 @@ describe "Window", ->
|
||||
expect(atom.state.project).toEqual projectState
|
||||
expect(atom.saveSync).toHaveBeenCalled()
|
||||
|
||||
describe ".removeEditorWindow()", ->
|
||||
it "unsubscribes from all buffers", ->
|
||||
waitsForPromise ->
|
||||
atom.workspace.open("sample.js")
|
||||
@@ -123,7 +124,7 @@ describe "Window", ->
|
||||
pane.splitRight(pane.copyActiveItem())
|
||||
expect(atom.workspaceView.find('.editor').length).toBe 2
|
||||
|
||||
atom.unloadEditorWindow()
|
||||
atom.removeEditorWindow()
|
||||
|
||||
expect(buffer.getSubscriptionCount()).toBe 0
|
||||
|
||||
|
||||
@@ -195,13 +195,12 @@ describe "WorkspaceView", ->
|
||||
atom.workspaceView.height(200)
|
||||
atom.workspaceView.attachToDom()
|
||||
rightEditorView = atom.workspaceView.getActiveView()
|
||||
rightEditorView.getEditor().setText("\t ")
|
||||
rightEditorView.getEditor().setText("\t \n")
|
||||
leftEditorView = rightEditorView.splitLeft()
|
||||
expect(rightEditorView.find(".line:first").text()).toBe " "
|
||||
expect(leftEditorView.find(".line:first").text()).toBe " "
|
||||
|
||||
{invisibles} = rightEditorView.component.state
|
||||
{space, tab, eol} = invisibles
|
||||
{space, tab, eol} = atom.config.get('editor.invisibles')
|
||||
withInvisiblesShowing = "#{tab} #{space}#{space}#{eol}"
|
||||
|
||||
atom.workspaceView.trigger "window:toggle-invisibles"
|
||||
|
||||
+18
-11
@@ -156,7 +156,7 @@ class Atom extends Model
|
||||
@keymaps = new KeymapManager({configDirPath, resourcePath})
|
||||
@keymap = @keymaps # Deprecated
|
||||
@packages = new PackageManager({devMode, configDirPath, resourcePath, safeMode})
|
||||
@themes = new ThemeManager({packageManager: @packages, configDirPath, resourcePath})
|
||||
@themes = new ThemeManager({packageManager: @packages, configDirPath, resourcePath, safeMode})
|
||||
@contextMenu = new ContextMenuManager(devMode)
|
||||
@menu = new MenuManager({resourcePath})
|
||||
@clipboard = new Clipboard()
|
||||
@@ -311,11 +311,6 @@ class Atom extends Model
|
||||
@requireUserInitScript()
|
||||
@menu.update()
|
||||
|
||||
$(window).on 'unload', =>
|
||||
$(document.body).css('visibility', 'hidden')
|
||||
@unloadEditorWindow()
|
||||
false
|
||||
|
||||
@displayWindow()
|
||||
|
||||
unloadEditorWindow: ->
|
||||
@@ -327,13 +322,18 @@ class Atom extends Model
|
||||
@packages.deactivatePackages()
|
||||
@state.packageStates = @packages.packageStates
|
||||
@saveSync()
|
||||
@workspaceView.remove()
|
||||
@workspaceView = null
|
||||
@project.destroy()
|
||||
@windowEventHandler?.unsubscribe()
|
||||
@keymaps.destroy()
|
||||
@windowState = null
|
||||
|
||||
removeEditorWindow: ->
|
||||
return if not @project and not @workspaceView
|
||||
|
||||
@workspaceView?.remove()
|
||||
@workspaceView = null
|
||||
@project?.destroy()
|
||||
@project = null
|
||||
|
||||
@windowEventHandler?.unsubscribe()
|
||||
|
||||
loadThemes: ->
|
||||
@themes.load()
|
||||
|
||||
@@ -451,6 +451,7 @@ class Atom extends Model
|
||||
center: ->
|
||||
ipc.send('call-window-method', 'center')
|
||||
|
||||
|
||||
# Schedule the window to be shown and focused on the next tick.
|
||||
#
|
||||
# This is done in a next tick to prevent a white flicker from occurring
|
||||
@@ -470,6 +471,12 @@ class Atom extends Model
|
||||
app.emit('will-exit')
|
||||
remote.process.exit(status)
|
||||
|
||||
setDocumentEdited: (edited) ->
|
||||
ipc.send('call-window-method', 'setDocumentEdited', edited)
|
||||
|
||||
setRepresentedFilename: (filename) ->
|
||||
ipc.send('call-window-method', 'setRepresentedFilename', filename)
|
||||
|
||||
# Public: Is the current window in development mode?
|
||||
inDevMode: ->
|
||||
@getLoadSettings().devMode
|
||||
|
||||
@@ -135,7 +135,7 @@ class AtomApplication
|
||||
|
||||
# Registers basic application commands, non-idempotent.
|
||||
handleEvents: ->
|
||||
@on 'application:run-all-specs', -> @runSpecs(exitWhenDone: false, resourcePath: global.devResourcePath)
|
||||
@on 'application:run-all-specs', -> @runSpecs(exitWhenDone: false, resourcePath: global.devResourcePath, safeMode: @focusedWindow()?.safeMode)
|
||||
@on 'application:run-benchmarks', -> @runBenchmarks()
|
||||
@on 'application:quit', -> app.quit()
|
||||
@on 'application:new-window', -> @openPath(windowDimensions: @focusedWindow()?.getDimensions())
|
||||
@@ -387,11 +387,13 @@ class AtomApplication
|
||||
# Opens up a new {AtomWindow} to run specs within.
|
||||
#
|
||||
# options -
|
||||
# :exitWhenDone - A Boolean that if true, will close the window upon
|
||||
# :exitWhenDone - A Boolean that, if true, will close the window upon
|
||||
# completion.
|
||||
# :resourcePath - The path to include specs from.
|
||||
# :specPath - The directory to load specs from.
|
||||
runSpecs: ({exitWhenDone, resourcePath, specDirectory, logFile}) ->
|
||||
# :safeMode - A Boolean that, if true, won't run specs from ~/.atom/packages
|
||||
# and ~/.atom/dev/packages, defaults to false.
|
||||
runSpecs: ({exitWhenDone, resourcePath, specDirectory, logFile, safeMode}) ->
|
||||
if resourcePath isnt @resourcePath and not fs.existsSync(resourcePath)
|
||||
resourcePath = @resourcePath
|
||||
|
||||
@@ -402,7 +404,8 @@ class AtomApplication
|
||||
|
||||
isSpec = true
|
||||
devMode = true
|
||||
new AtomWindow({bootstrapScript, resourcePath, exitWhenDone, isSpec, devMode, specDirectory, logFile})
|
||||
safeMode ?= false
|
||||
new AtomWindow({bootstrapScript, resourcePath, exitWhenDone, isSpec, devMode, specDirectory, logFile, safeMode})
|
||||
|
||||
runBenchmarks: ->
|
||||
try
|
||||
|
||||
@@ -20,7 +20,7 @@ class AtomWindow
|
||||
isSpec: null
|
||||
|
||||
constructor: (settings={}) ->
|
||||
{@resourcePath, pathToOpen, initialLine, initialColumn, @isSpec, @exitWhenDone} = settings
|
||||
{@resourcePath, pathToOpen, initialLine, initialColumn, @isSpec, @exitWhenDone, @safeMode} = settings
|
||||
|
||||
# Normalize to make sure drive letter case is consistent on Windows
|
||||
@resourcePath = path.normalize(@resourcePath) if @resourcePath
|
||||
|
||||
@@ -40,8 +40,6 @@ class BufferedProcess
|
||||
# containing the exit status (optional).
|
||||
constructor: ({command, args, options, stdout, stderr, exit}={}) ->
|
||||
options ?= {}
|
||||
# Quick hack. Killing @process will only kill cmd.exe, and not the child
|
||||
# process and will just orphan it. Does not escape ^ (cmd's escape symbol).
|
||||
# Related to joyent/node#2318
|
||||
if process.platform is "win32"
|
||||
# Quote all arguments and escapes inner quotes
|
||||
@@ -55,7 +53,10 @@ class BufferedProcess
|
||||
"\"#{arg.replace(/"/g, '\\"')}\""
|
||||
else
|
||||
cmdArgs = []
|
||||
cmdArgs.unshift("\"#{command}\"")
|
||||
if /\s/.test(command)
|
||||
cmdArgs.unshift("\"#{command}\"")
|
||||
else
|
||||
cmdArgs.unshift(command)
|
||||
cmdArgs = ['/s', '/c', "\"#{cmdArgs.join(' ')}\""]
|
||||
cmdOptions = _.clone(options)
|
||||
cmdOptions.windowsVerbatimArguments = true
|
||||
@@ -114,8 +115,48 @@ class BufferedProcess
|
||||
onLines(buffered) if buffered.length > 0
|
||||
onDone()
|
||||
|
||||
# Kill all child processes of the spawned cmd.exe process on Windows.
|
||||
#
|
||||
# This is required since killing the cmd.exe does not terminate child
|
||||
# processes.
|
||||
killOnWindows: ->
|
||||
parentPid = @process.pid
|
||||
cmd = 'wmic'
|
||||
args = [
|
||||
'process'
|
||||
'where'
|
||||
"(ParentProcessId=#{parentPid})"
|
||||
'get'
|
||||
'processid'
|
||||
]
|
||||
|
||||
wmicProcess = ChildProcess.spawn(cmd, args)
|
||||
wmicProcess.on 'error', -> # ignore errors
|
||||
output = ''
|
||||
wmicProcess.stdout.on 'data', (data) -> output += data
|
||||
wmicProcess.stdout.on 'close', =>
|
||||
pidsToKill = output.split(/\s+/)
|
||||
.filter (pid) -> /^\d+$/.test(pid)
|
||||
.map (pid) -> parseInt(pid)
|
||||
.filter (pid) -> pid isnt parentPid and 0 < pid < Infinity
|
||||
|
||||
for pid in pidsToKill
|
||||
try
|
||||
process.kill(pid)
|
||||
@killProcess()
|
||||
|
||||
killProcess: ->
|
||||
@process?.kill()
|
||||
@process = null
|
||||
|
||||
# Public: Terminate the process.
|
||||
kill: ->
|
||||
return if @killed
|
||||
|
||||
@killed = true
|
||||
@process.kill()
|
||||
@process = null
|
||||
if process.platform is 'win32'
|
||||
@killOnWindows()
|
||||
else
|
||||
@killProcess()
|
||||
|
||||
undefined
|
||||
|
||||
+13
-2
@@ -103,8 +103,19 @@ class Config
|
||||
# Returns the value from Atom's default settings, the user's configuration
|
||||
# file, or `null` if the key doesn't exist in either.
|
||||
get: (keyPath) ->
|
||||
value = _.valueForKeyPath(@settings, keyPath) ? _.valueForKeyPath(@defaultSettings, keyPath)
|
||||
_.deepClone(value)
|
||||
value = _.valueForKeyPath(@settings, keyPath)
|
||||
defaultValue = _.valueForKeyPath(@defaultSettings, keyPath)
|
||||
|
||||
if value?
|
||||
value = _.deepClone(value)
|
||||
valueIsObject = _.isObject(value) and not _.isArray(value)
|
||||
defaultValueIsObject = _.isObject(defaultValue) and not _.isArray(defaultValue)
|
||||
if valueIsObject and defaultValueIsObject
|
||||
_.defaults(value, defaultValue)
|
||||
else
|
||||
value = _.deepClone(defaultValue)
|
||||
|
||||
value
|
||||
|
||||
# Public: Retrieves the setting for the given key as an integer.
|
||||
#
|
||||
|
||||
+5
-4
@@ -95,8 +95,8 @@ class Cursor extends Model
|
||||
getBufferPosition: ->
|
||||
@marker.getHeadBufferPosition()
|
||||
|
||||
autoscroll: ->
|
||||
@editor.scrollToScreenRange(@getScreenRange())
|
||||
autoscroll: (options) ->
|
||||
@editor.scrollToScreenRange(@getScreenRange(), options)
|
||||
|
||||
# Public: If the marker range is empty, the cursor is marked as being visible.
|
||||
updateVisibility: ->
|
||||
@@ -273,9 +273,10 @@ class Cursor extends Model
|
||||
# line.
|
||||
moveToFirstCharacterOfLine: ->
|
||||
{row, column} = @getScreenPosition()
|
||||
screenline = @editor.lineForScreenRow(row)
|
||||
|
||||
goalColumn = screenline.text.search(/\S/)
|
||||
bufferRange = @editor.bufferRangeForScreenRange([[row, 0], [row, Infinity]])
|
||||
screenLineText = @editor.getTextInBufferRange(bufferRange)
|
||||
goalColumn = screenLineText.search(/\S/)
|
||||
goalColumn = 0 if goalColumn == column or goalColumn == -1
|
||||
@setScreenPosition([row, goalColumn])
|
||||
|
||||
|
||||
@@ -38,10 +38,10 @@ class DisplayBuffer extends Model
|
||||
verticalScrollbarWidth: 15
|
||||
scopedCharacterWidthsChangeCount: 0
|
||||
|
||||
constructor: ({tabLength, @editorWidthInChars, @tokenizedBuffer, buffer}={}) ->
|
||||
constructor: ({tabLength, @editorWidthInChars, @tokenizedBuffer, buffer, @invisibles}={}) ->
|
||||
super
|
||||
@softWrap ?= atom.config.get('editor.softWrap') ? false
|
||||
@tokenizedBuffer ?= new TokenizedBuffer({tabLength, buffer})
|
||||
@tokenizedBuffer ?= new TokenizedBuffer({tabLength, buffer, @invisibles})
|
||||
@buffer = @tokenizedBuffer.buffer
|
||||
@charWidthsByScope = {}
|
||||
@markers = {}
|
||||
@@ -81,7 +81,7 @@ class DisplayBuffer extends Model
|
||||
params
|
||||
|
||||
copy: ->
|
||||
newDisplayBuffer = new DisplayBuffer({@buffer, tabLength: @getTabLength()})
|
||||
newDisplayBuffer = new DisplayBuffer({@buffer, tabLength: @getTabLength(), @invisibles})
|
||||
newDisplayBuffer.setScrollTop(@getScrollTop())
|
||||
newDisplayBuffer.setScrollLeft(@getScrollLeft())
|
||||
|
||||
@@ -340,6 +340,9 @@ class DisplayBuffer extends Model
|
||||
setTabLength: (tabLength) ->
|
||||
@tokenizedBuffer.setTabLength(tabLength)
|
||||
|
||||
setInvisibles: (@invisibles) ->
|
||||
@tokenizedBuffer.setInvisibles(@invisibles)
|
||||
|
||||
# Deprecated: Use the softWrap property directly
|
||||
setSoftWrap: (@softWrap) -> @softWrap
|
||||
|
||||
|
||||
@@ -3,6 +3,7 @@ React = require 'react-atom-fork'
|
||||
{debounce, defaults, isEqualForProperties} = require 'underscore-plus'
|
||||
scrollbarStyle = require 'scrollbar-style'
|
||||
{Range, Point} = require 'text-buffer'
|
||||
grim = require 'grim'
|
||||
|
||||
GutterComponent = require './gutter-component'
|
||||
InputComponent = require './input-component'
|
||||
@@ -48,10 +49,9 @@ EditorComponent = React.createClass
|
||||
domPollingPaused: false
|
||||
|
||||
render: ->
|
||||
{focused, showIndentGuide, showInvisibles, showLineNumbers, visible} = @state
|
||||
{focused, showIndentGuide, showLineNumbers, visible} = @state
|
||||
{editor, mini, cursorBlinkPeriod, cursorBlinkResumeDelay} = @props
|
||||
maxLineNumberDigits = editor.getLineCount().toString().length
|
||||
invisibles = if showInvisibles and not mini then @state.invisibles else {}
|
||||
hasSelection = editor.getSelection()? and !editor.getSelection().isEmpty()
|
||||
style = {}
|
||||
|
||||
@@ -109,10 +109,10 @@ EditorComponent = React.createClass
|
||||
ref: 'lines',
|
||||
editor, lineHeightInPixels, defaultCharWidth, lineDecorations, highlightDecorations,
|
||||
showIndentGuide, renderedRowRange, @pendingChanges, scrollTop, scrollLeft,
|
||||
@scrollingVertically, scrollHeight, scrollWidth, mouseWheelScreenRow, invisibles,
|
||||
@scrollingVertically, scrollHeight, scrollWidth, mouseWheelScreenRow,
|
||||
@visible, scrollViewHeight, @scopedCharacterWidthsChangeCount, lineWidth, @useHardwareAcceleration,
|
||||
placeholderText, @performedInitialMeasurement, @backgroundColor, cursorPixelRects,
|
||||
cursorBlinkPeriod, cursorBlinkResumeDelay
|
||||
cursorBlinkPeriod, cursorBlinkResumeDelay, mini
|
||||
}
|
||||
|
||||
ScrollbarComponent
|
||||
@@ -186,8 +186,13 @@ EditorComponent = React.createClass
|
||||
componentWillUnmount: ->
|
||||
@props.parentView.trigger 'editor:will-be-removed', [@props.parentView]
|
||||
@unsubscribe()
|
||||
window.removeEventListener 'resize', @requestHeightAndWidthMeasurement
|
||||
clearInterval(@domPollingIntervalId)
|
||||
@domPollingIntervalId = null
|
||||
@props.editor.destroy()
|
||||
|
||||
componentWillReceiveProps: (newProps) ->
|
||||
@props.editor.setMini(newProps.mini)
|
||||
|
||||
componentWillUpdate: ->
|
||||
wasVisible = @visible
|
||||
@@ -495,7 +500,7 @@ EditorComponent = React.createClass
|
||||
'editor:fold-at-indent-level-9': => editor.foldAllAtIndentLevel(8)
|
||||
'editor:toggle-line-comments': => editor.toggleLineCommentsInSelection()
|
||||
'editor:log-cursor-scope': => editor.logCursorScope()
|
||||
'editor:checkout-head-revision': => editor.checkoutHead()
|
||||
'editor:checkout-head-revision': => atom.project.getRepo()?.checkoutHeadForEditor(editor)
|
||||
'editor:copy-path': => editor.copyPathToClipboard()
|
||||
'editor:move-line-up': => editor.moveLineUp()
|
||||
'editor:move-line-down': => editor.moveLineDown()
|
||||
@@ -509,21 +514,31 @@ EditorComponent = React.createClass
|
||||
addCommandListeners: (listenersByCommandName) ->
|
||||
{parentView} = @props
|
||||
|
||||
for command, listener of listenersByCommandName
|
||||
parentView.command command, listener
|
||||
addListener = (command, listener) ->
|
||||
parentView.command command, (event) ->
|
||||
event.stopPropagation()
|
||||
listener(event)
|
||||
|
||||
addListener(command, listener) for command, listener of listenersByCommandName
|
||||
|
||||
return
|
||||
|
||||
observeConfig: ->
|
||||
@subscribe atom.config.observe 'editor.showIndentGuide', @setShowIndentGuide
|
||||
@subscribe atom.config.observe 'editor.invisibles', @setInvisibles
|
||||
@subscribe atom.config.observe 'editor.showInvisibles', @setShowInvisibles
|
||||
@subscribe atom.config.observe 'editor.showLineNumbers', @setShowLineNumbers
|
||||
@subscribe atom.config.observe 'editor.scrollSensitivity', @setScrollSensitivity
|
||||
@subscribe atom.config.observe 'editor.useHardwareAcceleration', @setUseHardwareAcceleration
|
||||
|
||||
onFocus: ->
|
||||
@refs.input.focus()
|
||||
@refs.input.focus() if @isMounted()
|
||||
|
||||
onTextInput: (event) ->
|
||||
event.stopPropagation()
|
||||
|
||||
# If we prevent the insertion of a space character, then the browser
|
||||
# interprets the spacebar keypress as a page-down command.
|
||||
event.preventDefault() unless event.data is ' '
|
||||
|
||||
return unless @isInputEnabled()
|
||||
|
||||
{editor} = @props
|
||||
@@ -536,12 +551,8 @@ EditorComponent = React.createClass
|
||||
selectedLength = inputNode.selectionEnd - inputNode.selectionStart
|
||||
editor.selectLeft() if selectedLength is 1
|
||||
|
||||
editor.insertText(event.data)
|
||||
inputNode.value = event.data
|
||||
inputNode.value = event.data if editor.insertText(event.data)
|
||||
|
||||
# If we prevent the insertion of a space character, then the browser
|
||||
# interprets the spacebar keypress as a page-down command.
|
||||
event.preventDefault() unless event.data is ' '
|
||||
|
||||
onInputFocused: ->
|
||||
@setState(focused: true)
|
||||
@@ -934,24 +945,14 @@ EditorComponent = React.createClass
|
||||
setShowIndentGuide: (showIndentGuide) ->
|
||||
@setState({showIndentGuide})
|
||||
|
||||
# Public: Defines which characters are invisible.
|
||||
#
|
||||
# invisibles - An {Object} defining the invisible characters:
|
||||
# :eol - The end of line invisible {String} (default: `\u00ac`).
|
||||
# :space - The space invisible {String} (default: `\u00b7`).
|
||||
# :tab - The tab invisible {String} (default: `\u00bb`).
|
||||
# :cr - The carriage return invisible {String} (default: `\u00a4`).
|
||||
# Deprecated
|
||||
setInvisibles: (invisibles={}) ->
|
||||
defaults invisibles,
|
||||
eol: '\u00ac'
|
||||
space: '\u00b7'
|
||||
tab: '\u00bb'
|
||||
cr: '\u00a4'
|
||||
|
||||
@setState({invisibles})
|
||||
grim.deprecate "Use config.set('editor.invisibles', invisibles) instead"
|
||||
atom.config.set('editor.invisibles', invisibles)
|
||||
|
||||
# Deprecated
|
||||
setShowInvisibles: (showInvisibles) ->
|
||||
@setState({showInvisibles})
|
||||
atom.config.set('editor.showInvisibles', showInvisibles)
|
||||
|
||||
setShowLineNumbers: (showLineNumbers) ->
|
||||
@setState({showLineNumbers})
|
||||
|
||||
@@ -58,6 +58,12 @@ class EditorView extends View
|
||||
softWrapAtPreferredLineLength: false
|
||||
scrollSensitivity: 40
|
||||
useHardwareAcceleration: true
|
||||
confirmCheckoutHeadRevision: true
|
||||
invisibles:
|
||||
eol: '\u00ac'
|
||||
space: '\u00b7'
|
||||
tab: '\u00bb'
|
||||
cr: '\u00a4'
|
||||
|
||||
@nextEditorId: 1
|
||||
|
||||
@@ -231,7 +237,7 @@ class EditorView extends View
|
||||
'editor:fold-at-indent-level-9': => @editor.foldAllAtIndentLevel(8)
|
||||
'editor:toggle-line-comments': => @toggleLineCommentsInSelection()
|
||||
'editor:log-cursor-scope': => @logCursorScope()
|
||||
'editor:checkout-head-revision': => @checkoutHead()
|
||||
'editor:checkout-head-revision': => atom.project.getRepo()?.checkoutHeadForEditor(@editor)
|
||||
'editor:copy-path': => @copyPathToClipboard()
|
||||
'editor:move-line-up': => @editor.moveLineUp()
|
||||
'editor:move-line-down': => @editor.moveLineDown()
|
||||
@@ -338,11 +344,6 @@ class EditorView extends View
|
||||
getPlaceholderText: ->
|
||||
@placeholderText
|
||||
|
||||
# Checkout the HEAD revision of this editor's file.
|
||||
checkoutHead: ->
|
||||
if path = @editor.getPath()
|
||||
atom.project.getRepo()?.checkoutHead(path)
|
||||
|
||||
configure: ->
|
||||
@subscribe atom.config.observe 'editor.showLineNumbers', (showLineNumbers) => @gutter.setShowLineNumbers(showLineNumbers)
|
||||
@subscribe atom.config.observe 'editor.showInvisibles', (showInvisibles) => @setShowInvisibles(showInvisibles)
|
||||
@@ -641,9 +642,9 @@ class EditorView extends View
|
||||
@scrollBottom(@editor.getScreenLineCount() * @lineHeight)
|
||||
|
||||
# Public: Scrolls the editor to the position of the most recently added
|
||||
# cursor.
|
||||
# cursor if it isn't current on screen.
|
||||
#
|
||||
# The editor is also centered.
|
||||
# The editor is centered around the cursor's position if possible.
|
||||
scrollToCursorPosition: ->
|
||||
@scrollToBufferPosition(@editor.getCursorBufferPosition(), center: true)
|
||||
|
||||
|
||||
+51
-12
@@ -159,13 +159,16 @@ class Editor extends Model
|
||||
@delegatesProperties '$lineHeightInPixels', '$defaultCharWidth', '$height', '$width',
|
||||
'$scrollTop', '$scrollLeft', 'manageScrollPosition', toProperty: 'displayBuffer'
|
||||
|
||||
constructor: ({@softTabs, initialLine, initialColumn, tabLength, softWrap, @displayBuffer, buffer, registerEditor, suppressCursorCreation}) ->
|
||||
constructor: ({@softTabs, initialLine, initialColumn, tabLength, softWrap, @displayBuffer, buffer, registerEditor, suppressCursorCreation, @mini}) ->
|
||||
super
|
||||
|
||||
@cursors = []
|
||||
@selections = []
|
||||
|
||||
@displayBuffer ?= new DisplayBuffer({buffer, tabLength, softWrap})
|
||||
if @shouldShowInvisibles()
|
||||
invisibles = atom.config.get('editor.invisibles')
|
||||
|
||||
@displayBuffer ?= new DisplayBuffer({buffer, tabLength, softWrap, invisibles})
|
||||
@buffer = @displayBuffer.buffer
|
||||
@softTabs = @usesSoftTabs() ? @softTabs ? atom.config.get('editor.softTabs') ? true
|
||||
|
||||
@@ -186,6 +189,9 @@ class Editor extends Model
|
||||
@subscribe @$scrollTop, (scrollTop) => @emit 'scroll-top-changed', scrollTop
|
||||
@subscribe @$scrollLeft, (scrollLeft) => @emit 'scroll-left-changed', scrollLeft
|
||||
|
||||
@subscribe atom.config.observe 'editor.showInvisibles', callNow: false, (show) => @updateInvisibles()
|
||||
@subscribe atom.config.observe 'editor.invisibles', callNow: false, => @updateInvisibles()
|
||||
|
||||
atom.workspace?.editorAdded(this) if registerEditor
|
||||
|
||||
serializeParams: ->
|
||||
@@ -281,6 +287,11 @@ class Editor extends Model
|
||||
# Controls visibility based on the given {Boolean}.
|
||||
setVisible: (visible) -> @displayBuffer.setVisible(visible)
|
||||
|
||||
setMini: (mini) ->
|
||||
if mini isnt @mini
|
||||
@mini = mini
|
||||
@updateInvisibles()
|
||||
|
||||
# Set the number of characters that can be displayed horizontally in the
|
||||
# editor.
|
||||
#
|
||||
@@ -435,10 +446,6 @@ class Editor extends Model
|
||||
# filePath - A {String} path.
|
||||
saveAs: (filePath) -> @buffer.saveAs(filePath)
|
||||
|
||||
checkoutHead: ->
|
||||
if filePath = @getPath()
|
||||
atom.project.getRepo()?.checkoutHead(filePath)
|
||||
|
||||
# Copies the current file path to the native clipboard.
|
||||
copyPathToClipboard: ->
|
||||
if filePath = @getPath()
|
||||
@@ -629,12 +636,29 @@ class Editor extends Model
|
||||
|
||||
# Public: For each selection, replace the selected text with the given text.
|
||||
#
|
||||
# Emits: `will-insert-text -> ({text, cancel})` before the text has
|
||||
# been inserted. Calling `cancel` will prevent the text from being
|
||||
# inserted.
|
||||
# Emits: `did-insert-text -> ({text})` after the text has been inserted.
|
||||
#
|
||||
# text - A {String} representing the text to insert.
|
||||
# options - See {Selection::insertText}.
|
||||
#
|
||||
# Returns a {Bool} indicating whether or not the text was inserted.
|
||||
insertText: (text, options={}) ->
|
||||
options.autoIndentNewline ?= @shouldAutoIndent()
|
||||
options.autoDecreaseIndent ?= @shouldAutoIndent()
|
||||
@mutateSelectedText (selection) -> selection.insertText(text, options)
|
||||
willInsert = true
|
||||
cancel = -> willInsert = false
|
||||
@emit('will-insert-text', {cancel, text})
|
||||
|
||||
if willInsert
|
||||
options.autoIndentNewline ?= @shouldAutoIndent()
|
||||
options.autoDecreaseIndent ?= @shouldAutoIndent()
|
||||
@mutateSelectedText (selection) =>
|
||||
range = selection.insertText(text, options)
|
||||
@emit('did-insert-text', {text, range})
|
||||
range
|
||||
else
|
||||
false
|
||||
|
||||
# Public: For each selection, replace the selected text with a newline.
|
||||
insertNewline: ->
|
||||
@@ -1588,8 +1612,14 @@ class Editor extends Model
|
||||
moveCursorToBeginningOfPreviousParagraph: ->
|
||||
@moveCursors (cursor) -> cursor.moveToBeginningOfPreviousParagraph()
|
||||
|
||||
scrollToCursorPosition: ->
|
||||
@getCursor().autoscroll()
|
||||
# Public: Scroll the editor to reveal the most recently added cursor if it is
|
||||
# off-screen.
|
||||
#
|
||||
# options - An optional hash of options.
|
||||
# :center - Center the editor around the cursor if possible. Defauls to
|
||||
# true.
|
||||
scrollToCursorPosition: (options) ->
|
||||
@getCursor().autoscroll(center: options?.center ? true)
|
||||
|
||||
pageUp: ->
|
||||
newScrollTop = @getScrollTop() - @getHeight()
|
||||
@@ -1928,6 +1958,15 @@ class Editor extends Model
|
||||
shouldAutoIndent: ->
|
||||
atom.config.get("editor.autoIndent")
|
||||
|
||||
shouldShowInvisibles: ->
|
||||
not @mini and atom.config.get('editor.showInvisibles')
|
||||
|
||||
updateInvisibles: ->
|
||||
if @shouldShowInvisibles()
|
||||
@displayBuffer.setInvisibles(atom.config.get('editor.invisibles'))
|
||||
else
|
||||
@displayBuffer.setInvisibles(null)
|
||||
|
||||
# Public: Batch multiple operations as a single undo/redo step.
|
||||
#
|
||||
# Any group of operations that are logically grouped from the perspective of
|
||||
@@ -2017,7 +2056,7 @@ class Editor extends Model
|
||||
setScrollRight: (scrollRight) -> @displayBuffer.setScrollRight(scrollRight)
|
||||
|
||||
getScrollHeight: -> @displayBuffer.getScrollHeight()
|
||||
getScrollWidth: (scrollWidth) -> @displayBuffer.getScrollWidth(scrollWidth)
|
||||
getScrollWidth: -> @displayBuffer.getScrollWidth()
|
||||
|
||||
getVisibleRowRange: -> @displayBuffer.getVisibleRowRange()
|
||||
|
||||
|
||||
+22
-1
@@ -1,4 +1,4 @@
|
||||
{join} = require 'path'
|
||||
{basename, join} = require 'path'
|
||||
|
||||
_ = require 'underscore-plus'
|
||||
{Emitter, Subscriber} = require 'emissary'
|
||||
@@ -93,6 +93,27 @@ class Git
|
||||
@getPathStatus(path)
|
||||
@subscribe buffer, 'destroyed', => @unsubscribe(buffer)
|
||||
|
||||
# Subscribes to editor view event.
|
||||
checkoutHeadForEditor: (editor) ->
|
||||
filePath = editor.getPath()
|
||||
return unless filePath
|
||||
|
||||
fileName = basename(filePath)
|
||||
|
||||
checkoutHead = =>
|
||||
editor.buffer.reload() if editor.buffer.isModified()
|
||||
@checkoutHead(filePath)
|
||||
|
||||
if atom.config.get('editor.confirmCheckoutHeadRevision')
|
||||
atom.confirm
|
||||
message: 'Confirm Checkout HEAD Revision'
|
||||
detailedMessage: "Are you sure you want to discard all changes to \"#{fileName}\" since the last Git commit?"
|
||||
buttons:
|
||||
OK: checkoutHead
|
||||
Cancel: null
|
||||
else
|
||||
checkoutHead()
|
||||
|
||||
# Public: Destroy this `Git` object. This destroys any tasks and subscriptions
|
||||
# and releases the underlying libgit2 repository handle.
|
||||
destroy: ->
|
||||
|
||||
@@ -22,12 +22,12 @@ LinesComponent = React.createClass
|
||||
if performedInitialMeasurement
|
||||
{editor, highlightDecorations, scrollHeight, scrollWidth, placeholderText, backgroundColor} = @props
|
||||
{lineHeightInPixels, defaultCharWidth, scrollViewHeight, scopedCharacterWidthsChangeCount} = @props
|
||||
{scrollTop, scrollLeft, cursorPixelRects} = @props
|
||||
{scrollTop, scrollLeft, cursorPixelRects, mini} = @props
|
||||
style =
|
||||
height: Math.max(scrollHeight, scrollViewHeight)
|
||||
width: scrollWidth
|
||||
WebkitTransform: @getTransform()
|
||||
backgroundColor: backgroundColor
|
||||
backgroundColor: if mini then null else backgroundColor
|
||||
|
||||
div {className: 'lines', style},
|
||||
div className: 'placeholder-text', placeholderText if placeholderText?
|
||||
@@ -60,7 +60,7 @@ LinesComponent = React.createClass
|
||||
shouldComponentUpdate: (newProps) ->
|
||||
return true unless isEqualForProperties(newProps, @props,
|
||||
'renderedRowRange', 'lineDecorations', 'highlightDecorations', 'lineHeightInPixels', 'defaultCharWidth',
|
||||
'scrollTop', 'scrollLeft', 'showIndentGuide', 'scrollingVertically', 'invisibles', 'visible',
|
||||
'scrollTop', 'scrollLeft', 'showIndentGuide', 'scrollingVertically', 'visible',
|
||||
'scrollViewHeight', 'mouseWheelScreenRow', 'scopedCharacterWidthsChangeCount', 'lineWidth', 'useHardwareAcceleration',
|
||||
'placeholderText', 'performedInitialMeasurement', 'backgroundColor', 'cursorPixelRects'
|
||||
)
|
||||
@@ -82,7 +82,7 @@ LinesComponent = React.createClass
|
||||
return unless performedInitialMeasurement
|
||||
|
||||
@clearScreenRowCaches() unless prevProps.lineHeightInPixels is @props.lineHeightInPixels
|
||||
@removeLineNodes() unless isEqualForProperties(prevProps, @props, 'showIndentGuide', 'invisibles')
|
||||
@removeLineNodes() unless isEqualForProperties(prevProps, @props, 'showIndentGuide')
|
||||
@updateLines(@props.lineWidth isnt prevProps.lineWidth)
|
||||
@measureCharactersInNewLines() if visible and not scrollingVertically
|
||||
|
||||
@@ -170,34 +170,30 @@ LinesComponent = React.createClass
|
||||
lineHTML
|
||||
|
||||
buildEmptyLineInnerHTML: (line) ->
|
||||
{showIndentGuide, invisibles} = @props
|
||||
{cr, eol} = invisibles
|
||||
{indentLevel, tabLength} = line
|
||||
{showIndentGuide} = @props
|
||||
{indentLevel, tabLength, endOfLineInvisibles} = line
|
||||
|
||||
if showIndentGuide and indentLevel > 0
|
||||
invisiblesToRender = []
|
||||
invisiblesToRender.push(cr) if cr? and line.lineEnding is '\r\n'
|
||||
invisiblesToRender.push(eol) if eol?
|
||||
|
||||
invisibleIndex = 0
|
||||
lineHTML = ''
|
||||
for i in [0...indentLevel]
|
||||
lineHTML += "<span class='indent-guide'>"
|
||||
for j in [0...tabLength]
|
||||
if invisible = invisiblesToRender.shift()
|
||||
if invisible = endOfLineInvisibles?[invisibleIndex++]
|
||||
lineHTML += "<span class='invisible-character'>#{invisible}</span>"
|
||||
else
|
||||
lineHTML += ' '
|
||||
lineHTML += "</span>"
|
||||
|
||||
while invisiblesToRender.length
|
||||
lineHTML += "<span class='invisible-character'>#{invisiblesToRender.shift()}</span>"
|
||||
while invisibleIndex < endOfLineInvisibles?.length
|
||||
lineHTML += "<span class='invisible-character'>#{line.endOfLineInvisibles[invisibleIndex++]}</span>"
|
||||
|
||||
lineHTML
|
||||
else
|
||||
@buildEndOfLineHTML(line, @props.invisibles) or ' '
|
||||
@buildEndOfLineHTML(line) or ' '
|
||||
|
||||
buildLineInnerHTML: (line) ->
|
||||
{invisibles, mini, showIndentGuide, invisibles} = @props
|
||||
{mini, showIndentGuide} = @props
|
||||
{tokens, text} = line
|
||||
innerHTML = ""
|
||||
|
||||
@@ -207,23 +203,19 @@ LinesComponent = React.createClass
|
||||
for token in tokens
|
||||
innerHTML += @updateScopeStack(scopeStack, token.scopes)
|
||||
hasIndentGuide = not mini and showIndentGuide and (token.hasLeadingWhitespace or (token.hasTrailingWhitespace and lineIsWhitespaceOnly))
|
||||
innerHTML += token.getValueAsHtml({invisibles, hasIndentGuide})
|
||||
innerHTML += token.getValueAsHtml({hasIndentGuide})
|
||||
|
||||
innerHTML += @popScope(scopeStack) while scopeStack.length > 0
|
||||
innerHTML += @buildEndOfLineHTML(line, invisibles)
|
||||
innerHTML += @buildEndOfLineHTML(line)
|
||||
innerHTML
|
||||
|
||||
buildEndOfLineHTML: (line, invisibles) ->
|
||||
return '' if @props.mini or line.isSoftWrapped()
|
||||
buildEndOfLineHTML: (line) ->
|
||||
{endOfLineInvisibles} = line
|
||||
|
||||
html = ''
|
||||
# Note the lack of '?' in the character checks. A user can set the chars
|
||||
# to an empty string which we will interpret as not-set
|
||||
if invisibles.cr and line.lineEnding is '\r\n'
|
||||
html += "<span class='invisible-character'>#{invisibles.cr}</span>"
|
||||
if invisibles.eol
|
||||
html += "<span class='invisible-character'>#{invisibles.eol}</span>"
|
||||
|
||||
if endOfLineInvisibles?
|
||||
for invisible in endOfLineInvisibles
|
||||
html += "<span class='invisible-character'>#{invisible}</span>"
|
||||
html
|
||||
|
||||
updateScopeStack: (scopeStack, desiredScopes) ->
|
||||
|
||||
@@ -15,6 +15,7 @@ class MenuManager
|
||||
@pendingUpdateOperation = null
|
||||
@template = []
|
||||
atom.keymaps.on 'bundled-keymaps-loaded', => @loadPlatformItems()
|
||||
atom.packages.on 'activated', => @sortPackagesMenu()
|
||||
|
||||
# Public: Adds the given item definition to the existing template.
|
||||
#
|
||||
@@ -130,3 +131,14 @@ class MenuManager
|
||||
# Get an {Array} of {String} classes for the given element.
|
||||
classesForElement: (element) ->
|
||||
element?.classList.toString().split(' ') ? []
|
||||
|
||||
sortPackagesMenu: ->
|
||||
packagesMenu = @template.find ({label}) => @normalizeLabel(label) is 'Packages'
|
||||
return unless packagesMenu?.submenu?
|
||||
|
||||
packagesMenu.submenu.sort (item1, item2) =>
|
||||
if item1.label and item2.label
|
||||
@normalizeLabel(item1.label).localeCompare(@normalizeLabel(item2.label))
|
||||
else
|
||||
0
|
||||
@update()
|
||||
|
||||
@@ -371,9 +371,10 @@ class Package
|
||||
# to minimize the impact on startup time.
|
||||
getIncompatibleNativeModules: ->
|
||||
localStorageKey = "installed-packages:#{@name}:#{@metadata.version}"
|
||||
try
|
||||
{incompatibleNativeModules} = JSON.parse(global.localStorage.getItem(localStorageKey)) ? {}
|
||||
return incompatibleNativeModules if incompatibleNativeModules?
|
||||
unless atom.inDevMode()
|
||||
try
|
||||
{incompatibleNativeModules} = JSON.parse(global.localStorage.getItem(localStorageKey)) ? {}
|
||||
return incompatibleNativeModules if incompatibleNativeModules?
|
||||
|
||||
incompatibleNativeModules = []
|
||||
for nativeModulePath in @getNativeModuleDependencyPaths()
|
||||
|
||||
@@ -141,13 +141,17 @@ class PaneView extends View
|
||||
@activeItem
|
||||
|
||||
onActiveItemChanged: (item) =>
|
||||
@previousActiveItem?.off? 'title-changed', @activeItemTitleChanged
|
||||
if @previousActiveItem?.off?
|
||||
@previousActiveItem.off 'title-changed', @activeItemTitleChanged
|
||||
@previousActiveItem.off 'modified-status-changed', @activeItemModifiedChanged
|
||||
@previousActiveItem = item
|
||||
|
||||
return unless item?
|
||||
|
||||
hasFocus = @hasFocus()
|
||||
item.on? 'title-changed', @activeItemTitleChanged
|
||||
if item.on?
|
||||
item.on 'title-changed', @activeItemTitleChanged
|
||||
item.on 'modified-status-changed', @activeItemModifiedChanged
|
||||
view = @viewForItem(item)
|
||||
otherView.hide() for otherView in @itemViews.children().not(view).views()
|
||||
@itemViews.append(view) unless view.parent().is(@itemViews)
|
||||
@@ -183,6 +187,9 @@ class PaneView extends View
|
||||
activeItemTitleChanged: =>
|
||||
@trigger 'pane:active-item-title-changed'
|
||||
|
||||
activeItemModifiedChanged: =>
|
||||
@trigger 'pane:active-item-modified-status-changed'
|
||||
|
||||
viewForItem: (item) ->
|
||||
return unless item?
|
||||
if item instanceof $
|
||||
|
||||
@@ -10,6 +10,7 @@ class ReactEditorView extends View
|
||||
@content: (params) ->
|
||||
attributes = params.attributes ? {}
|
||||
attributes.class = 'editor react editor-colors'
|
||||
attributes.tabIndex = -1
|
||||
@div attributes
|
||||
|
||||
focusOnAttach: false
|
||||
@@ -29,6 +30,7 @@ class ReactEditorView extends View
|
||||
softWrap: false
|
||||
tabLength: 2
|
||||
softTabs: true
|
||||
mini: mini
|
||||
|
||||
props = defaults({@editor, parentView: this}, props)
|
||||
@component = React.renderComponent(EditorComponent(props), @element)
|
||||
@@ -55,6 +57,11 @@ class ReactEditorView extends View
|
||||
lines.addClass(klass)
|
||||
lines.length > 0
|
||||
|
||||
@on 'focus', =>
|
||||
if @component?
|
||||
@component.onFocus()
|
||||
else
|
||||
@focusOnAttach = true
|
||||
|
||||
getEditor: -> @editor
|
||||
|
||||
@@ -66,6 +73,7 @@ class ReactEditorView extends View
|
||||
Object.defineProperty @::, 'lastRenderedScreenRow', get: -> @component.getRenderedRowRange()[1]
|
||||
Object.defineProperty @::, 'active', get: -> @is(@getPane()?.activeView)
|
||||
Object.defineProperty @::, 'isFocused', get: -> @component?.state.focused
|
||||
Object.defineProperty @::, 'mini', get: -> @component?.props.mini
|
||||
|
||||
afterAttach: (onDom) ->
|
||||
return unless onDom
|
||||
@@ -115,8 +123,9 @@ class ReactEditorView extends View
|
||||
@find('.lines').prepend(view)
|
||||
|
||||
beforeRemove: ->
|
||||
React.unmountComponentAtNode(@element) if @component.isMounted()
|
||||
return unless @attached
|
||||
@attached = false
|
||||
React.unmountComponentAtNode(@element) if @component.isMounted()
|
||||
@trigger 'editor:detached', this
|
||||
|
||||
# Public: Split the editor view left.
|
||||
@@ -142,12 +151,6 @@ class ReactEditorView extends View
|
||||
getPane: ->
|
||||
@parent('.item-views').parents('.pane').view()
|
||||
|
||||
focus: ->
|
||||
if @component?
|
||||
@component.onFocus()
|
||||
else
|
||||
@focusOnAttach = true
|
||||
|
||||
hide: ->
|
||||
super
|
||||
@pollComponentDOM()
|
||||
@@ -169,9 +172,6 @@ class ReactEditorView extends View
|
||||
pageUp: ->
|
||||
@editor.pageUp()
|
||||
|
||||
getModel: ->
|
||||
@component?.getModel()
|
||||
|
||||
getFirstVisibleScreenRow: ->
|
||||
@editor.getVisibleRowRange()[0]
|
||||
|
||||
|
||||
@@ -16,7 +16,7 @@ module.exports =
|
||||
class ThemeManager
|
||||
Emitter.includeInto(this)
|
||||
|
||||
constructor: ({@packageManager, @resourcePath, @configDirPath}) ->
|
||||
constructor: ({@packageManager, @resourcePath, @configDirPath, @safeMode}) ->
|
||||
@lessCache = null
|
||||
@packageManager.registerPackageActivator(this, ['theme'])
|
||||
|
||||
@@ -51,6 +51,28 @@ class ThemeManager
|
||||
themeNames = themeNames.filter (themeName) ->
|
||||
themeName and typeof themeName is 'string'
|
||||
|
||||
# Use a built-in syntax and UI theme when in safe mode since themes
|
||||
# installed to ~/.atom/packages will not be loaded.
|
||||
if @safeMode
|
||||
builtInThemeNames = [
|
||||
'atom-dark-syntax'
|
||||
'atom-dark-ui'
|
||||
'atom-light-syntax'
|
||||
'atom-light-ui'
|
||||
'base16-tomorrow-dark-theme'
|
||||
'base16-tomorrow-light-theme'
|
||||
'solarized-dark-syntax'
|
||||
'solarized-light-syntax'
|
||||
]
|
||||
themeNames = _.intersection(themeNames, builtInThemeNames)
|
||||
if themeNames.length is 0
|
||||
themeNames = ['atom-dark-syntax', 'atom-dark-ui']
|
||||
else if themeNames.length is 1
|
||||
if _.endsWith(themeNames[0], '-ui')
|
||||
themeNames.unshift('atom-dark-syntax')
|
||||
else
|
||||
themeNames.push('atom-dark-ui')
|
||||
|
||||
# Reverse so the first (top) theme is loaded after the others. We want
|
||||
# the first/top theme to override later themes in the stack.
|
||||
themeNames.reverse()
|
||||
|
||||
+18
-20
@@ -2,11 +2,7 @@ _ = require 'underscore-plus'
|
||||
textUtils = require './text-utils'
|
||||
|
||||
WhitespaceRegexesByTabLength = {}
|
||||
LeadingSpaceRegex = /^[ ]+/
|
||||
TrailingSpaceRegex = /[ ]+$/
|
||||
EscapeRegex = /[&"'<>]/g
|
||||
CharacterRegex = /./g
|
||||
StartCharacterRegex = /^./
|
||||
StartDotRegex = /^\.?/
|
||||
WhitespaceRegex = /\S/
|
||||
|
||||
@@ -22,6 +18,9 @@ class Token
|
||||
isHardTab: null
|
||||
hasLeadingWhitespace: false
|
||||
hasTrailingWhitespace: false
|
||||
firstNonWhitespaceIndex: null
|
||||
firstTrailingWhitespaceIndex: null
|
||||
hasInvisibleCharacters: false
|
||||
|
||||
constructor: ({@value, @scopes, @isAtomic, @bufferDelta, @isHardTab}) ->
|
||||
@screenDelta = @value.length
|
||||
@@ -136,14 +135,12 @@ class Token
|
||||
scopeClasses = scope.split('.')
|
||||
_.isSubset(targetClasses, scopeClasses)
|
||||
|
||||
getValueAsHtml: ({invisibles, hasIndentGuide})->
|
||||
invisibles ?= {}
|
||||
getValueAsHtml: ({hasIndentGuide})->
|
||||
if @isHardTab
|
||||
classes = 'hard-tab'
|
||||
classes += ' indent-guide' if hasIndentGuide
|
||||
classes += ' invisible-character' if invisibles.tab
|
||||
value = if invisibles.tab then @value.replace(StartCharacterRegex, invisibles.tab) else @value
|
||||
html = "<span class='#{classes}'>#{@escapeString(value)}</span>"
|
||||
classes += ' invisible-character' if @hasInvisibleCharacters
|
||||
html = "<span class='#{classes}'>#{@escapeString(@value)}</span>"
|
||||
else
|
||||
startIndex = 0
|
||||
endIndex = @value.length
|
||||
@@ -151,26 +148,27 @@ class Token
|
||||
leadingHtml = ''
|
||||
trailingHtml = ''
|
||||
|
||||
if @hasLeadingWhitespace and match = LeadingSpaceRegex.exec(@value)
|
||||
if @hasLeadingWhitespace
|
||||
leadingWhitespace = @value.substring(0, @firstNonWhitespaceIndex)
|
||||
|
||||
classes = 'leading-whitespace'
|
||||
classes += ' indent-guide' if hasIndentGuide
|
||||
classes += ' invisible-character' if invisibles.space
|
||||
classes += ' invisible-character' if @hasInvisibleCharacters
|
||||
|
||||
match[0] = match[0].replace(CharacterRegex, invisibles.space) if invisibles.space
|
||||
leadingHtml = "<span class='#{classes}'>#{match[0]}</span>"
|
||||
leadingHtml = "<span class='#{classes}'>#{leadingWhitespace}</span>"
|
||||
startIndex = @firstNonWhitespaceIndex
|
||||
|
||||
startIndex = match[0].length
|
||||
if @hasTrailingWhitespace
|
||||
tokenIsOnlyWhitespace = @firstTrailingWhitespaceIndex is 0
|
||||
trailingWhitespace = @value.substring(@firstTrailingWhitespaceIndex)
|
||||
|
||||
if @hasTrailingWhitespace and match = TrailingSpaceRegex.exec(@value)
|
||||
tokenIsOnlyWhitespace = match[0].length is @value.length
|
||||
classes = 'trailing-whitespace'
|
||||
classes += ' indent-guide' if hasIndentGuide and not @hasLeadingWhitespace and tokenIsOnlyWhitespace
|
||||
classes += ' invisible-character' if invisibles.space
|
||||
classes += ' invisible-character' if @hasInvisibleCharacters
|
||||
|
||||
match[0] = match[0].replace(CharacterRegex, invisibles.space) if invisibles.space
|
||||
trailingHtml = "<span class='#{classes}'>#{match[0]}</span>"
|
||||
trailingHtml = "<span class='#{classes}'>#{trailingWhitespace}</span>"
|
||||
|
||||
endIndex = match.index
|
||||
endIndex = @firstTrailingWhitespaceIndex
|
||||
|
||||
html = leadingHtml
|
||||
if @value.length > MaxTokenLength
|
||||
|
||||
@@ -19,27 +19,23 @@ class TokenizedBuffer extends Model
|
||||
invalidRows: null
|
||||
visible: false
|
||||
|
||||
constructor: ({@buffer, @tabLength}) ->
|
||||
constructor: ({@buffer, @tabLength, @invisibles}) ->
|
||||
@tabLength ?= atom.config.getPositiveInt('editor.tabLength', 2)
|
||||
|
||||
@subscribe atom.syntax, 'grammar-added grammar-updated', (grammar) =>
|
||||
if grammar.injectionSelector?
|
||||
@resetTokenizedLines() if @hasTokenForSelector(grammar.injectionSelector)
|
||||
@retokenizeLines() if @hasTokenForSelector(grammar.injectionSelector)
|
||||
else
|
||||
newScore = grammar.getScore(@buffer.getPath(), @buffer.getText())
|
||||
@setGrammar(grammar, newScore) if newScore > @currentGrammarScore
|
||||
|
||||
@on 'grammar-changed grammar-updated', => @resetTokenizedLines()
|
||||
@on 'grammar-changed grammar-updated', => @retokenizeLines()
|
||||
@subscribe @buffer, "changed", (e) => @handleBufferChange(e)
|
||||
@subscribe @buffer, "path-changed", =>
|
||||
@bufferPath = @buffer.getPath()
|
||||
@reloadGrammar()
|
||||
|
||||
@subscribe @$tabLength.changes, (tabLength) =>
|
||||
lastRow = @buffer.getLastRow()
|
||||
@tokenizedLines = @buildPlaceholderTokenizedLinesForRows(0, lastRow)
|
||||
@invalidateRow(0)
|
||||
@emit "changed", { start: 0, end: lastRow, delta: 0 }
|
||||
@subscribe @$tabLength.changes, (tabLength) => @retokenizeLines()
|
||||
|
||||
@subscribe atom.config.observe 'editor.tabLength', callNow: false, =>
|
||||
@setTabLength(atom.config.getPositiveInt('editor.tabLength', 2))
|
||||
@@ -59,7 +55,7 @@ class TokenizedBuffer extends Model
|
||||
@unsubscribe(@grammar) if @grammar
|
||||
@grammar = grammar
|
||||
@currentGrammarScore = score ? grammar.getScore(@buffer.getPath(), @buffer.getText())
|
||||
@subscribe @grammar, 'grammar-updated', => @resetTokenizedLines()
|
||||
@subscribe @grammar, 'grammar-updated', => @retokenizeLines()
|
||||
@emit 'grammar-changed', grammar
|
||||
|
||||
reloadGrammar: ->
|
||||
@@ -74,11 +70,13 @@ class TokenizedBuffer extends Model
|
||||
return true if selector.matches(token.scopes)
|
||||
false
|
||||
|
||||
resetTokenizedLines: ->
|
||||
@tokenizedLines = @buildPlaceholderTokenizedLinesForRows(0, @buffer.getLastRow())
|
||||
retokenizeLines: ->
|
||||
lastRow = @buffer.getLastRow()
|
||||
@tokenizedLines = @buildPlaceholderTokenizedLinesForRows(0, lastRow)
|
||||
@invalidRows = []
|
||||
@invalidateRow(0)
|
||||
@fullyTokenized = false
|
||||
@emit "changed", {start: 0, end: lastRow, delta: 0}
|
||||
|
||||
setVisible: (@visible) ->
|
||||
@tokenizeInBackground() if @visible
|
||||
@@ -94,6 +92,11 @@ class TokenizedBuffer extends Model
|
||||
# tabLength - A {Number} that defines the new tab length.
|
||||
setTabLength: (@tabLength) ->
|
||||
|
||||
setInvisibles: (invisibles) ->
|
||||
if invisibles isnt @invisibles
|
||||
@invisibles = invisibles
|
||||
@retokenizeLines()
|
||||
|
||||
tokenizeInBackground: ->
|
||||
return if not @visible or @pendingChunk or not @isAlive()
|
||||
@pendingChunk = true
|
||||
@@ -206,15 +209,16 @@ class TokenizedBuffer extends Model
|
||||
tokens = [new Token(value: line, scopes: [@grammar.scopeName])]
|
||||
tabLength = @getTabLength()
|
||||
indentLevel = @indentLevelForRow(row)
|
||||
new TokenizedLine({tokens, tabLength, indentLevel})
|
||||
lineEnding = @buffer.lineEndingForRow(row)
|
||||
new TokenizedLine({tokens, tabLength, indentLevel, @invisibles, lineEnding})
|
||||
|
||||
buildTokenizedTokenizedLineForRow: (row, ruleStack) ->
|
||||
line = @buffer.lineForRow(row)
|
||||
lineEnding = @buffer.lineEndingForRow(row)
|
||||
tabLength = @getTabLength()
|
||||
indentLevel = @indentLevelForRow(row)
|
||||
{ tokens, ruleStack } = @grammar.tokenizeLine(line, ruleStack, row is 0)
|
||||
new TokenizedLine({tokens, ruleStack, tabLength, lineEnding, indentLevel})
|
||||
{tokens, ruleStack} = @grammar.tokenizeLine(line, ruleStack, row is 0)
|
||||
new TokenizedLine({tokens, ruleStack, tabLength, lineEnding, indentLevel, @invisibles})
|
||||
|
||||
# FIXME: benogle says: These are actually buffer rows as all buffer rows are
|
||||
# accounted for in @tokenizedLines
|
||||
|
||||
@@ -1,10 +1,16 @@
|
||||
_ = require 'underscore-plus'
|
||||
|
||||
NonWhitespaceRegex = /\S/
|
||||
LeadingWhitespaceRegex = /^\s*/
|
||||
TrailingWhitespaceRegex = /\s*$/
|
||||
RepeatedSpaceRegex = /[ ]/g
|
||||
idCounter = 1
|
||||
|
||||
module.exports =
|
||||
class TokenizedLine
|
||||
constructor: ({tokens, @lineEnding, @ruleStack, @startBufferColumn, @fold, @tabLength, @indentLevel}) ->
|
||||
endOfLineInvisibles: null
|
||||
|
||||
constructor: ({tokens, @lineEnding, @ruleStack, @startBufferColumn, @fold, @tabLength, @indentLevel, @invisibles}) ->
|
||||
@startBufferColumn ?= 0
|
||||
@tokens = @breakOutAtomicTokens(tokens)
|
||||
@text = @buildText()
|
||||
@@ -12,6 +18,9 @@ class TokenizedLine
|
||||
|
||||
@id = idCounter++
|
||||
@markLeadingAndTrailingWhitespaceTokens()
|
||||
if @invisibles
|
||||
@substituteInvisibleCharacters()
|
||||
@buildEndOfLineInvisibles() if @lineEnding?
|
||||
|
||||
buildText: ->
|
||||
text = ""
|
||||
@@ -90,12 +99,14 @@ class TokenizedLine
|
||||
tokens: leftTokens
|
||||
startBufferColumn: @startBufferColumn
|
||||
ruleStack: @ruleStack
|
||||
invisibles: @invisibles
|
||||
lineEnding: null
|
||||
)
|
||||
rightFragment = new TokenizedLine(
|
||||
tokens: rightTokens
|
||||
startBufferColumn: @bufferColumnForScreenColumn(column)
|
||||
ruleStack: @ruleStack
|
||||
invisibles: @invisibles
|
||||
lineEnding: @lineEnding
|
||||
)
|
||||
[leftFragment, rightFragment]
|
||||
@@ -133,15 +144,55 @@ class TokenizedLine
|
||||
outputTokens
|
||||
|
||||
markLeadingAndTrailingWhitespaceTokens: ->
|
||||
firstNonWhitespacePosition = @text.search(/\S/)
|
||||
firstTrailingWhitespacePosition = @text.search(/\s*$/)
|
||||
lineIsWhitespaceOnly = firstTrailingWhitespacePosition is 0
|
||||
position = 0
|
||||
for token, i in @tokens
|
||||
token.hasLeadingWhitespace = position < firstNonWhitespacePosition
|
||||
firstNonWhitespaceIndex = @text.search(NonWhitespaceRegex)
|
||||
firstTrailingWhitespaceIndex = @text.search(TrailingWhitespaceRegex)
|
||||
lineIsWhitespaceOnly = firstTrailingWhitespaceIndex is 0
|
||||
index = 0
|
||||
for token in @tokens
|
||||
if index < firstNonWhitespaceIndex
|
||||
token.hasLeadingWhitespace = true
|
||||
token.firstNonWhitespaceIndex = Math.min(index + token.value.length, firstNonWhitespaceIndex - index)
|
||||
# Only the *last* segment of a soft-wrapped line can have trailing whitespace
|
||||
token.hasTrailingWhitespace = @lineEnding? and (position + token.value.length > firstTrailingWhitespacePosition)
|
||||
position += token.value.length
|
||||
if @lineEnding? and (index + token.value.length > firstTrailingWhitespaceIndex)
|
||||
token.hasTrailingWhitespace = true
|
||||
token.firstTrailingWhitespaceIndex = Math.max(0, firstTrailingWhitespaceIndex - index)
|
||||
index += token.value.length
|
||||
|
||||
substituteInvisibleCharacters: ->
|
||||
invisibles = @invisibles
|
||||
changedText = false
|
||||
|
||||
for token, i in @tokens
|
||||
if token.isHardTab
|
||||
if invisibles.tab
|
||||
token.value = invisibles.tab + token.value.substring(invisibles.tab.length)
|
||||
token.hasInvisibleCharacters = true
|
||||
changedText = true
|
||||
else
|
||||
if invisibles.space
|
||||
if token.hasLeadingWhitespace
|
||||
token.value = token.value.replace LeadingWhitespaceRegex, (leadingWhitespace) ->
|
||||
leadingWhitespace.replace RepeatedSpaceRegex, invisibles.space
|
||||
token.hasInvisibleCharacters = true
|
||||
changedText = true
|
||||
if token.hasTrailingWhitespace
|
||||
token.value = token.value.replace TrailingWhitespaceRegex, (leadingWhitespace) ->
|
||||
leadingWhitespace.replace RepeatedSpaceRegex, invisibles.space
|
||||
token.hasInvisibleCharacters = true
|
||||
changedText = true
|
||||
|
||||
@text = @buildText() if changedText
|
||||
|
||||
buildEndOfLineInvisibles: ->
|
||||
@endOfLineInvisibles = []
|
||||
{cr, eol} = @invisibles
|
||||
|
||||
switch @lineEnding
|
||||
when '\r\n'
|
||||
@endOfLineInvisibles.push(cr) if cr
|
||||
@endOfLineInvisibles.push(eol) if eol
|
||||
when '\n'
|
||||
@endOfLineInvisibles.push(eol) if eol
|
||||
|
||||
isComment: ->
|
||||
for token in @tokens
|
||||
|
||||
@@ -23,9 +23,9 @@ class WindowEventHandler
|
||||
@subscribe ipc, 'context-command', (command, args...) ->
|
||||
$(atom.contextMenu.activeElement).trigger(command, args...)
|
||||
|
||||
@subscribe $(window), 'focus', -> $("body").removeClass('is-blurred')
|
||||
@subscribe $(window), 'focus', -> document.body.classList.remove('is-blurred')
|
||||
|
||||
@subscribe $(window), 'blur', -> $("body").addClass('is-blurred')
|
||||
@subscribe $(window), 'blur', -> document.body.classList.add('is-blurred')
|
||||
|
||||
@subscribe $(window), 'window:open-path', (event, {pathToOpen, initialLine, initialColumn}) ->
|
||||
unless fs.isDirectorySync(pathToOpen)
|
||||
@@ -35,13 +35,16 @@ class WindowEventHandler
|
||||
confirmed = atom.workspaceView?.confirmClose()
|
||||
atom.hide() if confirmed and not @reloadRequested and atom.getCurrentWindow().isWebViewFocused()
|
||||
@reloadRequested = false
|
||||
|
||||
atom.storeDefaultWindowDimensions()
|
||||
atom.storeWindowDimensions()
|
||||
atom.unloadEditorWindow() if confirmed
|
||||
|
||||
confirmed
|
||||
|
||||
@subscribe $(window), 'blur unload', ->
|
||||
atom.storeDefaultWindowDimensions()
|
||||
@subscribe $(window), 'blur', -> atom.storeDefaultWindowDimensions()
|
||||
|
||||
@subscribe $(window), 'unload', ->
|
||||
atom.storeWindowDimensions()
|
||||
@subscribe $(window), 'unload', -> atom.removeEditorWindow()
|
||||
|
||||
@subscribeToCommand $(window), 'window:toggle-full-screen', -> atom.toggleFullScreen()
|
||||
|
||||
@@ -57,8 +60,7 @@ class WindowEventHandler
|
||||
|
||||
@subscribeToCommand $(document), 'core:focus-previous', @focusPrevious
|
||||
|
||||
@subscribe $(document), 'keydown', (event) ->
|
||||
atom.keymaps.handleKeyboardEvent(event.originalEvent)
|
||||
document.addEventListener 'keydown', @onKeydown
|
||||
|
||||
@subscribe $(document), 'drop', (e) ->
|
||||
e.preventDefault()
|
||||
@@ -95,6 +97,10 @@ class WindowEventHandler
|
||||
bindCommandToAction('core:redo', 'redo:')
|
||||
bindCommandToAction('core:select-all', 'selectAll:')
|
||||
|
||||
onKeydown: (event) ->
|
||||
atom.keymaps.handleKeyboardEvent(event)
|
||||
event.stopImmediatePropagation()
|
||||
|
||||
openLink: ({target, currentTarget}) ->
|
||||
location = target?.getAttribute('href') or currentTarget?.getAttribute('href')
|
||||
if location and location[0] isnt '#' and /^https?:\/\//.test(location)
|
||||
|
||||
@@ -110,6 +110,7 @@ class WorkspaceView extends View
|
||||
atom.project.on 'path-changed', => @updateTitle()
|
||||
@on 'pane-container:active-pane-item-changed', => @updateTitle()
|
||||
@on 'pane:active-item-title-changed', '.active.pane', => @updateTitle()
|
||||
@on 'pane:active-item-modified-status-changed', '.active.pane', => @updateDocumentEdited()
|
||||
|
||||
@command 'application:about', -> ipc.send('command', 'application:about')
|
||||
@command 'application:run-all-specs', -> ipc.send('command', 'application:run-all-specs')
|
||||
@@ -210,19 +211,28 @@ class WorkspaceView extends View
|
||||
confirmClose: ->
|
||||
@panes.confirmClose()
|
||||
|
||||
# Updates the application's title, based on whichever file is open.
|
||||
# Updates the application's title and proxy icon based on whichever file is
|
||||
# open.
|
||||
updateTitle: ->
|
||||
if projectPath = atom.project.getPath()
|
||||
if item = @getModel().getActivePaneItem()
|
||||
@setTitle("#{item.getTitle?() ? 'untitled'} - #{projectPath}")
|
||||
title = "#{item.getTitle?() ? 'untitled'} - #{projectPath}"
|
||||
@setTitle(title, item.getPath?())
|
||||
else
|
||||
@setTitle(projectPath)
|
||||
@setTitle(projectPath, projectPath)
|
||||
else
|
||||
@setTitle('untitled')
|
||||
|
||||
# Sets the application's title.
|
||||
setTitle: (title) ->
|
||||
# Sets the application's title (and the proxy icon on OS X)
|
||||
setTitle: (title, proxyIconPath='') ->
|
||||
document.title = title
|
||||
atom.setRepresentedFilename(proxyIconPath)
|
||||
|
||||
# On OS X, fades the application window's proxy icon when the current file
|
||||
# has been modified.
|
||||
updateDocumentEdited: ->
|
||||
modified = @model.getActivePaneItem()?.isModified?() ? false
|
||||
atom.setDocumentEdited(modified)
|
||||
|
||||
# Get all editor views.
|
||||
#
|
||||
|
||||
@@ -30,7 +30,7 @@
|
||||
}
|
||||
|
||||
.cursors.blink-off .cursor {
|
||||
visibility: hidden;
|
||||
opacity: 0;
|
||||
}
|
||||
|
||||
.horizontal-scrollbar {
|
||||
|
||||
@@ -43,6 +43,10 @@ div > .inline-block-tight:last-child {
|
||||
margin-right: 0;
|
||||
}
|
||||
|
||||
.inline-block .inline-block {
|
||||
vertical-align: top;
|
||||
}
|
||||
|
||||
// Use left margin when it's in a float: right element.
|
||||
// Sets the margin correctly when inline blocks are hidden and shown.
|
||||
.pull-right {
|
||||
|
||||
Referência em uma Nova Issue
Bloquear um usuário