Comparar commits

..

22 Commits

Autor SHA1 Mensagem Data
Nathan Sobo 85b95ebda5 Re-render everything if scrolling more than a page 2014-05-06 17:08:52 -06:00
Nathan Sobo c6beefc3c2 Render each line as its own texture on the GPU 2014-05-06 12:45:25 -06:00
Nathan Sobo eb9b3eddd8 Correctly handle updates that replace all the lines 2014-05-06 12:45:09 -06:00
Nathan Sobo d33cad1a06 Incrementally update lines when scrolling and disable gutter
React seems to be taking a long time to diff gutter lines and lines
when scrolling. This is an experiment to remove that overhead.
2014-05-06 11:17:37 -06:00
Nathan Sobo 2688e7ff56 Start optimization experiment: Render lines manually
This is just setting innerHTML of the lines div every time, which is
obviously slow. Next step, draw only the newest lines unless the line
height has changed.
2014-05-06 10:17:07 -06:00
Nathan Sobo 3810167feb Only refresh editor scrollbars on stylesheet changes that require it
If a stylesheet is added or removed, we check if it contains a selector
for scrollbars before refreshing anything.
2014-05-05 18:58:45 -06:00
Nathan Sobo efc336bf8e Emit stylesheet-added/removed from ThemeManager w/ CSSStyleSheet objects
This enables subscribers to detect not just that stylesheets have
changed, but specifically how they have changed. This is used by the
React editor component to only refresh scrollbars when a stylesheet
that actually contains selectors for scrollbar elements is added or
removed.
2014-05-05 18:58:45 -06:00
Nathan Sobo dfcf2af1e1 Default scrollbar height/width to 15 when it's measure as 0
A 0 measurement indicates that overlay scrollbars are enabled, so we
just fall back to 15px in that case so the user can hover directly over
the scrollbar to scroll.
2014-05-05 18:58:45 -06:00
Nathan Sobo 084dae1775 Hide and show scrollbars before measuring them after stylesheet changes
We measure the scrollbar-corner node when there's a stylesheet change,
but Chromium won't apply the new style if it was already visible before
the change. This commit hides and shows it before measuring so we get
accurate values.
2014-05-05 18:58:45 -06:00
Nathan Sobo 1270af928f Explicitly assign dummy scrollbars to the correct width/height
Previously, dummy scrollbars were always 15px wide/tall. This caused
them to obscure the ability to click for the entire 15px region, even if
the actual scrollbar was styled to be much thinner. Now we explicitly
measure the size of scrollbars on mount and when the stylesheets change
and set the height/width explicitly.
2014-05-05 18:58:45 -06:00
Nathan Sobo 644d0c72c6 Hide scrollbar when not scrollable in a given direction 2014-05-05 18:58:45 -06:00
Nathan Sobo bbef96d583 Add a dummy scrollbar corner
Horizontal / vertical scrollbars render a 'corner' on the lower right
when they would otherwise overlap. I previously relied on drawing both
dummy scrollbars at their full width/height so the corner got rendered,
but that interfered with the display of the horizontal scrollbar in
certain circumstances because it was too wide to scroll. This commit
provides that behavior with an absolutely positioned div with the same
dimensions as the intersection of scrollbars when both are visible.
2014-05-05 18:58:44 -06:00
Nathan Sobo df373a0024 Don't allow spec window size to interfere with the size of the editor 2014-05-05 18:58:44 -06:00
Nathan Sobo db70a23c1a Don't obscure last character of long lines with vertical scrollbar
This entailed quite a few changes to dial in scrollbars. The scrollbars
are now adjusted in size to account for the width of the opposite
scrollbar. If the width or height are not explicitly constrained and we
are scrollable in the opposite direction that is constrained, we account
for the width of the opposite scrollbar in assigning a natural height
or width based on the content.
2014-05-05 18:58:44 -06:00
Nathan Sobo c5f73840f8 Account for gutter width in scrollWidth of horizontal scrollbar
Because the scrollbar now spans the entire editor but the scrollable
area does not include the gutter, we need to add the current width of
the gutter to the scroll width of the horizontal scrollbar to allow
it to scroll to the end of the longest lines.
2014-05-05 18:58:44 -06:00
Nathan Sobo f95e06cf64 Remove stray return in spec 2014-05-05 18:58:44 -06:00
Nathan Sobo 4f62352565 Update line number padding when max digits changes 2014-05-05 18:58:44 -06:00
Nathan Sobo 3f4274f724 Remove logging 2014-05-05 18:58:44 -06:00
Nathan Sobo 42c645c98e Fix specs that broke when accounting for horizontal scrollbar height 2014-05-05 18:58:44 -06:00
Nathan Sobo 55af1c1a46 Respect horizontal scrollbar when rendering the vertical, and vice versa
We set overflow to hidden in the opposite scroll direction only if we
can't actually scroll in that direction, causing the white square where
neither scrollbar overlaps to appear at the lower right corner.
2014-05-05 18:58:44 -06:00
Nathan Sobo 1ad394b1ea Update scrollTop to valid position when scrollbar disappears 2014-05-05 18:58:44 -06:00
Nathan Sobo 7a88376d78 Revert "Revert "Don't obscure the last line of the editor with the horizontal scrollbar""
This reverts commit 1d634e471e.
2014-05-05 18:58:44 -06:00
79 arquivos alterados com 856 adições e 1666 exclusões
-1
Ver Arquivo
@@ -1,7 +1,6 @@
*.swp
*~
.DS_Store
Thumbs.db
.project
.svn
.nvm-version
+46 -69
Ver Arquivo
@@ -1,100 +1,77 @@
# :tada: Contributing to Atom :tada:
The following is a set of guidelines for contributing to Atom and its packages,
which are hosted in the [Atom Organization](https://github.com/atom) on GitHub.
If you're unsure which package is causing your problem or if you're having an
issue with Atom core, please use the feedback form in the application or email
[atom@github.com](mailto:atom@github.com). These are just guidelines, not rules,
use your best judgement and feel free to propose changes to this document in a
pull request.
These are just guidelines, not rules, use your best judgement and feel free
to propose changes to this document in a pull request.
## Submitting Issues
* Include screenshots and animated GIFs whenever possible; they are immensely
helpful.
* Include the behavior you expected and other places you've seen that behavior
such as Emacs, vi, Xcode, etc.
* Check the dev tools (`alt-cmd-i`) for errors and stack traces to include.
* On Mac, check Console.app for stack traces to include if reporting a crash.
* Perform a cursory search to see if a similar issue has already been submitted.
## Issues
* Include screenshots and animated GIFs whenever possible, they are immensely
helpful.
* Include the behavior you expected to happen and other places you've seen
that behavior such as Emacs, vi, Xcode, etc.
* Check the Console app for stack traces to include if reporting a crash.
* Check the Dev tools (`alt-cmd-i`) for errors and stack traces to include.
### Package Repositories
This is the repository for the core Atom editor only. Atom comes bundled with
many packages and themes that are stored in other repos under the
[Atom organization](https://github.com/atom) such as
[tabs](https://github.com/atom/tabs),
[atom organization](https://github.com/atom) such as [tabs](https://github.com/atom/tabs),
[find-and-replace](https://github.com/atom/find-and-replace),
[language-javascript](https://github.com/atom/language-javascript), and
[atom-light-ui](http://github.com/atom/atom-light-ui).
[language-javascript](https://github.com/atom/language-javascript),
and [atom-light-ui](http://github.com/atom/atom-light-ui).
For more information on how to work with Atom's official packages, see
[Contributing to Atom Packages](https://atom.io/docs/latest/contributing-to-packages.html)
If you think you know which package is causing the issue you are reporting, feel
free to open up the issue in that specific repository instead. When in doubt
just open the issue here but be aware that it may get closed here and reopened
in the proper package's repository.
## Pull Requests
* Include screenshots and animated GIFs in your pull request whenever possible.
* Follow the [CoffeeScript](#coffeescript-styleguide),
[JavaScript](https://github.com/styleguide/javascript),
and [CSS](https://github.com/styleguide/css) styleguides.
* Include thoughtfully-worded, well-structured
[Jasmine](http://jasmine.github.io/) specs.
* Document new code based on the
[Documentation Styleguide](#documentation-styleguide)
* End files with a newline.
* Place requires in the following order:
* Include screenshots and animated GIFs whenever possible.
* Follow the [CoffeeScript](#coffeescript-styleguide),
[JavaScript](https://github.com/styleguide/javascript),
and [CSS](https://github.com/styleguide/css) styleguides
* Include thoughtfully worded [Jasmine](http://pivotal.github.com/jasmine)
specs
* Avoid placing files in `vendor`. 3rd-party packages should be added as a
`package.json` dependency.
* Files end with a newline.
* Requires should be in the following order:
* Built in Node Modules (such as `path`)
* Built in Atom and Atom Shell Modules (such as `atom`, `shell`)
* Local Modules (using relative paths)
* Place class properties in the following order:
* Class methods and properties (methods starting with a `@`)
* Instance methods and properties
* Avoid platform-dependent code:
* Class variables and methods should be in the following order:
* Class methods (methods starting with a `@`)
* Instance methods
* Beware of platform differences
* Use `require('atom').fs.getHomeDirectory()` to get the home directory.
* Use `path.join()` to concatenate filenames.
* Use `os.tmpdir()` rather than `/tmp` when you need to reference the
temporary directory.
* Temporary directory is not `/tmp` on Windows, use `os.tmpdir()` when
possible
## Git Commit Messages
* Use the present tense ("Add feature" not "Added feature")
* Use the imperative mood ("Move cursor to..." not "Moves cursor to...")
* Limit the first line to 72 characters or less
* Reference issues and pull requests liberally
* Consider starting the commit message with an applicable emoji:
* :lipstick: `:lipstick:` when improving the format/structure of the code
* :racehorse: `:racehorse:` when improving performance
* :non-potable_water: `:non-potable_water:` when plugging memory leaks
* :memo: `:memo:` when writing docs
* :penguin: `:penguin:` when fixing something on Linux
* :apple: `:apple:` when fixing something on Mac OS
* :bug: `:bug:` when fixing a bug
* :fire: `:fire:` when removing code or files
* :green_heart: `:green_heart:` when fixing the CI build
* :white_check_mark: `:white_check_mark:` when adding tests
* :lock: `:lock:` when dealing with security
* Use the present tense
* Reference issues and pull requests liberally
* Consider starting the commit message with an applicable emoji:
* :lipstick: when improving the format/structure of the code
* :racehorse: when improving performance
* :non-potable_water: when plugging memory leaks
* :memo: when writing docs
* :penguin: when fixing something on Linux
## CoffeeScript Styleguide
* Set parameter defaults without spaces around the equal sign
* `clear = (count=1) ->` instead of `clear = (count = 1) ->`
* Use parentheses if it improves code clarity.
* Prefer alphabetic keywords to symbolic keywords:
* `a is b` instead of `a == b`
* Avoid spaces inside the curly-braces of hash literals:
* `{a: 1, b: 2}` instead of `{ a: 1, b: 2 }`
* Include a single line of whitespace between methods.
* `clear = (count=1) ->` instead of `clear = (count = 1) ->`
## Documentation Styleguide
* Use [TomDoc](http://tomdoc.org).
* Use [Markdown](https://daringfireball.net/projects/markdown).
* Reference methods and classes in markdown with the custom `{}` notation:
* Reference classes with `{ClassName}`
* Reference instance methods with `{ClassName::methodName}`
* Reference class methods with `{ClassName.methodName}`
* Delegate to comments elsewhere with `{Delegates to: ClassName.methodName}`
style notation.
* Reference classes with `{ClassName}`.
* Reference instance methods with `{ClassName::methodName}`.
* Reference class methods with `{ClassName.methodName}`.
* Delegate to comments elsewhere with `{Delegates to: ClassName.methodName}`
style notation.
### Example
+15 -7
Ver Arquivo
@@ -1,8 +1,15 @@
![Atom](https://cloud.githubusercontent.com/assets/72919/2874231/3af1db48-d3dd-11e3-98dc-6066f8bc766f.png)
Atom is a hackable text editor for the 21st century, built on [atom-shell](http://github.com/atom/atom-shell), and based on everything we love about our favorite editors. We designed it to be deeply customizable, but still approachable using the default configuration.
Atom is a hackable text editor for the 21st century.
Visit [atom.io](https://atom.io) to learn more.
Atom is open source and built on top of [atom-shell](http://github.com/atom/atom-shell).
Atom is designed to be customizable, but also usable without needing to edit a config file.
Atom is modern, approachable, and hackable to the core.
Visit [atom.io](http://atom.io)
to learn more.
## Installing
@@ -12,10 +19,11 @@ Atom will automatically update when a new release is available.
## Building
* [Linux](docs/build-instructions/linux.md)
* [OS X](docs/build-instructions/os-x.md)
* [FreeBSD](docs/build-instructions/freebsd.md)
* [Windows](docs/build-instructions/windows.md)
```sh
git clone git@github.com:atom/atom.git
cd atom
script/build # Creates application at /Applications/Atom.app
```
## Developing
Check out the [guides](https://atom.io/docs/latest) and the [API reference](https://atom.io/docs/api).
Check out the [guides](https://atom.io/docs/latest) and the [API reference](atom.io/docs/api).
+1 -1
Ver Arquivo
@@ -6,6 +6,6 @@
"url": "https://github.com/atom/atom.git"
},
"dependencies": {
"atom-package-manager": "0.57.0"
"atom-package-manager": "0.45.0"
}
}
+9 -17
Ver Arquivo
@@ -1,17 +1,17 @@
#!/bin/bash
if [ "$(uname)" == 'Darwin' ]; then
if [ "`uname`" == 'Darwin' ]; then
OS='Mac'
elif [ "$(expr substr $(uname -s) 1 5)" == 'Linux' ]; then
elif [ "`expr substr $(uname -s) 1 5`" == 'Linux' ]; then
OS='Linux'
elif [ "$(expr substr $(uname -s) 1 10)" == 'MINGW32_NT' ]; then
elif [ "`expr substr $(uname -s) 1 10`" == 'MINGW32_NT' ]; then
OS='Cygwin'
else
echo "Your platform ($(uname -a)) is not supported."
echo "Your platform (`uname -a`) is not supported."
exit 1
fi
while getopts ":wtfvh-:" opt; do
while getopts ":wtfvhs-:" opt; do
case "$opt" in
-)
case "${OPTARG}" in
@@ -66,25 +66,17 @@ if [ $OS == 'Mac' ]; then
open -a "$ATOM_PATH/$ATOM_APP_NAME" -n --args --executed-from="$(pwd)" --pid=$$ "$@"
fi
elif [ $OS == 'Linux' ]; then
SCRIPT=$(readlink -f "$0")
USR_DIRECTORY=$(readlink -f $(dirname $SCRIPT)/..)
SCRIPT=`readlink -f "$0"`
USR_DIRECTORY=`readlink -f $(dirname $SCRIPT)/..`
ATOM_PATH="$USR_DIRECTORY/share/atom/atom"
: ${TMPDIR:=/tmp}
[ -x "$ATOM_PATH" ] || ATOM_PATH="$TMPDIR/atom-build/Atom/atom"
[ -x "$ATOM_PATH" ] || ATOM_PATH='/tmp/atom-build/Atom/atom'
if [ $EXPECT_OUTPUT ]; then
"$ATOM_PATH" --executed-from="$(pwd)" --pid=$$ "$@"
exit $?
else
(
nohup "$ATOM_PATH" --executed-from="$(pwd)" --pid=$$ "$@" > "$TMPDIR/atom-nohup.out" 2>&1
if [ $? -ne 0 ]; then
cat "$TMPDIR/atom-nohup.out"
exit $?
fi
) &
nohup "$ATOM_PATH" --executed-from="$(pwd)" --pid=$$ "$@" > /dev/null 2>&1 &
fi
fi
+18 -6
Ver Arquivo
@@ -36,23 +36,35 @@ module.exports = (grunt) ->
grunt.log.write = (args...) -> grunt.log
[major, minor, patch] = packageJson.version.split('.')
tmpDir = os.tmpdir()
appName = if process.platform is 'darwin' then 'Atom.app' else 'Atom'
buildDir = grunt.option('build-dir') ? path.join(tmpDir, 'atom-build')
atomShellDownloadDir = path.join(os.tmpdir(), 'atom-cached-atom-shells')
symbolsDir = path.join(buildDir, 'Atom.breakpad.syms')
shellAppDir = path.join(buildDir, appName)
if process.platform is 'win32'
appName = 'Atom'
tmpDir = os.tmpdir()
buildDir = grunt.option('build-dir') ? path.join(tmpDir, 'atom-build')
symbolsDir = path.join(buildDir, 'Atom.breakpad.syms')
shellAppDir = path.join(buildDir, appName)
contentsDir = shellAppDir
appDir = path.join(shellAppDir, 'resources', 'app')
atomShellDownloadDir = path.join(os.tmpdir(), 'atom-cached-atom-shells')
installDir = path.join(process.env.ProgramFiles, appName)
else if process.platform is 'darwin'
appName = 'Atom.app'
tmpDir = '/tmp'
buildDir = grunt.option('build-dir') ? path.join(tmpDir, 'atom-build')
symbolsDir = path.join(buildDir, 'Atom.breakpad.syms')
shellAppDir = path.join(buildDir, appName)
contentsDir = path.join(shellAppDir, 'Contents')
appDir = path.join(contentsDir, 'Resources', 'app')
atomShellDownloadDir = '/tmp/atom-cached-atom-shells'
installDir = path.join('/Applications', appName)
else
appName = 'Atom'
tmpDir = '/tmp'
buildDir = grunt.option('build-dir') ? path.join(tmpDir, 'atom-build')
symbolsDir = path.join(buildDir, 'Atom.breakpad.syms')
shellAppDir = path.join(buildDir, appName)
contentsDir = shellAppDir
appDir = path.join(shellAppDir, 'resources', 'app')
atomShellDownloadDir = '/tmp/atom-cached-atom-shells'
installDir = process.env.INSTALL_PREFIX ? '/usr/local'
coffeeConfig =
+1 -3
Ver Arquivo
@@ -18,7 +18,7 @@
"grunt-contrib-coffee": "~0.9.0",
"grunt-contrib-less": "~0.8.0",
"grunt-cson": "0.8.0",
"grunt-download-atom-shell": "~0.7.2",
"grunt-download-atom-shell": "~0.7.0",
"grunt-lesslint": "0.13.0",
"grunt-markdown": "~0.4.0",
"grunt-peg": "~1.1.0",
@@ -27,8 +27,6 @@
"json-front-matter": "~0.1.3",
"legal-eagle": "~0.4.0",
"minidump": "0.5.x",
"read-package-json": "1.1.8",
"normalize-package-data": "0.2.12",
"rcedit": "~0.1.2",
"request": "~2.27.0",
"rimraf": "~2.2.2",
+1 -1
Ver Arquivo
@@ -5,7 +5,7 @@ module.exports = (grunt) ->
{rm} = require('./task-helpers')(grunt)
grunt.registerTask 'partial-clean', 'Delete some of the build files', ->
tmpdir = os.tmpdir()
tmpdir = if process.platform is 'win32' then os.tmpdir() else '/tmp'
rm grunt.config.get('atom.buildDir')
rm require('../src/coffee-cache').cacheDir
+1 -1
Ver Arquivo
@@ -26,7 +26,7 @@ module.exports = (grunt) ->
getLicenseText = (dependencyLicenses) ->
{keys} = require 'underscore-plus'
text = """
#{fs.readFileSync('LICENSE.md', 'utf8')}
#{fs.readFileSync('LICENSE.md')}
This application bundles the following third-party packages in accordance
with the following licenses:\n\n
+3 -7
Ver Arquivo
@@ -5,18 +5,14 @@ module.exports = (grunt) ->
{spawn} = require('./task-helpers')(grunt)
getVersion = (callback) ->
onBuildMachine = process.env.JANKY_SHA1 and process.env.JANKY_BRANCH is 'master'
inRepository = fs.existsSync(path.resolve(__dirname, '..', '..', '.git'))
{version} = require(path.join(grunt.config.get('atom.appDir'), 'package.json'))
if onBuildMachine or not inRepository
if process.env.JANKY_SHA1 and process.env.JANKY_BRANCH is 'master'
{version} = require(path.join(grunt.config.get('atom.appDir'), 'package.json'))
callback(null, version)
else
cmd = 'git'
args = ['rev-parse', '--short', 'HEAD']
spawn {cmd, args}, (error, {stdout}={}, code) ->
commitHash = stdout?.trim?()
combinedVersion = "#{version}-#{commitHash}"
callback(error, combinedVersion)
callback(error, stdout?.trim?())
grunt.registerTask 'set-version', 'Set the version in the plist and package.json', ->
done = @async()
+3 -3
Ver Arquivo
@@ -10,8 +10,8 @@ keystrokes pass through elements with the class `.editor`:
```coffee
'.editor':
'cmd-delete': 'editor:delete-to-beginning-of-line'
'alt-backspace': 'editor:delete-to-beginning-of-word'
'cmd-delete': 'editor:backspace-to-beginning-of-line'
'alt-backspace': 'editor:backspace-to-beginning-of-word'
'ctrl-A': 'editor:select-to-first-character-of-line'
'ctrl-shift-e': 'editor:select-to-end-of-line'
'cmd-left': 'editor:move-to-first-character-of-line'
@@ -24,7 +24,7 @@ keystrokes pass through elements with the class `.editor`:
Beneath the first selector are several bindings, mapping specific *keystroke
patterns* to *commands*. When an element with the `.editor` class is focused and
`cmd-delete` is pressed, an custom DOM event called
`editor:delete-to-beginning-of-line` is emitted on the `.editor` element.
`editor:backspace-to-beginning-of-line` is emitted on the `.editor` element.
The second selector group also targets editors, but only if they don't have the
`.mini` class. In this example, the commands for code folding don't really make
-24
Ver Arquivo
@@ -1,24 +0,0 @@
## Developing Node Modules
Atom contains a number of packages that are Node modules instead of Atom packages. If you want to
make changes to the Node modules, for instance `atom-keymap`, you have to link them into the
development environment differently than you would a normal Atom package.
### Linking a Node Module Into Your Atom Dev Environment
Here are the steps to run a local version of a node module *not an apm* within Atom. We're using
`atom-keymap` as an example:
```bash
$ git clone https://github.com/atom/atom-keymap.git
$ cd atom-keymap
$ npm install
$ npm link
$ apm rebuild # This is the special step, it makes the npm work with Atom's version of Node
$ cd WHERE-YOU-CLONED-ATOM
$ npm link atom-keymap
$ atom # Should work!
```
After this, you'll have to `npm install` and `apm rebuild` when you make a change to the node
module's code.
-22
Ver Arquivo
@@ -1,22 +0,0 @@
# FreeBSD
FreeBSD -RELEASE 64-bit is the recommended platform.
## Requirements
* FreeBSD
* `pkg install node`
* `pkg install npm`
* `pkg install libgnome-keyring`
* `npm config set python /usr/local/bin/python2 -g` to ensure that gyp uses Python 2
## Instructions
```sh
git clone https://github.com/atom/atom
cd atom
script/build # Creates application at $TMPDIR/atom-build/Atom
sudo script/grunt install # Installs command to /usr/local/bin/atom
```
## Troubleshooting
-49
Ver Arquivo
@@ -1,49 +0,0 @@
# Linux
Ubuntu LTS 12.04 64-bit is the recommended platform.
## Requirements
* OS with 64-bit architecture
* [node.js](http://nodejs.org/download/) v0.10.x
* [npm](http://www.npmjs.org/) v1.4.x
* libgnome-keyring-dev `sudo apt-get install libgnome-keyring-dev` (refer to your distribution's manual on how to install packages if you are not on Debian or Ubuntu-based systems)
* `npm config set python /usr/bin/python2 -g` to ensure that gyp uses Python 2
## Instructions
```sh
git clone https://github.com/atom/atom
cd atom
script/build # Creates application at $TMPDIR/atom-build/Atom
sudo script/grunt install # Installs command to /usr/local/bin/atom
script/grunt mkdeb # Generates a .deb package at $TMPDIR/atom-build
```
## Troubleshooting
### Exception: "TypeError: Unable to watch path"
If you get following error with a big traceback right after Atom starts:
```
TypeError: Unable to watch path
```
you have to increase number of watched files by inotify. For testing if
this is the reason for this error you can issue
```sh
sudo sysctl fs.inotify.max_user_watches=32768
```
and restart Atom. If Atom now works fine, you can make this setting permanent:
```sh
echo 32768 > /proc/sys/fs/inotify/max_user_watches
```
See also https://github.com/atom/atom/issues/2082.
-17
Ver Arquivo
@@ -1,17 +0,0 @@
# OS X
## Requirements
* OS X 10.8 or later
* [node.js](http://nodejs.org/download/) v0.10.x
* Command Line Tools for [Xcode](https://developer.apple.com/xcode/downloads/) (run `xcode-select --install` to install)
## Instructions
```sh
git clone https://github.com/atom/atom
cd atom
script/build # Creates application at /Applications/Atom.app
```
## Troubleshooting
-35
Ver Arquivo
@@ -1,35 +0,0 @@
# Windows
## Requirements
* Windows 7 or later
* [Visual C++ 2010 Express](http://www.visualstudio.com/en-us/downloads/download-visual-studio-vs#DownloadFamilies_4) with [SP1](http://www.microsoft.com/en-us/download/details.aspx?id=23691)
* [node.js](http://nodejs.org/download/) v0.10.x
* [Python](http://www.python.org/download/) v2.7.x
* [GitHub for Windows](http://windows.github.com/)
## Instructions
```bat
# Use the `Git Shell` app which was installed by GitHub for Windows. Also Make
# sure you have logged into the GitHub for Windows GUI App.
cd C:\
git clone https://github.com/atom/atom/
cd atom
script\build
```
## Why do I have to use GitHub for Windows?
You don't, You can use your existing Git! GitHub for Windows's Git Shell is just
easier to set up. You need to have Posix tools in your `%PATH%` (i.e. `grep`,
`sed`, et al.), which isn't the default configuration when you install Git. To
fix this, you probably need to fiddle with your system PATH.
## Troubleshooting
### Common Errors
* `node is not recognized`
* If you just installed node you need to restart your computer before node is
available on your Path.
-52
Ver Arquivo
@@ -1,52 +0,0 @@
# Contributing to Official Atom Packages
If you think you know which package is causing the issue you are reporting, feel
free to open up the issue in that specific repository instead. When in doubt
just open the issue here but be aware that it may get closed here and reopened
in the proper package's repository.
## Hacking on Packages
### Cloning
The first step is creating your own clone. You can of course do this manually
with git, or you can use the `apm develop` command to create a clone based on
the package's `repository` field in the `package.json`.
For example, if you want to make changes to the `tree-view` package, run the
following command:
```
> apm develop tree-view
Cloning https://github.com/atom/tree-view ✓
Installing modules ✓
~/.atom/dev/packages/tree-view -> ~/github/tree-view
```
This clones the `tree-view` repository to `~/github`. If you prefer a different
path, specify it via the `ATOM_REPOS_HOME` environment variable.
### Running in Development Mode
Editing a package in Atom is a bit of a circular experience: you're using Atom
to modify itself. What happens if you temporarily break something? You don't
want the version of Atom you're using to edit to become useless in the process.
For this reason, you'll only want to load packages in **development mode** while
you are working on them. You'll perform your editing in **stable mode**, only
switching to development mode to test your changes.
To open a development mode window, use the "Application: Open Dev" command,
which is normally bound to `cmd-shift-o`. You can also run dev mode from the
command line with `atom --dev`.
To load your package in development mode, create a symlink to it in
`~/.atom/dev/packages`. This occurs automatically when you clone the package
with `apm develop`. You can also run `apm link --dev` and `apm unlink --dev`
from the package directory to create and remove dev-mode symlinks.
### Installing Dependencies
Finally, you need to install the cloned package's dependencies by running
`apm install` within the package directory. This step is also performed
automatically the first time you run `apm develop`, but you'll want to keep
dependencies up to date by running `apm update` after pulling upstream changes.
-1
Ver Arquivo
@@ -1 +0,0 @@
../CONTRIBUTING.md
+142
Ver Arquivo
@@ -0,0 +1,142 @@
# Contributing to Atom Packages
The following is a set of guidelines for contributing to Atom packages, which
are hosted in the [Atom Organization](https://github.com/atom) on GitHub. If
you're unsure which package is causing your problem or if you're having an issue
with Atom core, please use the feedback form in the application or email
[atom@github.com](mailto:atom@github.com).
## Submitting Issues
* Include screenshots and animated GIFs whenever possible; they are immensely
helpful.
* Include the behavior you expected and other places you've seen that behavior
such as Emacs, vi, Xcode, etc.
* Check the dev tools (`alt-cmd-i`) for errors and stack traces to include.
* Check Console.app for stack traces to include if reporting a crash.
* Perform a cursory search to see if a similar issue has already been submitted.
## Hacking on Packages
### Cloning
The first step is creating your own clone. You can of course do this manually
with git, or you can use the `apm develop` command to create a clone based on
the package's `repository` field in the `package.json`.
For example, if you want to make changes to the `tree-view` package, run the
following command:
```
> apm develop tree-view
Cloning https://github.com/atom/tree-view ✓
Installing modules ✓
~/.atom/dev/packages/tree-view -> ~/github/tree-view
```
This clones the `tree-view` repository to `~/github`. If you prefer a different
path, specify it via the `ATOM_REPOS_HOME` environment variable.
### Running in Development Mode
Editing a package in Atom is a bit of a circular experience: you're using Atom
to modify itself. What happens if you temporarily break something? You don't
want the version of Atom you're using to edit to become useless in the process.
For this reason, you'll only want to load packages in **development mode** while
you are working on them. You'll perform your editing in **stable mode**, only
switching to development mode to test your changes.
To open a development mode window, use the "Application: Open Dev" command,
which is normally bound to `cmd-shift-o`. You can also run dev mode from the
command line with `atom --dev`.
To load your package in development mode, create a symlink to it in
`~/.atom/dev/packages`. This occurs automatically when you clone the package
with `apm develop`. You can also run `apm link --dev` and `apm unlink --dev`
from the package directory to create and remove dev-mode symlinks.
### Installing Dependencies
Finally, you need to install the cloned package's dependencies by running
`apm install` within the package directory. This step is also performed
automatically the first time you run `apm develop`, but you'll want to keep
dependencies up to date by running `apm update` after pulling upstream changes.
## Submitting Pull Requests
### Code Guidelines
* Include screenshots and animated GIFs in your pull request whenever possible.
* Follow the [CoffeeScript](#coffeescript-styleguide),
[JavaScript](https://github.com/styleguide/javascript),
and [CSS](https://github.com/styleguide/css) styleguides.
* Include thoughtfully-worded, well-structured
[Jasmine](http://pivotal.github.com/jasmine) specs.
* Document new code based on the
[Documentation Styleguide](#documentation-styleguide)
* End files with a newline.
* Place requires in the following order:
* Built in Node Modules (such as `path`)
* Built in Atom and Atom Shell Modules (such as `atom`, `shell`)
* Local Modules (using relative paths)
* Place class properties in the following order:
* Class methods and properties (methods starting with a `@`)
* Instance methods and properties
* Avoid platform-dependent code:
* Use `require('atom').fs.getHomeDirectory()` to get the home directory.
* Use `path.join()` to concatenate filenames.
* Use `os.tmpdir()` rather than `/tmp` when you need to reference the
temporary directory.
### Commit Message Guidelines
* Use the present tense ("Add feature" not "Added feature")
* Use the imperative mood ("Move cursor to..." not "Moves cursor to...")
* Limit the first line to 72 characters or less
* Reference issues and pull requests liberally
* Consider starting the commit message with an applicable emoji:
* :lipstick: when improving the format/structure of the code
* :racehorse: when improving performance
* :non-potable_water: when plugging memory leaks
* :memo: when writing docs
* :bulb: Check out the [Emoji Cheat Sheet](http://www.emoji-cheat-sheet.com)
for more ideas.
## CoffeeScript Styleguide
* Use parentheses if it improves code clarity.
* Prefer alphabetic keywords to symbolic keywords:
* `a is b` instead of `a == b`
* Avoid spaces inside the curly-braces of hash literals:
* `{a: 1, b: 2}` instead of `{ a: 1, b: 2 }`
* Set parameter defaults without spaces around the equal sign:
* `clear = (count=1) ->` instead of `clear = (count = 1) ->`
* Include a single line of whitespace between methods.
## Documentation Styleguide
* Use [TomDoc](http://tomdoc.org).
* Use [Markdown](https://daringfireball.net/projects/markdown).
* Reference methods and classes in markdown with the custom `{}` notation:
* Reference classes with `{ClassName}`
* Reference instance methods with `{ClassName::methodName}`
* Reference class methods with `{ClassName.methodName}`
### Example
```coffee
# Public: Disable the package with the given name.
#
# This method emits multiple events:
#
# * `package-will-be-disabled` - before the package is disabled.
# * `package-disabled` - after the package is disabled.
#
# name - The {String} name of the package to disable.
# options - The {Object} with disable options (default: {}):
# :trackTime - `true` to track the amount of time disabling took.
# :ignoreErrors - `true` to catch and ignore errors thrown.
# callback - The {Function} to call after the package has been disabled.
#
# Returns `undefined`.
disablePackage: (name, options, callback) ->
```
+2 -2
Ver Arquivo
@@ -20,7 +20,7 @@ apm help init
You should see a message print out with details about the `apm init` command.
If you do not, launch Atom and run the _Atom > Install Shell Commands_ menu
If you do not, launch Atom and run the _Atom > Install Shell Commmands_ menu
to install the `apm` and `atom` commands.
### Convert the Package
@@ -49,4 +49,4 @@ the editor to see it in action!
[plist]: http://en.wikipedia.org/wiki/Property_list
[R]: http://en.wikipedia.org/wiki/R_(programming_language)
[TextMate]: http://macromates.com
[TextMateOrg]: https://github.com/textmate
[TextMateOrg]: https://github.com/textmate/r.tmbundle
+1 -1
Ver Arquivo
@@ -25,7 +25,7 @@ apm help init
You should see a message print out with details about the `apm init` command.
If you do not, launch Atom and run the _Atom > Install Shell Commands_ menu
If you do not, launch Atom and run the _Atom > Install Shell Commmands_ menu
to install the `apm` and `atom` commands.
You can now run `apm help init` to see all the options for initializing new
+1 -1
Ver Arquivo
@@ -34,7 +34,7 @@ apm help install
You should see a message print out with details about the `apm install` command.
If you do not, launch Atom and run the _Atom > Install Shell Commands_ menu
If you do not, launch Atom and run the _Atom > Install Shell Commmands_ menu
to install the `apm` and `atom` commands.
You can also install packages by using the `apm install` command:
-2
Ver Arquivo
@@ -5,7 +5,6 @@
* [Creating a Package](creating-a-package.md)
* [Creating a Theme](creating-a-theme.md)
* [Publishing a Package](publishing-a-package.md)
* [Writing Specs](writing-specs.md)
* [Converting a TextMate Bundle](converting-a-text-mate-bundle.md)
* [Converting a TextMate Theme](converting-a-text-mate-theme.md)
* [Contributing](contributing.md)
@@ -13,7 +12,6 @@
### Advanced Topics
* [Configuration](advanced/configuration.md)
* [Developing Node Modules](advanced/node-modules.md)
* [Keymaps](advanced/keymaps.md)
* [Serialization](advanced/serialization.md)
* [View System](advanced/view-system.md)
+5 -5
Ver Arquivo
@@ -7,7 +7,7 @@ Publishing a package allows other people to install it and use it in Atom. It
is a great way to share what you've made and get feedback and contributions from
others.
This guide assumes your package's name is `my-package` but you should pick a
This guide assumes your package's name is `my-package` and but you should pick a
better name.
### Install apm
@@ -24,7 +24,7 @@ apm help publish
You should see a message print out with details about the `apm publish` command.
If you do not, launch Atom and run the _Atom > Install Shell Commands_ menu
If you do not, launch Atom and run the _Atom > Install Shell Commmands_ menu
to install the `apm` and `atom` commands.
### Prepare Your Package
@@ -42,7 +42,7 @@ If not, there are a few things you should check before publishing:
* Your package is in a Git repository that has been pushed to
[GitHub][github]. Follow [this guide][repo-guide] if your package isn't
already on GitHub.
### Publish Your Package
Before you publish a package it is a good idea to check ahead of time if
@@ -59,7 +59,7 @@ Now let's review what the `apm publish` command does:
3. Creates a new [Git tag][git-tag] for the version being published.
4. Pushes the tag and current branch up to GitHub.
5. Updates atom.io with the new version being published.
Now run the following commands to publish your package:
```sh
@@ -80,7 +80,7 @@ digit of the version before publishing so the published version will be `0.1.0`
and the Git tag created will be `v0.1.0`.
In the future you can run `apm publish major` to publish the `1.0.0` version but
since this was the first version being published it is a good idea to start
since this was the first version being published it is a good idead to start
with a minor release.
### Further Reading
-61
Ver Arquivo
@@ -1,61 +0,0 @@
# Writting specs
Atom uses [Jasmine](http://jasmine.github.io/2.0/introduction.html) as its spec framework. Any new functionality should have specs to guard against regressions.
## Create a new spec
[Atom specs](https://github.com/atom/atom/tree/master/spec) and [package specs](https://github.com/atom/markdown-preview/tree/master/spec) are added to their respective `spec` directory. The example below creates a spec for Atom core.
0. Create a spec file
Spec files **must** end with `-spec` so add `sample-spec.coffee` to `atom/spec`.
0. Add one or more `describe` method
The `describe` method takes two arguments, a description and a function. If the description explains a behavior it typically begins with `when` if it is more like a unit test it begins with the method name.
```coffee
describe "when a test is written", ->
# contents
```
or
```coffee
describe "Editor::moveUp", ->
# contents
```
0. Add one or more `it` method
The `it` method also takes two arugments, a description and a function. Try and make the description flow with the `it` method. For example, a description of `this should work` doesn't read well as `it this should work`. But a description of `should work` sounds great as `it should work`.
```coffee
describe "when a test is written", ->
it "has some expectations that should pass", ->
# Expectations
```
0. Add one or more expectations
The best way to learn about expectations is to read the [jamsine documentation](http://jasmine.github.io/2.0/introduction.html#section-Expectations) about them. Below is a simple example.
```coffee
describe "when a test is written", ->
it "has some expectations that should pass", ->
expect("apples").toEqual("apples")
expect("oranges").not.toEqual("apples")
```
## Runnings specs
Most of the time you'll want to run specs by triggering the `window:run-package-specs` command. This command is not only to run package specs, it is also for Atom core specs. This will run all the specs in the current project's spec directory. If you want to run the Atom core specs and **all** the default package specs trigger the `window:run-all-specs` command.
To run a limited subset of specs use the `fdescribe` or `fit` methods. You can use those to focus a single spec or several specs. In the example above, focusing an individual spec looks like this:
```coffee
describe "when a test is written", ->
fit "has some expectations that should pass", ->
expect("apples").toEqual("apples")
expect("oranges").not.toEqual("apples")
```
-2
Ver Arquivo
@@ -149,8 +149,6 @@ ASCII art professional!
* [Getting your project on GitHub guide](http://guides.github.com/overviews/desktop)
* [Writing specs](writing-specs.md) for your package
* [Creating a package guide](creating-a-package.html) for more information
on the mechanics of packages
+4
Ver Arquivo
@@ -1,5 +1,9 @@
'.editor':
# Platform Bindings
'alt-left': 'editor:move-to-beginning-of-word'
'alt-right': 'editor:move-to-end-of-word'
'alt-shift-left': 'editor:select-to-beginning-of-word'
'alt-shift-right': 'editor:select-to-end-of-word'
'home': 'editor:move-to-first-character-of-line'
'end': 'editor:move-to-end-of-screen-line'
'shift-home': 'editor:select-to-first-character-of-line'
+4 -12
Ver Arquivo
@@ -65,8 +65,6 @@
'cmd-}': 'pane:show-next-item'
'cmd-alt-left': 'pane:show-previous-item'
'cmd-alt-right': 'pane:show-next-item'
'ctrl-tab': 'pane:show-next-item'
'ctrl-shift-tab': 'pane:show-previous-item'
'cmd-=': 'window:increase-font-size'
'cmd-+': 'window:increase-font-size'
'cmd--': 'window:decrease-font-size'
@@ -96,23 +94,17 @@
'cmd-9': 'pane:show-item-9'
'.editor':
# Platform Bindings
'alt-left': 'editor:move-to-beginning-of-word'
'alt-right': 'editor:move-to-end-of-word'
'alt-shift-left': 'editor:select-to-beginning-of-word'
'alt-shift-right': 'editor:select-to-end-of-word'
# Apple Specific
'cmd-backspace': 'editor:delete-to-beginning-of-line'
'cmd-shift-backspace': 'editor:delete-to-beginning-of-line'
'cmd-delete': 'editor:delete-to-beginning-of-line'
'cmd-backspace': 'editor:backspace-to-beginning-of-line'
'cmd-shift-backspace': 'editor:backspace-to-beginning-of-line'
'cmd-delete': 'editor:backspace-to-beginning-of-line'
'ctrl-A': 'editor:select-to-first-character-of-line'
'ctrl-E': 'editor:select-to-end-of-line'
'cmd-left': 'editor:move-to-first-character-of-line'
'cmd-right': 'editor:move-to-end-of-screen-line'
'cmd-shift-left': 'editor:select-to-first-character-of-line'
'cmd-shift-right': 'editor:select-to-end-of-line'
'alt-backspace': 'editor:delete-to-beginning-of-word'
'alt-backspace': 'editor:backspace-to-beginning-of-word'
'alt-delete': 'editor:delete-to-end-of-word'
'ctrl-a': 'editor:move-to-beginning-of-line'
'ctrl-e': 'editor:move-to-end-of-line'
+1 -1
Ver Arquivo
@@ -3,5 +3,5 @@
'alt-F': 'editor:select-to-end-of-word'
'alt-b': 'editor:move-to-beginning-of-word'
'alt-B': 'editor:select-to-beginning-of-word'
'alt-h': 'editor:delete-to-beginning-of-word'
'alt-h': 'editor:backspace-to-beginning-of-word'
'alt-d': 'editor:delete-to-end-of-word'
+2 -11
Ver Arquivo
@@ -60,17 +60,8 @@
'ctrl-k ctrl-right': 'window:focus-pane-on-right'
'.workspace .editor':
# Platform Bindings
'ctrl-left': 'editor:move-to-beginning-of-word'
'ctrl-right': 'editor:move-to-end-of-word'
'ctrl-shift-left': 'editor:select-to-beginning-of-word'
'ctrl-shift-right': 'editor:select-to-end-of-word'
'ctrl-backspace': 'editor:delete-to-beginning-of-word'
'ctrl-delete': 'editor:delete-to-end-of-word'
'ctrl-home': 'core:move-to-top'
'ctrl-end': 'core:move-to-bottom'
'ctrl-shift-home': 'core:select-to-top'
'ctrl-shift-end': 'core:select-to-bottom'
# Windows specific
'ctrl-delete': 'editor:backspace-to-beginning-of-word'
# Sublime Parity
'ctrl-a': 'core:select-all'
+2 -15
Ver Arquivo
@@ -1,8 +1,4 @@
'body':
# Platform Bindings
'ctrl-pageup': 'pane:show-previous-item'
'ctrl-pagedown': 'pane:show-next-item'
# Atom Specific
'enter': 'core:confirm'
'escape': 'core:cancel'
@@ -14,7 +10,6 @@
'ctrl-alt-i': 'window:toggle-dev-tools'
'ctrl-alt-p': 'window:run-package-specs'
'ctrl-alt-s': 'application:run-all-specs'
'F11': 'window:toggle-full-screen'
# Sublime Parity
'ctrl-N': 'application:new-window'
@@ -38,7 +33,6 @@
'pageup': 'core:page-up'
'pagedown': 'core:page-down'
'backspace': 'core:backspace'
'shift-backspace': 'core:backspace'
'ctrl-tab': 'pane:show-next-item'
'ctrl-shift-tab': 'pane:show-previous-item'
'ctrl-shift-up': 'core:move-up'
@@ -63,15 +57,8 @@
'ctrl-k ctrl-right': 'window:focus-pane-on-right'
'.workspace .editor':
# Platform Bindings
'ctrl-left': 'editor:move-to-beginning-of-word'
'ctrl-right': 'editor:move-to-end-of-word'
'ctrl-shift-left': 'editor:select-to-beginning-of-word'
'ctrl-shift-right': 'editor:select-to-end-of-word'
'ctrl-backspace': 'editor:delete-to-beginning-of-word'
'ctrl-delete': 'editor:delete-to-end-of-word'
'ctrl-home': 'core:move-to-top'
'ctrl-end': 'core:move-to-bottom'
# Windows specific
'ctrl-delete': 'editor:backspace-to-beginning-of-word'
# Sublime Parity
'ctrl-a': 'core:select-all'
-1
Ver Arquivo
@@ -185,7 +185,6 @@
{
label: 'Help'
submenu: [
{ label: 'Terms of Use', command: 'application:open-terms-of-use' }
{ label: 'Documentation', command: 'application:open-documentation' }
{ type: 'separator' }
]
-1
Ver Arquivo
@@ -145,7 +145,6 @@
{
label: '&Help'
submenu: [
{ label: 'View &Terms of Use', command: 'application:open-terms-of-use' }
{ label: 'View &License', command: 'application:open-license' }
{ label: "VERSION", enabled: false }
{ type: 'separator' }
-1
Ver Arquivo
@@ -165,7 +165,6 @@
label: '&Help'
submenu: [
{ label: '&About Atom...', command: 'application:about' }
{ label: 'View &Terms of Use', command: 'application:open-terms-of-use' }
{ label: 'View &License', command: 'application:open-license' }
{ label: "VERSION", enabled: false }
{ label: "Install &update", command: 'application:install-update', visible: false }
+38 -38
Ver Arquivo
@@ -1,7 +1,7 @@
{
"name": "atom",
"productName": "Atom",
"version": "0.97.0",
"version": "0.93.0",
"description": "A hackable text editor for the 21st Century.",
"main": "./src/browser/main.js",
"repository": {
@@ -17,18 +17,18 @@
"url": "http://github.com/atom/atom/raw/master/LICENSE.md"
}
],
"atomShellVersion": "0.12.5",
"atomShellVersion": "0.12.0",
"dependencies": {
"async": "0.2.6",
"atom-keymap": "^0.22.0",
"bootstrap": "git+https://github.com/atom/bootstrap.git#6af81906189f1747fd6c93479e3d998ebe041372",
"atom-keymap": "^0.19.0",
"bootstrap": "git://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",
"first-mate": "^1.5.3",
"fs-plus": "^2.2.3",
"fs-plus": "^2.2.2",
"fstream": "0.1.24",
"fuzzaldrin": "^1.1",
"git-utils": "^1.3",
@@ -41,24 +41,24 @@
"nslog": "0.5.0",
"oniguruma": "^1.0.6",
"optimist": "0.4.0",
"pathwatcher": "^1.3.1",
"pathwatcher": "^1.2.1",
"property-accessors": "^1",
"q": "^1.0.1",
"random-words": "0.0.1",
"react-atom-fork": "^0.10.0",
"reactionary-atom-fork": "^0.9.0",
"react": "^0.10.0",
"reactionary": "^0.8.0",
"runas": "^0.5",
"scandal": "0.15.2",
"scoped-property-store": "^0.9.0",
"scrollbar-style": "^0.4.0",
"scrollbar-style": "^0.1.0",
"season": "^1.0.2",
"semver": "1.1.4",
"serializable": "^1",
"space-pen": "3.2.0",
"space-pen": "3.1.1",
"temp": "0.5.0",
"text-buffer": "^2.2.2",
"text-buffer": "^2.2.0",
"theorist": "^1",
"underscore-plus": "^1.3.0",
"underscore-plus": "^1.2.1",
"vm-compatibility-layer": "0.1.0"
},
"packageDependencies": {
@@ -69,72 +69,72 @@
"base16-tomorrow-dark-theme": "0.15.0",
"solarized-dark-syntax": "0.14.0",
"solarized-light-syntax": "0.7.0",
"archive-view": "0.31.0",
"autocomplete": "0.28.0",
"autoflow": "0.17.0",
"archive-view": "0.30.0",
"autocomplete": "0.27.0",
"autoflow": "0.16.0",
"autosave": "0.13.0",
"background-tips": "0.13.0",
"bookmarks": "0.22.0",
"bracket-matcher": "0.38.0",
"bracket-matcher": "0.33.0",
"command-palette": "0.21.0",
"deprecation-cop": "0.5.0",
"dev-live-reload": "0.30.0",
"exception-reporting": "0.17.0",
"feedback": "0.33.0",
"find-and-replace": "0.106.0",
"fuzzy-finder": "0.51.0",
"feedback": "0.30.0",
"find-and-replace": "0.100.0",
"fuzzy-finder": "0.50.0",
"git-diff": "0.28.0",
"go-to-line": "0.21.0",
"go-to-line": "0.19.0",
"grammar-selector": "0.26.0",
"image-view": "0.33.0",
"keybinding-resolver": "0.17.0",
"link": "0.22.0",
"markdown-preview": "0.72.0",
"markdown-preview": "0.69.0",
"metrics": "0.32.0",
"open-on-github": "0.28.0",
"package-generator": "0.30.0",
"release-notes": "0.31.0",
"settings-view": "0.116.0",
"release-notes": "0.28.0",
"settings-view": "0.114.0",
"snippets": "0.43.0",
"spell-check": "0.35.0",
"spell-check": "0.34.0",
"status-bar": "0.40.0",
"styleguide": "0.29.0",
"symbols-view": "0.53.0",
"tabs": "0.40.0",
"symbols-view": "0.50.0",
"tabs": "0.39.0",
"timecop": "0.18.0",
"tree-view": "0.93.0",
"tree-view": "0.92.0",
"update-package-dependencies": "0.6.0",
"welcome": "0.14.0",
"welcome": "0.12.0",
"whitespace": "0.22.0",
"wrap-guide": "0.18.0",
"language-c": "0.15.0",
"language-coffee-script": "0.22.0",
"language-css": "0.16.0",
"language-gfm": "0.38.0",
"language-gfm": "0.33.0",
"language-git": "0.9.0",
"language-go": "0.12.0",
"language-html": "0.22.0",
"language-go": "0.10.0",
"language-html": "0.19.0",
"language-hyperlink": "0.9.0",
"language-java": "0.10.0",
"language-javascript": "0.26.0",
"language-javascript": "0.24.0",
"language-json": "0.8.0",
"language-less": "0.9.0",
"language-less": "0.8.0",
"language-make": "0.10.0",
"language-objective-c": "0.11.0",
"language-perl": "0.8.0",
"language-php": "0.14.0",
"language-property-list": "0.7.0",
"language-python": "0.17.0",
"language-ruby": "0.25.0",
"language-ruby-on-rails": "0.14.0",
"language-sass": "0.11.0",
"language-python": "0.15.0",
"language-ruby": "0.23.0",
"language-ruby-on-rails": "0.12.0",
"language-sass": "0.10.0",
"language-shellscript": "0.8.0",
"language-source": "0.7.0",
"language-sql": "0.8.0",
"language-text": "0.6.0",
"language-todo": "0.10.0",
"language-toml": "0.12.0",
"language-xml": "0.13.0",
"language-xml": "0.11.0",
"language-yaml": "0.6.0"
},
"private": true,
Arquivo binário não exibido.

Antes

Largura:  |  Altura:  |  Tamanho: 141 KiB

Depois

Largura:  |  Altura:  |  Tamanho: 361 KiB

+4 -14
Ver Arquivo
@@ -1,18 +1,8 @@
#!/usr/bin/env node
var fs = require('fs');
var nodeVersion = process.versions.node.split('.')
var nodeMajorVersion = +nodeVersion[0]
var nodeMinorVersion = +nodeVersion[1]
if (nodeMajorVersion === 0 && nodeMinorVersion < 10) {
console.warn("You must run script/bootstrap and script/build with node v0.10 or above");
process.exit(1);
}
// Make sure python2.7 is installed
if (process.platform == 'win32' && !fs.existsSync('C:\\Python27\\')) {
console.warn("You must have Python 2.7 installed at 'C:\\Python27\\'");
var nodeMinorVersion = process.versions.node.split('.')[1]
if (nodeMinorVersion !== '10') {
console.warn("You must run script/bootstrap and script/build with node v0.10.x");
process.exit(1);
}
@@ -41,7 +31,7 @@ if (!fs.existsSync(apmInstallPath))
if (!fs.existsSync(path.join(apmInstallPath, 'node_modules')))
fs.mkdirSync(path.join(apmInstallPath, 'node_modules'));
var apmPath = path.resolve(__dirname, '..', 'apm', 'node_modules', 'atom-package-manager', 'bin', 'apm')
var apmPath = 'apm/node_modules/atom-package-manager/bin/apm'
var apmFlags = process.env.JANKY_SHA1 || process.argv.indexOf('--no-color') !== -1 ? '--no-color' : '';
var npmPath = path.resolve(__dirname, '..', 'build', 'node_modules', '.bin', 'npm');
+1 -1
Ver Arquivo
@@ -8,7 +8,7 @@ var productName = require('../package.json').productName;
process.chdir(path.dirname(__dirname));
var home = process.env[(process.platform === 'win32') ? 'USERPROFILE' : 'HOME'];
var tmpdir = os.tmpdir();
var tmpdir = process.platform === 'win32' ? os.tmpdir() : '/tmp';
// Windows: Use START as a way to ignore error if Atom.exe isnt running
var killatom = process.platform === 'win32' ? 'START taskkill /F /IM ' + productName + '.exe' : 'pkill -9 ' + productName + ' || true';
-5
Ver Arquivo
@@ -1,5 +0,0 @@
@IF EXIST "%~dp0\node.exe" (
"%~dp0\node.exe" "%~dp0\grunt" %*
) ELSE (
node "%~dp0\grunt" %*
)
-3
Ver Arquivo
@@ -1,8 +1,6 @@
#!/bin/bash
# mkdeb version control-file-path deb-file-path
set -e
SCRIPT=`readlink -f "$0"`
ROOT=`readlink -f $(dirname $SCRIPT)/..`
cd $ROOT
@@ -14,7 +12,6 @@ ICON_FILE="$4"
DEB_PATH="$5"
TARGET_ROOT="`mktemp -d`"
chmod 755 "$TARGET_ROOT"
TARGET="$TARGET_ROOT/atom-$VERSION-amd64"
mkdir -p "$TARGET/usr"
+6 -6
Ver Arquivo
@@ -510,20 +510,20 @@ describe "the `atom` global", ->
# enabling of theme
pack = atom.packages.enablePackage(packageName)
activatedPackages = null
waitsFor ->
pack in atom.packages.getActivePackages()
activatedPackages = atom.packages.getActivePackages()
activatedPackages.length > 0
runs ->
expect(activatedPackages).toContain(pack)
expect(atom.config.get('core.themes')).toContain packageName
expect(atom.config.get('core.disabledPackages')).not.toContain packageName
# disabling of theme
pack = atom.packages.disablePackage(packageName)
waitsFor ->
not (pack in atom.packages.getActivePackages())
runs ->
activatedPackages = atom.packages.getActivePackages()
expect(activatedPackages).not.toContain(pack)
expect(atom.config.get('core.themes')).not.toContain packageName
expect(atom.config.get('core.themes')).not.toContain packageName
expect(atom.config.get('core.disabledPackages')).not.toContain packageName
+1 -7
Ver Arquivo
@@ -5,10 +5,6 @@ fs = require 'fs-plus'
describe "Config", ->
dotAtomPath = path.join(temp.dir, 'dot-atom-dir')
dotAtomPath = null
beforeEach ->
dotAtomPath = temp.path('dot-atom-dir')
describe ".get(keyPath)", ->
it "allows a key path's value to be read", ->
@@ -262,10 +258,8 @@ describe "Config", ->
describe ".initializeConfigDirectory()", ->
beforeEach ->
if fs.existsSync(dotAtomPath)
fs.removeSync(dotAtomPath)
atom.config.configDirPath = dotAtomPath
expect(fs.existsSync(atom.config.configDirPath)).toBeFalsy()
afterEach ->
fs.removeSync(dotAtomPath)
+4 -4
Ver Arquivo
@@ -948,7 +948,7 @@ describe "DisplayBuffer", ->
it "returns the start and end positions of the marker based on the line height and character widths assigned to the DisplayBuffer", ->
marker = displayBuffer.markScreenRange([[5, 10], [6, 4]])
displayBuffer.setLineHeightInPixels(20)
displayBuffer.setLineHeight(20)
displayBuffer.setDefaultCharWidth(10)
displayBuffer.setScopedCharWidths(["source.js", "keyword.control.js"], r: 11, e: 11, t: 11, u: 11, n: 11)
@@ -959,7 +959,7 @@ describe "DisplayBuffer", ->
describe "::setScrollTop", ->
beforeEach ->
displayBuffer.manageScrollPosition = true
displayBuffer.setLineHeightInPixels(10)
displayBuffer.setLineHeight(10)
it "disallows negative values", ->
displayBuffer.setHeight(displayBuffer.getScrollHeight() + 100)
@@ -979,7 +979,7 @@ describe "DisplayBuffer", ->
describe "::setScrollLeft", ->
beforeEach ->
displayBuffer.manageScrollPosition = true
displayBuffer.setLineHeightInPixels(10)
displayBuffer.setLineHeight(10)
displayBuffer.setDefaultCharWidth(10)
it "disallows negative values", ->
@@ -1000,7 +1000,7 @@ describe "DisplayBuffer", ->
describe "::scrollToScreenPosition(position)", ->
it "sets the scroll top and scroll left so the given screen position is in view", ->
displayBuffer.manageScrollPosition = true
displayBuffer.setLineHeightInPixels(10)
displayBuffer.setLineHeight(10)
displayBuffer.setDefaultCharWidth(10)
displayBuffer.setHorizontalScrollbarHeight(0)
+139 -256
Ver Arquivo
@@ -1,16 +1,12 @@
_ = require 'underscore-plus'
{extend, flatten, toArray, last} = _
{extend, flatten, toArray, last} = require 'underscore-plus'
ReactEditorView = require '../src/react-editor-view'
nbsp = String.fromCharCode(160)
describe "EditorComponent", ->
[contentNode, editor, wrapperView, component, node, verticalScrollbarNode, horizontalScrollbarNode] = []
[lineHeightInPixels, charWidth, delayAnimationFrames, nextAnimationFrame, lineOverdrawMargin] = []
[lineHeightInPixels, charWidth, delayAnimationFrames, nextAnimationFrame] = []
beforeEach ->
lineOverdrawMargin = 2
waitsForPromise ->
atom.packages.activatePackage('language-javascript')
@@ -33,156 +29,69 @@ describe "EditorComponent", ->
contentNode = document.querySelector('#jasmine-content')
contentNode.style.width = '1000px'
wrapperView = new ReactEditorView(editor, {lineOverdrawMargin})
wrapperView = new ReactEditorView(editor)
wrapperView.attachToDom()
{component} = wrapperView
component.setLineHeight(1.3)
component.setFontSize(20)
lineHeightInPixels = editor.getLineHeightInPixels()
lineHeightInPixels = editor.getLineHeight()
charWidth = editor.getDefaultCharWidth()
node = component.getDOMNode()
verticalScrollbarNode = node.querySelector('.vertical-scrollbar')
horizontalScrollbarNode = node.querySelector('.horizontal-scrollbar')
node.style.height = editor.getLineCount() * lineHeightInPixels + 'px'
node.style.width = '1000px'
component.measureHeightAndWidth()
afterEach ->
contentNode.style.width = ''
describe "line rendering", ->
it "renders the currently-visible lines plus the overdraw margin", ->
it "renders only the currently-visible lines", ->
node.style.height = 4.5 * lineHeightInPixels + 'px'
component.measureHeightAndWidth()
linesNode = node.querySelector('.lines')
expect(linesNode.style['-webkit-transform']).toBe "translate3d(0px, 0px, 0px)"
expect(node.querySelectorAll('.line').length).toBe 6 + 2 # no margin above
expect(component.lineNodeForScreenRow(0).textContent).toBe editor.lineForScreenRow(0).text
expect(component.lineNodeForScreenRow(0).offsetTop).toBe 0
expect(component.lineNodeForScreenRow(5).textContent).toBe editor.lineForScreenRow(5).text
expect(component.lineNodeForScreenRow(5).offsetTop).toBe 5 * lineHeightInPixels
lines = node.querySelectorAll('.line')
expect(lines.length).toBe 6
expect(lines[0].textContent).toBe editor.lineForScreenRow(0).text
expect(lines[5].textContent).toBe editor.lineForScreenRow(5).text
verticalScrollbarNode.scrollTop = 4.5 * lineHeightInPixels
verticalScrollbarNode.scrollTop = 2.5 * lineHeightInPixels
verticalScrollbarNode.dispatchEvent(new UIEvent('scroll'))
expect(linesNode.style['-webkit-transform']).toBe "translate3d(0px, #{-4.5 * lineHeightInPixels}px, 0px)"
expect(node.querySelectorAll('.line').length).toBe 6 + 4 # margin above and below
expect(component.lineNodeForScreenRow(2).offsetTop).toBe 2 * lineHeightInPixels
expect(component.lineNodeForScreenRow(2).textContent).toBe editor.lineForScreenRow(2).text
expect(component.lineNodeForScreenRow(9).offsetTop).toBe 9 * lineHeightInPixels
expect(component.lineNodeForScreenRow(9).textContent).toBe editor.lineForScreenRow(9).text
expect(node.querySelector('.scroll-view-content').style['-webkit-transform']).toBe "translate3d(0px, #{-2.5 * lineHeightInPixels}px, 0)"
it "updates the top position of subsequent lines when lines are inserted or removed", ->
lineNodes = node.querySelectorAll('.line')
expect(lineNodes.length).toBe 6
expect(lineNodes[0].offsetTop).toBe 2 * lineHeightInPixels
expect(lineNodes[0].textContent).toBe editor.lineForScreenRow(2).text
expect(lineNodes[5].textContent).toBe editor.lineForScreenRow(7).text
it "updates absolute positions of subsequent lines when lines are inserted or removed", ->
editor.getBuffer().deleteRows(0, 1)
lineNodes = node.querySelectorAll('.line')
expect(component.lineNodeForScreenRow(0).offsetTop).toBe 0
expect(component.lineNodeForScreenRow(1).offsetTop).toBe 1 * lineHeightInPixels
expect(component.lineNodeForScreenRow(2).offsetTop).toBe 2 * lineHeightInPixels
expect(lineNodes[0].offsetTop).toBe 0
expect(lineNodes[1].offsetTop).toBe 1 * lineHeightInPixels
expect(lineNodes[2].offsetTop).toBe 2 * lineHeightInPixels
editor.getBuffer().insert([0, 0], '\n\n')
lineNodes = node.querySelectorAll('.line')
expect(component.lineNodeForScreenRow(0).offsetTop).toBe 0 * lineHeightInPixels
expect(component.lineNodeForScreenRow(1).offsetTop).toBe 1 * lineHeightInPixels
expect(component.lineNodeForScreenRow(2).offsetTop).toBe 2 * lineHeightInPixels
expect(component.lineNodeForScreenRow(3).offsetTop).toBe 3 * lineHeightInPixels
expect(component.lineNodeForScreenRow(4).offsetTop).toBe 4 * lineHeightInPixels
it "updates the top position of lines when the line height changes", ->
initialLineHeightInPixels = editor.getLineHeightInPixels()
component.setLineHeight(2)
newLineHeightInPixels = editor.getLineHeightInPixels()
expect(newLineHeightInPixels).not.toBe initialLineHeightInPixels
expect(component.lineNodeForScreenRow(1).offsetTop).toBe 1 * newLineHeightInPixels
it "updates the top position of lines when the font size changes", ->
initialLineHeightInPixels = editor.getLineHeightInPixels()
component.setFontSize(10)
newLineHeightInPixels = editor.getLineHeightInPixels()
expect(newLineHeightInPixels).not.toBe initialLineHeightInPixels
expect(component.lineNodeForScreenRow(1).offsetTop).toBe 1 * newLineHeightInPixels
it "updates the top position of lines when the font family changes", ->
# Can't find a font that changes the line height, but we think one might exist
linesComponent = component.refs.scrollView.refs.lines
spyOn(linesComponent, 'measureLineHeightInPixelsAndCharWidth').andCallFake -> editor.setLineHeightInPixels(10)
initialLineHeightInPixels = editor.getLineHeightInPixels()
component.setFontFamily('sans-serif')
expect(linesComponent.measureLineHeightInPixelsAndCharWidth).toHaveBeenCalled()
newLineHeightInPixels = editor.getLineHeightInPixels()
expect(newLineHeightInPixels).not.toBe initialLineHeightInPixels
expect(component.lineNodeForScreenRow(1).offsetTop).toBe 1 * newLineHeightInPixels
it "renders the .lines div at the full height of the editor if there aren't enough lines to scroll vertically", ->
editor.setText('')
node.style.height = '300px'
component.measureHeightAndWidth()
linesNode = node.querySelector('.lines')
expect(linesNode.offsetHeight).toBe 300
describe "when showInvisibles is enabled", ->
invisibles = null
beforeEach ->
invisibles =
eol: 'E'
space: 'S'
tab: 'T'
cr: 'C'
atom.config.set("editor.showInvisibles", true)
atom.config.set("editor.invisibles", invisibles)
it "re-renders the lines when the showInvisibles config option changes", ->
editor.setText " a line with tabs\tand spaces "
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)
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 "
expect(component.lineNodeForScreenRow(0).textContent).toBe "#{invisibles.space}a line with tabs#{invisibles.tab} and spaces#{invisibles.space}#{invisibles.eol}"
it "displays newlines as their own token outside of the other tokens' scopes", ->
editor.setText "var"
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>"
it "displays trailing carriage returns using a visible, non-empty value", ->
editor.setText "a line that ends with a carriage return\r\n"
expect(component.lineNodeForScreenRow(0).textContent).toBe "a line that ends with a carriage return#{invisibles.cr}#{invisibles.eol}"
describe "when soft wrapping is enabled", ->
beforeEach ->
editor.setText "a line that wraps "
editor.setSoftWrap(true)
node.style.width = 15 * charWidth + 'px'
component.measureHeightAndWidth()
it "doesn't show end of line invisibles at the end of wrapped lines", ->
expect(component.lineNodeForScreenRow(0).textContent).toBe "a line that "
expect(component.lineNodeForScreenRow(1).textContent).toBe "wraps#{invisibles.space}#{invisibles.eol}"
expect(lineNodes[0].offsetTop).toBe 0
expect(lineNodes[1].offsetTop).toBe 1 * lineHeightInPixels
expect(lineNodes[2].offsetTop).toBe 2 * lineHeightInPixels
expect(lineNodes[3].offsetTop).toBe 3 * lineHeightInPixels
expect(lineNodes[4].offsetTop).toBe 4 * lineHeightInPixels
describe "when indent guides are enabled", ->
beforeEach ->
component.setShowIndentGuide(true)
it "adds an 'indent-guide' class to spans comprising the leading whitespace", ->
line1LeafNodes = getLeafNodes(component.lineNodeForScreenRow(1))
lines = node.querySelectorAll('.line')
line1LeafNodes = getLeafNodes(lines[1])
expect(line1LeafNodes[0].textContent).toBe ' '
expect(line1LeafNodes[0].classList.contains('indent-guide')).toBe true
expect(line1LeafNodes[1].classList.contains('indent-guide')).toBe false
line2LeafNodes = getLeafNodes(component.lineNodeForScreenRow(2))
line2LeafNodes = getLeafNodes(lines[2])
expect(line2LeafNodes[0].textContent).toBe ' '
expect(line2LeafNodes[0].classList.contains('indent-guide')).toBe true
expect(line2LeafNodes[1].textContent).toBe ' '
@@ -192,7 +101,8 @@ describe "EditorComponent", ->
it "renders leading whitespace spans with the 'indent-guide' class for empty lines", ->
editor.getBuffer().insert([1, Infinity], '\n')
line2LeafNodes = getLeafNodes(component.lineNodeForScreenRow(2))
lines = node.querySelectorAll('.line')
line2LeafNodes = getLeafNodes(lines[2])
expect(line2LeafNodes.length).toBe 3
expect(line2LeafNodes[0].textContent).toBe ' '
@@ -204,7 +114,8 @@ describe "EditorComponent", ->
it "renders indent guides correctly on lines containing only whitespace", ->
editor.getBuffer().insert([1, Infinity], '\n ')
line2LeafNodes = getLeafNodes(component.lineNodeForScreenRow(2))
lines = node.querySelectorAll('.line')
line2LeafNodes = getLeafNodes(lines[2])
expect(line2LeafNodes.length).toBe 3
expect(line2LeafNodes[0].textContent).toBe ' '
expect(line2LeafNodes[0].classList.contains('indent-guide')).toBe true
@@ -214,8 +125,9 @@ describe "EditorComponent", ->
expect(line2LeafNodes[2].classList.contains('indent-guide')).toBe true
it "does not render indent guides in trailing whitespace for lines containing non whitespace characters", ->
editor.getBuffer().setText " hi "
line0LeafNodes = getLeafNodes(component.lineNodeForScreenRow(0))
editor.getBuffer().setText (" hi ")
lines = node.querySelectorAll('.line')
line0LeafNodes = getLeafNodes(lines[0])
expect(line0LeafNodes[0].textContent).toBe ' '
expect(line0LeafNodes[0].classList.contains('indent-guide')).toBe true
expect(line0LeafNodes[1].textContent).toBe ' '
@@ -232,39 +144,40 @@ describe "EditorComponent", ->
node.style.height = 4.5 * lineHeightInPixels + 'px'
component.measureHeightAndWidth()
expect(node.querySelectorAll('.line-number').length).toBe 6 + 2 + 1 # line overdraw margin below + dummy line number
expect(component.lineNumberNodeForScreenRow(0).textContent).toBe "#{nbsp}1"
expect(component.lineNumberNodeForScreenRow(5).textContent).toBe "#{nbsp}6"
lines = node.querySelectorAll('.line-number')
expect(lines.length).toBe 6
expect(lines[0].textContent).toBe "#{nbsp}1"
expect(lines[5].textContent).toBe "#{nbsp}6"
verticalScrollbarNode.scrollTop = 2.5 * lineHeightInPixels
verticalScrollbarNode.dispatchEvent(new UIEvent('scroll'))
expect(node.querySelectorAll('.line-number').length).toBe 6 + 4 + 1 # line overdraw margin above/below + dummy line number
expect(node.querySelector('.line-numbers').style['-webkit-transform']).toBe "translate3d(0, #{-2.5 * lineHeightInPixels}px, 0)"
expect(component.lineNumberNodeForScreenRow(2).textContent).toBe "#{nbsp}3"
expect(component.lineNumberNodeForScreenRow(2).offsetTop).toBe 2 * lineHeightInPixels
return
expect(component.lineNumberNodeForScreenRow(7).textContent).toBe "#{nbsp}8"
expect(component.lineNumberNodeForScreenRow(7).offsetTop).toBe 7 * lineHeightInPixels
lineNumberNodes = node.querySelectorAll('.line-number')
expect(lineNumberNodes.length).toBe 6
expect(lineNumberNodes[0].offsetTop).toBe 2 * lineHeightInPixels
expect(lineNumberNodes[5].offsetTop).toBe 7 * lineHeightInPixels
expect(lineNumberNodes[0].textContent).toBe "#{nbsp}3"
expect(lineNumberNodes[5].textContent).toBe "#{nbsp}8"
it "updates the translation of subsequent line numbers when lines are inserted or removed", ->
it "updates absolute positions of subsequent line numbers when lines are inserted or removed", ->
editor.getBuffer().insert([0, 0], '\n\n')
lineNumberNodes = node.querySelectorAll('.line-number')
expect(component.lineNumberNodeForScreenRow(0).offsetTop).toBe 0
expect(component.lineNumberNodeForScreenRow(1).offsetTop).toBe 1 * lineHeightInPixels
expect(component.lineNumberNodeForScreenRow(2).offsetTop).toBe 2 * lineHeightInPixels
expect(component.lineNumberNodeForScreenRow(3).offsetTop).toBe 3 * lineHeightInPixels
expect(component.lineNumberNodeForScreenRow(4).offsetTop).toBe 4 * lineHeightInPixels
expect(lineNumberNodes[0].offsetTop).toBe 0
expect(lineNumberNodes[1].offsetTop).toBe 1 * lineHeightInPixels
expect(lineNumberNodes[2].offsetTop).toBe 2 * lineHeightInPixels
expect(lineNumberNodes[3].offsetTop).toBe 3 * lineHeightInPixels
expect(lineNumberNodes[4].offsetTop).toBe 4 * lineHeightInPixels
editor.getBuffer().insert([0, 0], '\n\n')
expect(component.lineNumberNodeForScreenRow(0).offsetTop).toBe 0
expect(component.lineNumberNodeForScreenRow(1).offsetTop).toBe 1 * lineHeightInPixels
expect(component.lineNumberNodeForScreenRow(2).offsetTop).toBe 2 * lineHeightInPixels
expect(component.lineNumberNodeForScreenRow(3).offsetTop).toBe 3 * lineHeightInPixels
expect(component.lineNumberNodeForScreenRow(4).offsetTop).toBe 4 * lineHeightInPixels
expect(component.lineNumberNodeForScreenRow(5).offsetTop).toBe 5 * lineHeightInPixels
expect(component.lineNumberNodeForScreenRow(6).offsetTop).toBe 6 * lineHeightInPixels
lineNumberNodes = node.querySelectorAll('.line-number')
expect(lineNumberNodes[0].offsetTop).toBe 0
expect(lineNumberNodes[1].offsetTop).toBe 1 * lineHeightInPixels
expect(lineNumberNodes[2].offsetTop).toBe 2 * lineHeightInPixels
expect(lineNumberNodes[3].offsetTop).toBe 3 * lineHeightInPixels
expect(lineNumberNodes[4].offsetTop).toBe 4 * lineHeightInPixels
it "renders • characters for soft-wrapped lines", ->
editor.setSoftWrap(true)
@@ -272,50 +185,43 @@ describe "EditorComponent", ->
node.style.width = 30 * charWidth + 'px'
component.measureHeightAndWidth()
expect(node.querySelectorAll('.line-number').length).toBe 6 + lineOverdrawMargin + 1 # 1 dummy line node
expect(component.lineNumberNodeForScreenRow(0).textContent).toBe "#{nbsp}1"
expect(component.lineNumberNodeForScreenRow(1).textContent).toBe "#{nbsp}"
expect(component.lineNumberNodeForScreenRow(2).textContent).toBe "#{nbsp}2"
expect(component.lineNumberNodeForScreenRow(3).textContent).toBe "#{nbsp}"
expect(component.lineNumberNodeForScreenRow(4).textContent).toBe "#{nbsp}3"
expect(component.lineNumberNodeForScreenRow(5).textContent).toBe "#{nbsp}"
lines = node.querySelectorAll('.line-number')
expect(lines.length).toBe 6
expect(lines[0].textContent).toBe "#{nbsp}1"
expect(lines[1].textContent).toBe "#{nbsp}"
expect(lines[2].textContent).toBe "#{nbsp}2"
expect(lines[3].textContent).toBe "#{nbsp}"
expect(lines[4].textContent).toBe "#{nbsp}3"
expect(lines[5].textContent).toBe "#{nbsp}"
it "pads line numbers to be right-justified based on the maximum number of line number digits", ->
it "pads line numbers to be right justified based on the maximum number of line number digits", ->
editor.getBuffer().setText([1..10].join('\n'))
for screenRow in [0..8]
expect(component.lineNumberNodeForScreenRow(screenRow).textContent).toBe "#{nbsp}#{screenRow + 1}"
expect(component.lineNumberNodeForScreenRow(9).textContent).toBe "10"
lineNumberNodes = toArray(node.querySelectorAll('.line-number'))
gutterNode = node.querySelector('.gutter')
initialGutterWidth = gutterNode.offsetWidth
for node, i in lineNumberNodes[0..8]
expect(node.textContent).toBe "#{nbsp}#{i + 1}"
expect(lineNumberNodes[9].textContent).toBe '10'
# Removes padding when the max number of digits goes down
editor.getBuffer().delete([[1, 0], [2, 0]])
for screenRow in [0..8]
expect(component.lineNumberNodeForScreenRow(screenRow).textContent).toBe "#{screenRow + 1}"
expect(gutterNode.offsetWidth).toBeLessThan initialGutterWidth
# Increases padding when the max number of digits goes up
editor.getBuffer().insert([0, 0], '\n\n')
for screenRow in [0..8]
expect(component.lineNumberNodeForScreenRow(screenRow).textContent).toBe "#{nbsp}#{screenRow + 1}"
expect(component.lineNumberNodeForScreenRow(9).textContent).toBe "10"
expect(gutterNode.offsetWidth).toBe initialGutterWidth
lineNumberNodes = toArray(node.querySelectorAll('.line-number'))
for node, i in lineNumberNodes
expect(node.textContent).toBe "#{i + 1}"
describe "cursor rendering", ->
it "renders the currently visible cursors, translated relative to the scroll position", ->
it "renders the currently visible cursors", ->
cursor1 = editor.getCursor()
cursor1.setScreenPosition([0, 5])
node.style.height = 4.5 * lineHeightInPixels + 'px'
node.style.width = 20 * lineHeightInPixels + 'px'
component.measureHeightAndWidth()
cursorNodes = node.querySelectorAll('.cursor')
expect(cursorNodes.length).toBe 1
expect(cursorNodes[0].offsetHeight).toBe lineHeightInPixels
expect(cursorNodes[0].offsetWidth).toBe charWidth
expect(cursorNodes[0].style['-webkit-transform']).toBe "translate3d(#{5 * charWidth}px, #{0 * lineHeightInPixels}px, 0px)"
expect(cursorNodes[0].offsetTop).toBe 0
expect(cursorNodes[0].offsetLeft).toBe 5 * charWidth
cursor2 = editor.addCursorAtScreenPosition([6, 11])
cursor3 = editor.addCursorAtScreenPosition([4, 10])
@@ -323,23 +229,25 @@ describe "EditorComponent", ->
cursorNodes = node.querySelectorAll('.cursor')
expect(cursorNodes.length).toBe 2
expect(cursorNodes[0].offsetTop).toBe 0
expect(cursorNodes[0].style['-webkit-transform']).toBe "translate3d(#{5 * charWidth}px, #{0 * lineHeightInPixels}px, 0px)"
expect(cursorNodes[1].style['-webkit-transform']).toBe "translate3d(#{10 * charWidth}px, #{4 * lineHeightInPixels}px, 0px)"
expect(cursorNodes[0].offsetLeft).toBe 5 * charWidth
expect(cursorNodes[1].offsetTop).toBe 4 * lineHeightInPixels
expect(cursorNodes[1].offsetLeft).toBe 10 * charWidth
verticalScrollbarNode.scrollTop = 2.5 * lineHeightInPixels
verticalScrollbarNode.dispatchEvent(new UIEvent('scroll'))
horizontalScrollbarNode.scrollLeft = 3.5 * charWidth
horizontalScrollbarNode.dispatchEvent(new UIEvent('scroll'))
cursorNodes = node.querySelectorAll('.cursor')
expect(cursorNodes.length).toBe 2
expect(cursorNodes[0].style['-webkit-transform']).toBe "translate3d(#{(11 - 3.5) * charWidth}px, #{(6 - 2.5) * lineHeightInPixels}px, 0px)"
expect(cursorNodes[1].style['-webkit-transform']).toBe "translate3d(#{(10 - 3.5) * charWidth}px, #{(4 - 2.5) * lineHeightInPixels}px, 0px)"
expect(cursorNodes[0].offsetTop).toBe 6 * lineHeightInPixels
expect(cursorNodes[0].offsetLeft).toBe 11 * charWidth
expect(cursorNodes[1].offsetTop).toBe 4 * lineHeightInPixels
expect(cursorNodes[1].offsetLeft).toBe 10 * charWidth
cursor3.destroy()
cursorNodes = node.querySelectorAll('.cursor')
expect(cursorNodes.length).toBe 1
expect(cursorNodes[0].style['-webkit-transform']).toBe "translate3d(#{(11 - 3.5) * charWidth}px, #{(6 - 2.5) * lineHeightInPixels}px, 0px)"
expect(cursorNodes[0].offsetTop).toBe 6 * lineHeightInPixels
expect(cursorNodes[0].offsetLeft).toBe 11 * charWidth
it "accounts for character widths when positioning cursors", ->
atom.config.set('editor.fontFamily', 'sans-serif')
@@ -348,7 +256,7 @@ describe "EditorComponent", ->
cursor = node.querySelector('.cursor')
cursorRect = cursor.getBoundingClientRect()
cursorLocationTextNode = component.lineNodeForScreenRow(0).querySelector('.storage.type.function.js').firstChild
cursorLocationTextNode = node.querySelector('.storage.type.function.js').firstChild.firstChild
range = document.createRange()
range.setStart(cursorLocationTextNode, 0)
range.setEnd(cursorLocationTextNode, 1)
@@ -358,22 +266,44 @@ describe "EditorComponent", ->
expect(cursorRect.width).toBe rangeRect.width
it "blinks cursors when they aren't moving", ->
spyOn(_._, 'now').andCallFake -> window.now # Ensure _.debounce is based on our fake spec timeline
cursorsNode = node.querySelector('.cursors')
editor.addCursorAtScreenPosition([1, 0])
[cursorNode1, cursorNode2] = node.querySelectorAll('.cursor')
expect(cursorNode1.classList.contains('blink-off')).toBe false
expect(cursorNode2.classList.contains('blink-off')).toBe false
expect(cursorsNode.classList.contains('blink-off')).toBe false
advanceClock(component.props.cursorBlinkPeriod / 2)
expect(cursorsNode.classList.contains('blink-off')).toBe true
advanceClock(component.props.cursorBlinkPeriod / 2)
expect(cursorsNode.classList.contains('blink-off')).toBe false
expect(cursorNode1.classList.contains('blink-off')).toBe true
expect(cursorNode2.classList.contains('blink-off')).toBe true
# Stop blinking after moving the cursor
advanceClock(component.props.cursorBlinkPeriod / 2)
expect(cursorNode1.classList.contains('blink-off')).toBe false
expect(cursorNode2.classList.contains('blink-off')).toBe false
advanceClock(component.props.cursorBlinkPeriod / 2)
expect(cursorNode1.classList.contains('blink-off')).toBe true
expect(cursorNode2.classList.contains('blink-off')).toBe true
# Stop blinking immediately when cursors move
advanceClock(component.props.cursorBlinkPeriod / 4)
expect(cursorNode1.classList.contains('blink-off')).toBe true
expect(cursorNode2.classList.contains('blink-off')).toBe true
# Stop blinking for one full period after moving the cursor
editor.moveCursorRight()
expect(cursorsNode.classList.contains('blink-off')).toBe false
expect(cursorNode1.classList.contains('blink-off')).toBe false
expect(cursorNode2.classList.contains('blink-off')).toBe false
advanceClock(component.props.cursorBlinkResumeDelay / 2)
expect(cursorNode1.classList.contains('blink-off')).toBe false
expect(cursorNode2.classList.contains('blink-off')).toBe false
advanceClock(component.props.cursorBlinkResumeDelay / 2)
expect(cursorNode1.classList.contains('blink-off')).toBe true
expect(cursorNode2.classList.contains('blink-off')).toBe true
advanceClock(component.props.cursorBlinkResumeDelay)
advanceClock(component.props.cursorBlinkPeriod / 2)
expect(cursorsNode.classList.contains('blink-off')).toBe true
expect(cursorNode1.classList.contains('blink-off')).toBe false
expect(cursorNode2.classList.contains('blink-off')).toBe false
it "renders the hidden input field at the position of the last cursor if it is on screen", ->
inputNode = node.querySelector('.hidden-input')
@@ -400,13 +330,13 @@ describe "EditorComponent", ->
cursorNodes = node.querySelectorAll('.cursor')
expect(cursorNodes.length).toBe 1
expect(cursorNodes[0].style['-webkit-transform']).toBe "translate3d(#{8 * charWidth}px, #{6 * lineHeightInPixels}px, 0px)"
expect(cursorNodes[0].offsetTop).toBe 6 * lineHeightInPixels
expect(cursorNodes[0].offsetLeft).toBe 8 * charWidth
describe "selection rendering", ->
[scrollViewNode, scrollViewClientLeft] = []
scrollViewClientLeft = null
beforeEach ->
scrollViewNode = node.querySelector('.scroll-view')
scrollViewClientLeft = node.querySelector('.scroll-view').getBoundingClientRect().left
it "renders 1 region for 1-line selections", ->
@@ -430,7 +360,7 @@ describe "EditorComponent", ->
expect(region1Rect.top).toBe 1 * lineHeightInPixels
expect(region1Rect.height).toBe 1 * lineHeightInPixels
expect(region1Rect.left).toBe scrollViewClientLeft + 6 * charWidth
expect(region1Rect.right).toBe scrollViewNode.getBoundingClientRect().right
expect(Math.ceil(region1Rect.right)).toBe node.clientWidth # TODO: Remove ceiling when react-wrapper is removed
region2Rect = regions[1].getBoundingClientRect()
expect(region2Rect.top).toBe 2 * lineHeightInPixels
@@ -447,13 +377,13 @@ describe "EditorComponent", ->
expect(region1Rect.top).toBe 1 * lineHeightInPixels
expect(region1Rect.height).toBe 1 * lineHeightInPixels
expect(region1Rect.left).toBe scrollViewClientLeft + 6 * charWidth
expect(region1Rect.right).toBe scrollViewNode.getBoundingClientRect().right
expect(Math.ceil(region1Rect.right)).toBe node.clientWidth # TODO: Remove ceiling when react-wrapper is removed
region2Rect = regions[1].getBoundingClientRect()
expect(region2Rect.top).toBe 2 * lineHeightInPixels
expect(region2Rect.height).toBe 3 * lineHeightInPixels
expect(region2Rect.left).toBe scrollViewClientLeft + 0
expect(region2Rect.right).toBe scrollViewNode.getBoundingClientRect().right
expect(Math.ceil(region2Rect.right)).toBe node.clientWidth # TODO: Remove ceiling when react-wrapper is removed
region3Rect = regions[2].getBoundingClientRect()
expect(region3Rect.top).toBe 5 * lineHeightInPixels
@@ -461,12 +391,9 @@ describe "EditorComponent", ->
expect(region3Rect.left).toBe scrollViewClientLeft + 0
expect(region3Rect.width).toBe 10 * charWidth
it "does not render empty selections unless they are the first selection (to prevent a Chromium rendering artifact caused by removing it)", ->
editor.addSelectionForBufferRange([[2, 2], [2, 2]])
expect(editor.getSelection(0).isEmpty()).toBe true
expect(editor.getSelection(1).isEmpty()).toBe true
expect(node.querySelectorAll('.selection').length).toBe 1
it "does not render empty selections", ->
expect(editor.getSelection().isEmpty()).toBe true
expect(node.querySelectorAll('.selection').length).toBe 0
describe "mouse interactions", ->
linesNode = null
@@ -600,16 +527,16 @@ describe "EditorComponent", ->
editor.setScrollTop(10)
expect(verticalScrollbarNode.scrollTop).toBe 10
it "updates the horizontal scrollbar and the x transform of the lines based on the scrollLeft of the model", ->
it "updates the horizontal scrollbar and scroll view content x transform based on the scrollLeft of the model", ->
node.style.width = 30 * charWidth + 'px'
component.measureHeightAndWidth()
linesNode = node.querySelector('.lines')
expect(linesNode.style['-webkit-transform']).toBe "translate3d(0px, 0px, 0px)"
scrollViewContentNode = node.querySelector('.scroll-view-content')
expect(scrollViewContentNode.style['-webkit-transform']).toBe "translate3d(0px, 0px, 0)"
expect(horizontalScrollbarNode.scrollLeft).toBe 0
editor.setScrollLeft(100)
expect(linesNode.style['-webkit-transform']).toBe "translate3d(-100px, 0px, 0px)"
expect(scrollViewContentNode.style['-webkit-transform']).toBe "translate3d(-100px, 0px, 0)"
expect(horizontalScrollbarNode.scrollLeft).toBe 100
it "updates the scrollLeft of the model when the scrollLeft of the horizontal scrollbar changes", ->
@@ -627,7 +554,7 @@ describe "EditorComponent", ->
node.style.width = 10 * charWidth + 'px'
component.measureHeightAndWidth()
editor.setScrollBottom(editor.getScrollHeight())
lastLineNode = component.lineNodeForScreenRow(editor.getLastScreenRow())
lastLineNode = last(node.querySelectorAll('.line'))
bottomOfLastLine = lastLineNode.getBoundingClientRect().bottom
topOfHorizontalScrollbar = horizontalScrollbarNode.getBoundingClientRect().top
expect(bottomOfLastLine).toBe topOfHorizontalScrollbar
@@ -635,6 +562,7 @@ describe "EditorComponent", ->
# Scroll so there's no space below the last line when the horizontal scrollbar disappears
node.style.width = 100 * charWidth + 'px'
component.measureHeightAndWidth()
lastLineNode = last(node.querySelectorAll('.line'))
bottomOfLastLine = lastLineNode.getBoundingClientRect().bottom
bottomOfEditor = node.getBoundingClientRect().bottom
expect(bottomOfLastLine).toBe bottomOfEditor
@@ -646,9 +574,11 @@ describe "EditorComponent", ->
editor.setScrollLeft(Infinity)
rightOfLongestLine = component.lineNodeForScreenRow(6).getBoundingClientRect().right
lineNodes = node.querySelectorAll('.line')
rightOfLongestLine = lineNodes[6].getBoundingClientRect().right
leftOfVerticalScrollbar = verticalScrollbarNode.getBoundingClientRect().left
expect(Math.round(rightOfLongestLine)).toBe leftOfVerticalScrollbar - 1 # Leave 1 px so the cursor is visible on the end of the line
expect(rightOfLongestLine).toBe leftOfVerticalScrollbar - 1 # Leave 1 px so the cursor is visible on the end of the line
it "only displays dummy scrollbars when scrollable in that direction", ->
expect(verticalScrollbarNode.style.display).toBe 'none'
@@ -740,32 +670,6 @@ describe "EditorComponent", ->
expect(verticalScrollbarNode.scrollTop).toBe 10
expect(horizontalScrollbarNode.scrollLeft).toBe 15
describe "when the mousewheel event's target is a line", ->
it "keeps the line on the DOM if it is scrolled off-screen", ->
node.style.height = 4.5 * lineHeightInPixels + 'px'
node.style.width = 20 * charWidth + 'px'
component.measureHeightAndWidth()
lineNode = node.querySelector('.line')
wheelEvent = new WheelEvent('mousewheel', wheelDeltaX: 0, wheelDeltaY: -500)
Object.defineProperty(wheelEvent, 'target', get: -> lineNode)
node.dispatchEvent(wheelEvent)
expect(node.contains(lineNode)).toBe true
describe "when the mousewheel event's target is a line number", ->
it "keeps the line number on the DOM if it is scrolled off-screen", ->
node.style.height = 4.5 * lineHeightInPixels + 'px'
node.style.width = 20 * charWidth + 'px'
component.measureHeightAndWidth()
lineNumberNode = node.querySelectorAll('.line-number')[1]
wheelEvent = new WheelEvent('mousewheel', wheelDeltaX: 0, wheelDeltaY: -500)
Object.defineProperty(wheelEvent, 'target', get: -> lineNumberNode)
node.dispatchEvent(wheelEvent)
expect(node.contains(lineNumberNode)).toBe true
describe "input events", ->
inputNode = null
@@ -801,24 +705,3 @@ describe "EditorComponent", ->
expect(editor.consolidateSelections).toHaveBeenCalled()
expect(event.abortKeyBinding).toHaveBeenCalled()
describe "hiding and showing the editor", ->
describe "when fontSize, fontFamily, or lineHeight changes while the editor is hidden", ->
it "does not attempt to measure the lineHeight and defaultCharWidth until the editor becomes visible again", ->
wrapperView.hide()
initialLineHeightInPixels = editor.getLineHeightInPixels()
initialCharWidth = editor.getDefaultCharWidth()
component.setLineHeight(2)
expect(editor.getLineHeightInPixels()).toBe initialLineHeightInPixels
expect(editor.getDefaultCharWidth()).toBe initialCharWidth
component.setFontSize(22)
expect(editor.getLineHeightInPixels()).toBe initialLineHeightInPixels
expect(editor.getDefaultCharWidth()).toBe initialCharWidth
component.setFontFamily('monospace')
expect(editor.getLineHeightInPixels()).toBe initialLineHeightInPixels
expect(editor.getDefaultCharWidth()).toBe initialCharWidth
wrapperView.show()
expect(editor.getLineHeightInPixels()).not.toBe initialLineHeightInPixels
expect(editor.getDefaultCharWidth()).not.toBe initialCharWidth
+17 -48
Ver Arquivo
@@ -696,7 +696,7 @@ describe "Editor", ->
editor.manageScrollPosition = true
editor.setVerticalScrollMargin(2)
editor.setHorizontalScrollMargin(2)
editor.setLineHeightInPixels(10)
editor.setLineHeight(10)
editor.setDefaultCharWidth(10)
editor.setHorizontalScrollbarHeight(0)
editor.setHeight(5.5 * 10)
@@ -1135,7 +1135,7 @@ describe "Editor", ->
describe "when the 'autoscroll' option is true", ->
it "autoscrolls to the selection", ->
editor.manageScrollPosition = true
editor.setLineHeightInPixels(10)
editor.setLineHeight(10)
editor.setDefaultCharWidth(10)
editor.setHeight(50)
editor.setWidth(50)
@@ -1731,26 +1731,26 @@ describe "Editor", ->
editor.backspace()
expect(editor.lineForBufferRow(0)).toBe 'var = () {'
describe ".deleteToBeginningOfWord()", ->
describe ".backspaceToBeginningOfWord()", ->
describe "when no text is selected", ->
it "deletes all text between the cursor and the beginning of the word", ->
editor.setCursorBufferPosition([1, 24])
editor.addCursorAtBufferPosition([3, 5])
[cursor1, cursor2] = editor.getCursors()
editor.deleteToBeginningOfWord()
editor.backspaceToBeginningOfWord()
expect(buffer.lineForRow(1)).toBe ' var sort = function(ems) {'
expect(buffer.lineForRow(3)).toBe ' ar pivot = items.shift(), current, left = [], right = [];'
expect(cursor1.getBufferPosition()).toEqual [1, 22]
expect(cursor2.getBufferPosition()).toEqual [3, 4]
editor.deleteToBeginningOfWord()
editor.backspaceToBeginningOfWord()
expect(buffer.lineForRow(1)).toBe ' var sort = functionems) {'
expect(buffer.lineForRow(2)).toBe ' if (items.length <= 1) return itemsar pivot = items.shift(), current, left = [], right = [];'
expect(cursor1.getBufferPosition()).toEqual [1, 21]
expect(cursor2.getBufferPosition()).toEqual [2, 39]
editor.deleteToBeginningOfWord()
editor.backspaceToBeginningOfWord()
expect(buffer.lineForRow(1)).toBe ' var sort = ems) {'
expect(buffer.lineForRow(2)).toBe ' if (items.length <= 1) return ar pivot = items.shift(), current, left = [], right = [];'
expect(cursor1.getBufferPosition()).toEqual [1, 13]
@@ -1758,24 +1758,24 @@ describe "Editor", ->
editor.setText(' var sort')
editor.setCursorBufferPosition([0, 2])
editor.deleteToBeginningOfWord()
editor.backspaceToBeginningOfWord()
expect(buffer.lineForRow(0)).toBe 'var sort'
describe "when text is selected", ->
it "deletes only selected text", ->
editor.setSelectedBufferRanges([[[1, 24], [1, 27]], [[2, 0], [2, 4]]])
editor.deleteToBeginningOfWord()
editor.backspaceToBeginningOfWord()
expect(buffer.lineForRow(1)).toBe ' var sort = function(it) {'
expect(buffer.lineForRow(2)).toBe 'if (items.length <= 1) return items;'
describe ".deleteToBeginningOfLine()", ->
describe ".backspaceToBeginningOfLine()", ->
describe "when no text is selected", ->
it "deletes all text between the cursor and the beginning of the line", ->
editor.setCursorBufferPosition([1, 24])
editor.addCursorAtBufferPosition([2, 5])
[cursor1, cursor2] = editor.getCursors()
editor.deleteToBeginningOfLine()
editor.backspaceToBeginningOfLine()
expect(buffer.lineForRow(1)).toBe 'ems) {'
expect(buffer.lineForRow(2)).toBe 'f (items.length <= 1) return items;'
expect(cursor1.getBufferPosition()).toEqual [1, 0]
@@ -1784,13 +1784,13 @@ describe "Editor", ->
describe "when at the beginning of the line", ->
it "deletes the newline", ->
editor.setCursorBufferPosition([2])
editor.deleteToBeginningOfLine()
editor.backspaceToBeginningOfLine()
expect(buffer.lineForRow(1)).toBe ' var sort = function(items) { if (items.length <= 1) return items;'
describe "when text is selected", ->
it "still deletes all text to begginning of the line", ->
editor.setSelectedBufferRanges([[[1, 24], [1, 27]], [[2, 0], [2, 4]]])
editor.deleteToBeginningOfLine()
editor.backspaceToBeginningOfLine()
expect(buffer.lineForRow(1)).toBe 'ems) {'
expect(buffer.lineForRow(2)).toBe ' if (items.length <= 1) return items;'
@@ -2063,44 +2063,17 @@ describe "Editor", ->
describe ".copySelectedText()", ->
it "copies selected text onto the clipboard", ->
editor.setSelectedBufferRanges([[[0,4], [0,13]], [[1,6], [1, 10]], [[2,8], [2, 13]]])
editor.copySelectedText()
expect(buffer.lineForRow(0)).toBe "var quicksort = function () {"
expect(buffer.lineForRow(1)).toBe " var sort = function(items) {"
expect(buffer.lineForRow(2)).toBe " if (items.length <= 1) return items;"
expect(clipboard.readText()).toBe 'quicksort\nsort\nitems'
expect(atom.clipboard.readWithMetadata().metadata.selections).toEqual([
'quicksort'
'sort'
'items'
])
expect(clipboard.readText()).toBe 'quicksort\nsort'
describe ".pasteText()", ->
it "pastes text into the buffer", ->
atom.clipboard.write('first')
editor.pasteText()
expect(editor.lineForBufferRow(0)).toBe "var first = function () {"
expect(editor.lineForBufferRow(1)).toBe " var first = function(items) {"
describe 'when the clipboard has many selections', ->
it "pastes each selection separately into the buffer", ->
atom.clipboard.write('first\nsecond', {selections: ['first', 'second'] })
editor.pasteText()
expect(editor.lineForBufferRow(0)).toBe "var first = function () {"
expect(editor.lineForBufferRow(1)).toBe " var second = function(items) {"
describe 'and the selections count does not match', ->
it "pastes the whole text into the buffer", ->
atom.clipboard.write('first\nsecond\nthird', {selections: ['first', 'second', 'third'] })
editor.pasteText()
expect(editor.lineForBufferRow(0)).toBe "var first"
expect(editor.lineForBufferRow(1)).toBe "second"
expect(editor.lineForBufferRow(2)).toBe "third = function () {"
expect(editor.lineForBufferRow(3)).toBe " var first"
expect(editor.lineForBufferRow(4)).toBe "second"
expect(editor.lineForBufferRow(5)).toBe "third = function(items) {"
expect(editor.buffer.lineForRow(0)).toBe "var first = function () {"
expect(buffer.lineForRow(1)).toBe " var first = function(items) {"
describe ".indentSelectedRows()", ->
describe "when nothing is selected", ->
@@ -2623,10 +2596,6 @@ describe "Editor", ->
atom.workspace.open('sample-with-tabs.coffee', softTabs: true).then (editor) ->
expect(editor.getSoftTabs()).toBeFalsy()
waitsForPromise ->
atom.workspace.open('sample-with-tabs-and-initial-comment.js', softTabs: true).then (editor) ->
expect(editor.getSoftTabs()).toBeFalsy()
waitsForPromise ->
atom.workspace.open(null, softTabs: false).then (editor) ->
expect(editor.getSoftTabs()).toBeFalsy()
@@ -3123,7 +3092,7 @@ describe "Editor", ->
describe ".scrollToCursorPosition()", ->
it "scrolls the last cursor into view", ->
editor.setCursorScreenPosition([8, 8])
editor.setLineHeightInPixels(10)
editor.setLineHeight(10)
editor.setDefaultCharWidth(10)
editor.setHeight(50)
editor.setWidth(50)
@@ -3139,7 +3108,7 @@ describe "Editor", ->
it "scrolls one screen height up or down", ->
editor.manageScrollPosition = true
editor.setLineHeightInPixels(10)
editor.setLineHeight(10)
editor.setHeight(50)
expect(editor.getScrollHeight()).toBe 130
+2 -9
Ver Arquivo
@@ -33,10 +33,10 @@ describe "EditorView", ->
$('#jasmine-content').append(this)
waitsForPromise ->
atom.packages.activatePackage('language-text')
atom.packages.activatePackage('language-text', sync: true)
waitsForPromise ->
atom.packages.activatePackage('language-javascript')
atom.packages.activatePackage('language-javascript', sync: true)
getLineHeight = ->
return cachedLineHeight if cachedLineHeight?
@@ -1803,13 +1803,6 @@ describe "EditorView", ->
expect(editorView.renderedLines.find('.line:eq(10) .indent-guide').text()).toBe "#{eol} "
expect(editorView.renderedLines.find('.line:eq(10) .invisible-character').text()).toBe eol
describe "when editor.showIndentGuide is set to false", ->
it "does not render the indent guide on whitespace only lines (regression)", ->
editorView.attachToDom()
editor.setText(' ')
atom.config.set('editor.showIndentGuide', false)
expect(editorView.renderedLines.find('.line:eq(0) .indent-guide').length).toBe 0
describe "when soft-wrap is enabled", ->
beforeEach ->
jasmine.unspy(window, 'setTimeout')
-8
Ver Arquivo
@@ -1,8 +0,0 @@
/**
* Look, this is a comment. Don't go making assumtions that I want soft tabs
* because this block comment has leading spaces, Geez.
*/
if (beNice) {
console.log('Thank you for being nice.');
}
+3 -7
Ver Arquivo
@@ -261,9 +261,7 @@ window.waitsForPromise = (args...) ->
window.resetTimeouts = ->
window.now = 0
window.timeoutCount = 0
window.intervalCount = 0
window.timeouts = []
window.intervalTimeouts = {}
window.fakeSetTimeout = (callback, ms) ->
id = ++window.timeoutCount
@@ -274,15 +272,13 @@ window.fakeClearTimeout = (idToClear) ->
window.timeouts = window.timeouts.filter ([id]) -> id != idToClear
window.fakeSetInterval = (callback, ms) ->
id = ++window.intervalCount
action = ->
callback()
window.intervalTimeouts[id] = window.fakeSetTimeout(action, ms)
window.intervalTimeouts[id] = window.fakeSetTimeout(action, ms)
id
window.fakeSetTimeout(action, ms)
window.fakeSetTimeout(action, ms)
window.fakeClearInterval = (idToClear) ->
window.fakeClearTimeout(@intervalTimeouts[idToClear])
window.fakeClearTimeout(idToClear)
window.advanceClock = (delta=1) ->
window.now += delta
+1 -8
Ver Arquivo
@@ -20,7 +20,7 @@ describe "ThemeManager", ->
describe "theme getters and setters", ->
beforeEach ->
atom.packages.loadPackages()
atom.packages.loadPackages(sync: true)
it 'getLoadedThemes get all the loaded themes', ->
themes = themeManager.getLoadedThemes()
@@ -280,18 +280,11 @@ describe "ThemeManager", ->
describe "when a non-existent theme is present in the config", ->
it "logs a warning but does not throw an exception (regression)", ->
reloaded = false
waitsForPromise ->
themeManager.activateThemes()
runs ->
themeManager.once 'reloaded', -> reloaded = true
spyOn(console, 'warn')
expect(-> atom.config.set('core.themes', ['atom-light-ui', 'theme-really-does-not-exist'])).not.toThrow()
waitsFor -> reloaded
runs ->
expect(console.warn.callCount).toBe 1
expect(console.warn.argsForCall[0][0].length).toBeGreaterThan 0
+2 -5
Ver Arquivo
@@ -39,7 +39,7 @@ class Atom extends Model
# Public: Load or create the Atom environment in the given mode.
#
# - mode: Pass 'editor' or 'spec' depending on the kind of environment you
# want to build.
# want to build.
#
# Returns an Atom instance, fully initialized
@loadOrCreate: (mode) ->
@@ -473,15 +473,12 @@ class Atom extends Model
# Public: Set the full screen state of the current window.
setFullScreen: (fullScreen=false) ->
ipc.send('call-window-method', 'setFullScreen', fullScreen)
if fullScreen then document.body.classList.add("fullscreen") else document.body.classList.remove("fullscreen")
# Public: Is the current window in full screen mode?
isFullScreen: ->
@getCurrentWindow().isFullScreen()
# Public: Get the version of the Atom application.
#
# Returns the version text {String}.
getVersion: ->
@constructor.getVersion()
@@ -491,7 +488,7 @@ class Atom extends Model
# Public: Get the directory path to Atom's configuration area.
#
# Returns the absolute path to `~/.atom`.
# Returns the absolute path to ~/.atom
getConfigDirPath: ->
@constructor.getConfigDirPath()
-1
Ver Arquivo
@@ -146,7 +146,6 @@ class AtomApplication
atomWindow?.browserWindow.inspectElement(x, y)
@on 'application:open-documentation', -> shell.openExternal('https://atom.io/docs/latest/?app')
@on 'application:open-terms-of-use', -> shell.openExternal('https://atom.io/terms')
@on 'application:install-update', -> @autoUpdateManager.install()
@on 'application:check-for-update', => @autoUpdateManager.check()
+1 -1
Ver Arquivo
@@ -42,7 +42,7 @@ start = ->
app.removeListener 'open-url', addUrlToOpen
args.pathsToOpen = args.pathsToOpen.map (pathToOpen) ->
path.resolve(args.executedFrom ? process.cwd(), pathToOpen.toString())
path.resolve(args.executedFrom ? process.cwd(), pathToOpen)
require('coffee-script').register()
if args.devMode
+2 -9
Ver Arquivo
@@ -12,7 +12,7 @@ ChildProcess = require 'child_process'
# args = ['-ef']
# stdout = (output) -> console.log(output)
# exit = (code) -> console.log("ps -ef exited with #{code}")
# process = new BufferedProcess({command, args, stdout, exit})
# process = new BufferredProcess({command, args, stdout, exit})
# ```
module.exports =
class BufferedProcess
@@ -39,14 +39,7 @@ 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"
@process = ChildProcess.spawn(process.env.comspec || "cmd.exe",
[ "/c", command ].concat(args), options)
else
@process = ChildProcess.spawn(command, args, options)
@process = ChildProcess.spawn(command, args, options)
@killed = false
stdoutClosed = true
+3 -5
Ver Arquivo
@@ -222,13 +222,11 @@ class Config
#
# keyPath - The {String} name of the key to observe
# options - An optional {Object} containing the `callNow` key.
# callback - The {Function} to call when the value of the key changes.
# The first argument will be the new value of the key and the
#   second argument will be an {Object} with a `previous` property
# that is the prior value of the key.
# callback - The {Function} that fires when the. It is given a single argument, `value`,
# which is the new value of `keyPath`.
#
# Returns an {Object} with the following keys:
# :off - A {Function} that unobserves the `keyPath` when called.
# :off - A {Function} that unobserves the `keyPath` with called.
observe: (keyPath, options={}, callback) ->
if _.isFunction(options)
callback = options
-1
Ver Arquivo
@@ -98,6 +98,5 @@ class ContextMenuManager
showForEvent: (event) ->
@activeElement = event.target
menuTemplate = @combinedMenuTemplateForElement(event.target)
return unless menuTemplate?.length > 0
@executeBuildHandlers(event, menuTemplate)
remote.getCurrentWindow().emit('context-menu', menuTemplate)
+6 -8
Ver Arquivo
@@ -1,15 +1,13 @@
React = require 'react-atom-fork'
{div} = require 'reactionary-atom-fork'
React = require 'react'
{div} = require 'reactionary'
module.exports =
CursorComponent = React.createClass
displayName: 'CursorComponent'
render: ->
{cursor, scrollTop, scrollLeft} = @props
{top, left, height, width} = cursor.getPixelRect()
top -= scrollTop
left -= scrollLeft
WebkitTransform = "translate3d(#{left}px, #{top}px, 0px)"
{top, left, height, width} = @props.cursor.getPixelRect()
className = 'cursor'
className += ' blink-off' if @props.blinkOff
div className: 'cursor', style: {height, width, WebkitTransform}
div className: className, style: {top, left, height, width}
+1 -5
Ver Arquivo
@@ -78,11 +78,7 @@ class CursorView extends View
setVisible: (visible) ->
unless @visible is visible
@visible = visible
hiddenCursor = 'hidden-cursor'
if visible
@removeClass hiddenCursor
else
@addClass hiddenCursor
@toggle(@visible)
stopBlinking: ->
@constructor.stopBlinking(this) if @blinking
+1 -1
Ver Arquivo
@@ -465,7 +465,7 @@ class Cursor extends Model
getCurrentParagraphBufferRange: ->
@editor.languageMode.rowRangeForParagraphAtBufferRow(@getBufferRow())
# Public: Returns the characters preceding the cursor in the current word.
# Public: Returns the characters preceeding the cursor in the current word.
getCurrentWordPrefix: ->
@editor.getTextInBufferRange([@getBeginningOfCurrentWordBufferPosition(), @getBufferPosition()])
+15 -20
Ver Arquivo
@@ -1,9 +1,10 @@
React = require 'react-atom-fork'
{div} = require 'reactionary-atom-fork'
{debounce, toArray} = require 'underscore-plus'
React = require 'react'
{div} = require 'reactionary'
{debounce} = require 'underscore-plus'
SubscriberMixin = require './subscriber-mixin'
CursorComponent = require './cursor-component'
module.exports =
CursorsComponent = React.createClass
displayName: 'CursorsComponent'
@@ -12,44 +13,38 @@ CursorsComponent = React.createClass
cursorBlinkIntervalHandle: null
render: ->
{editor, scrollTop, scrollLeft} = @props
{blinkOff} = @state
{editor} = @props
blinkOff = @state.blinkCursorsOff
className = 'cursors'
className += ' blink-off' if blinkOff
div {className},
div className: 'cursors',
if @isMounted()
for selection in editor.getSelections()
if selection.isEmpty() and editor.selectionIntersectsVisibleRowRange(selection)
{cursor} = selection
CursorComponent({key: cursor.id, cursor, scrollTop, scrollLeft})
CursorComponent({key: cursor.id, cursor, blinkOff})
getInitialState: ->
blinkOff: false
blinkCursorsOff: false
componentDidMount: ->
{editor} = @props
@startBlinkingCursors()
componentWillUnmount: ->
@stopBlinkingCursors()
clearInterval(@cursorBlinkIntervalHandle)
componentWillUpdate: ({cursorsMoved}) ->
@pauseCursorBlinking() if cursorsMoved
startBlinkingCursors: ->
@toggleCursorBlinkHandle = setInterval(@toggleCursorBlink, @props.cursorBlinkPeriod / 2) if @isMounted()
@cursorBlinkIntervalHandle = setInterval(@toggleCursorBlink, @props.cursorBlinkPeriod / 2)
startBlinkingCursorsAfterDelay: null # Created lazily
stopBlinkingCursors: ->
clearInterval(@toggleCursorBlinkHandle)
toggleCursorBlink: ->
@setState(blinkOff: not @state.blinkOff)
toggleCursorBlink: -> @setState(blinkCursorsOff: not @state.blinkCursorsOff)
pauseCursorBlinking: ->
@state.blinkOff = false
@stopBlinkingCursors()
@state.blinkCursorsOff = false
clearInterval(@cursorBlinkIntervalHandle)
@startBlinkingCursorsAfterDelay ?= debounce(@startBlinkingCursors, @props.cursorBlinkResumeDelay)
@startBlinkingCursorsAfterDelay()
+16 -17
Ver Arquivo
@@ -23,7 +23,7 @@ class DisplayBuffer extends Model
manageScrollPosition: false
softWrap: null
editorWidthInChars: null
lineHeightInPixels: null
lineHeight: null
defaultCharWidth: null
height: null
width: null
@@ -198,8 +198,8 @@ class DisplayBuffer extends Model
@setScrollLeft(scrollRight - @width)
@getScrollRight()
getLineHeightInPixels: -> @lineHeightInPixels
setLineHeightInPixels: (@lineHeightInPixels) -> @lineHeightInPixels
getLineHeight: -> @lineHeight
setLineHeight: (@lineHeight) -> @lineHeight
getDefaultCharWidth: -> @defaultCharWidth
setDefaultCharWidth: (@defaultCharWidth) -> @defaultCharWidth
@@ -227,22 +227,21 @@ class DisplayBuffer extends Model
@charWidthsByScope = {}
getScrollHeight: ->
unless @getLineHeightInPixels() > 0
throw new Error("You must assign lineHeightInPixels before calling ::getScrollHeight()")
unless @getLineHeight() > 0
throw new Error("You must assign lineHeight before calling ::getScrollHeight()")
@getLineCount() * @getLineHeightInPixels()
@getLineCount() * @getLineHeight()
getScrollWidth: ->
(@getMaxLineLength() * @getDefaultCharWidth()) + @getCursorWidth()
getVisibleRowRange: ->
unless @getLineHeightInPixels() > 0
throw new Error("You must assign a non-zero lineHeightInPixels before calling ::getVisibleRowRange()")
heightInLines = Math.ceil(@getHeight() / @getLineHeightInPixels()) + 1
startRow = Math.floor(@getScrollTop() / @getLineHeightInPixels())
endRow = Math.min(@getLineCount(), startRow + heightInLines)
unless @getLineHeight() > 0
throw new Error("You must assign a non-zero lineHeight before calling ::getVisibleRowRange()")
heightInLines = Math.ceil(@getClientHeight() / @getLineHeight()) + 1
startRow = Math.floor(@getScrollTop() / @getLineHeight())
endRow = Math.min(@getLineCount(), Math.ceil(startRow + heightInLines))
[startRow, endRow]
intersectsVisibleRowRange: (startRow, endRow) ->
@@ -254,7 +253,7 @@ class DisplayBuffer extends Model
@intersectsVisibleRowRange(start.row, end.row + 1)
scrollToScreenRange: (screenRange) ->
verticalScrollMarginInPixels = @getVerticalScrollMargin() * @getLineHeightInPixels()
verticalScrollMarginInPixels = @getVerticalScrollMargin() * @getLineHeight()
horizontalScrollMarginInPixels = @getHorizontalScrollMargin() * @getDefaultCharWidth()
{top, left, height, width} = @pixelRectForScreenRange(screenRange)
@@ -285,11 +284,11 @@ class DisplayBuffer extends Model
if screenRange.end.row > screenRange.start.row
top = @pixelPositionForScreenPosition(screenRange.start).top
left = 0
height = (screenRange.end.row - screenRange.start.row + 1) * @getLineHeightInPixels()
height = (screenRange.end.row - screenRange.start.row + 1) * @getLineHeight()
width = @getScrollWidth()
else
{top, left} = @pixelPositionForScreenPosition(screenRange.start)
height = @getLineHeightInPixels()
height = @getLineHeight()
width = @pixelPositionForScreenPosition(screenRange.end).left - left
{top, left, width, height}
@@ -512,7 +511,7 @@ class DisplayBuffer extends Model
targetColumn = screenPosition.column
defaultCharWidth = @defaultCharWidth
top = targetRow * @lineHeightInPixels
top = targetRow * @lineHeight
left = 0
column = 0
for token in @lineForRow(targetRow).tokens
@@ -527,7 +526,7 @@ class DisplayBuffer extends Model
targetTop = pixelPosition.top
targetLeft = pixelPosition.left
defaultCharWidth = @defaultCharWidth
row = Math.floor(targetTop / @getLineHeightInPixels())
row = Math.floor(targetTop / @getLineHeight())
row = Math.min(row, @getLastRow())
row = Math.max(0, row)
+52 -143
Ver Arquivo
@@ -1,7 +1,6 @@
React = require 'react-atom-fork'
{div, span} = require 'reactionary-atom-fork'
{debounce, defaults} = require 'underscore-plus'
scrollbarStyle = require 'scrollbar-style'
React = require 'react'
{div, span} = require 'reactionary'
{debounce} = require 'underscore-plus'
GutterComponent = require './gutter-component'
EditorScrollViewComponent = require './editor-scroll-view-component'
@@ -20,21 +19,16 @@ EditorComponent = React.createClass
batchingUpdates: false
updateRequested: false
cursorsMoved: false
selectionChanged: false
selectionAdded: false
preservedRowRange: null
scrollingVertically: false
gutterWidth: 0
refreshingScrollbars: false
measuringScrollbars: true
pendingVerticalScrollDelta: 0
pendingHorizontalScrollDelta: 0
mouseWheelScreenRow: null
render: ->
{focused, fontSize, lineHeight, fontFamily, showIndentGuide, showInvisibles, visible} = @state
{focused, fontSize, lineHeight, fontFamily, showIndentGuide} = @state
{editor, cursorBlinkPeriod, cursorBlinkResumeDelay} = @props
maxLineNumberDigits = editor.getScreenLineCount().toString().length
invisibles = if showInvisibles then @state.invisibles else {}
if @isMounted()
renderedRowRange = @getRenderedRowRange()
@@ -42,8 +36,7 @@ EditorComponent = React.createClass
scrollWidth = editor.getScrollWidth()
scrollTop = editor.getScrollTop()
scrollLeft = editor.getScrollLeft()
lineHeightInPixels = editor.getLineHeightInPixels()
scrollViewHeight = editor.getHeight()
lineHeightInPixels = editor.getLineHeight()
horizontalScrollbarHeight = editor.getHorizontalScrollbarHeight()
verticalScrollbarWidth = editor.getVerticalScrollbarWidth()
verticallyScrollable = editor.verticallyScrollable()
@@ -53,19 +46,17 @@ EditorComponent = React.createClass
className += ' is-focused' if focused
div className: className, style: {fontSize, lineHeight, fontFamily}, tabIndex: -1,
GutterComponent {
ref: 'gutter', editor, renderedRowRange, maxLineNumberDigits,
scrollTop, scrollHeight, lineHeight, lineHeightInPixels, fontSize, fontFamily,
@pendingChanges, onWidthChanged: @onGutterWidthChanged, @mouseWheelScreenRow
}
# GutterComponent {
# editor, renderedRowRange, maxLineNumberDigits, scrollTop, scrollHeight,
# lineHeight: lineHeightInPixels, fontSize, fontFamily, @pendingChanges,
# onWidthChanged: @onGutterWidthChanged
# }
EditorScrollViewComponent {
ref: 'scrollView', editor, fontSize, fontFamily, showIndentGuide,
lineHeight, lineHeightInPixels, renderedRowRange, @pendingChanges,
scrollTop, scrollLeft, scrollHeight, scrollWidth, @scrollingVertically,
@cursorsMoved, @selectionChanged, @selectionAdded, cursorBlinkPeriod,
cursorBlinkResumeDelay, @onInputFocused, @onInputBlurred, @mouseWheelScreenRow,
invisibles, visible, scrollViewHeight
ref: 'scrollView', editor, fontSize, fontFamily, showIndentGuide
scrollHeight, scrollWidth, lineHeight: lineHeightInPixels,
renderedRowRange, @pendingChanges, @scrollingVertically, @cursorsMoved,
cursorBlinkPeriod, cursorBlinkResumeDelay, @onInputFocused, @onInputBlurred
}
ScrollbarComponent
@@ -101,19 +92,17 @@ EditorComponent = React.createClass
width: verticalScrollbarWidth
getRenderedRowRange: ->
{editor, lineOverdrawMargin} = @props
[visibleStartRow, visibleEndRow] = editor.getVisibleRowRange()
renderedStartRow = Math.max(0, visibleStartRow - lineOverdrawMargin)
renderedEndRow = Math.min(editor.getScreenLineCount(), visibleEndRow + lineOverdrawMargin)
[renderedStartRow, renderedEndRow]
renderedRowRange = @props.editor.getVisibleRowRange()
if @preservedRowRange?
renderedRowRange[0] = Math.min(@preservedRowRange[0], renderedRowRange[0])
renderedRowRange[1] = Math.max(@preservedRowRange[1], renderedRowRange[1])
renderedRowRange
getInitialState: ->
visible: true
getInitialState: -> {}
getDefaultProps: ->
cursorBlinkPeriod: 800
cursorBlinkResumeDelay: 100
lineOverdrawMargin: 8
cursorBlinkResumeDelay: 200
componentWillMount: ->
@pendingChanges = []
@@ -126,7 +115,6 @@ EditorComponent = React.createClass
@listenForCommands()
@measureScrollbars()
@subscribe atom.themes, 'stylesheet-added stylsheet-removed', @onStylesheetsChanged
@subscribe scrollbarStyle.changes, @refreshScrollbars
@props.editor.setVisible(true)
@requestUpdate()
@@ -140,8 +128,6 @@ EditorComponent = React.createClass
componentDidUpdate: ->
@pendingChanges.length = 0
@cursorsMoved = false
@selectionChanged = false
@selectionAdded = false
@refreshingScrollbars = false
@measureScrollbars() if @measuringScrollbars
@props.parentView.trigger 'editor:display-updated'
@@ -152,14 +138,15 @@ EditorComponent = React.createClass
@subscribe editor, 'batched-updates-ended', @onBatchedUpdatesEnded
@subscribe editor, 'screen-lines-changed', @onScreenLinesChanged
@subscribe editor, 'cursors-moved', @onCursorsMoved
@subscribe editor, 'selection-removed selection-screen-range-changed', @onSelectionChanged
@subscribe editor, 'selection-screen-range-changed', @requestUpdate
@subscribe editor, 'selection-added', @onSelectionAdded
@subscribe editor, 'selection-removed', @onSelectionAdded
@subscribe editor.$scrollTop.changes, @onScrollTopChanged
@subscribe editor.$scrollLeft.changes, @requestUpdate
@subscribe editor.$height.changes, @requestUpdate
@subscribe editor.$width.changes, @requestUpdate
@subscribe editor.$defaultCharWidth.changes, @requestUpdate
@subscribe editor.$lineHeightInPixels.changes, @requestUpdate
@subscribe editor.$lineHeight.changes, @requestUpdate
listenForDOMEvents: ->
node = @getDOMNode()
@@ -185,8 +172,8 @@ EditorComponent = React.createClass
'editor:move-to-previous-word': => editor.moveCursorToPreviousWord()
'editor:select-word': => editor.selectWord()
'editor:consolidate-selections': @consolidateSelections
'editor:delete-to-beginning-of-word': => editor.deleteToBeginningOfWord()
'editor:delete-to-beginning-of-line': => editor.deleteToBeginningOfLine()
'editor:backspace-to-beginning-of-word': => editor.backspaceToBeginningOfWord()
'editor:backspace-to-beginning-of-line': => editor.backspaceToBeginningOfLine()
'editor:delete-to-end-of-word': => editor.deleteToEndOfWord()
'editor:delete-line': => editor.deleteLine()
'editor:cut-to-end-of-line': => editor.cutToEndOfLine()
@@ -262,7 +249,6 @@ EditorComponent = React.createClass
'editor:scroll-to-cursor': => editor.scrollToCursorPosition()
'core:page-up': => editor.pageUp()
'core:page-down': => editor.pageDown()
'benchmark:scroll': @runScrollBenchmark
addCommandListeners: (listenersByCommandName) ->
{parentView} = @props
@@ -273,10 +259,7 @@ EditorComponent = React.createClass
observeConfig: ->
@subscribe atom.config.observe 'editor.fontFamily', @setFontFamily
@subscribe atom.config.observe 'editor.fontSize', @setFontSize
@subscribe atom.config.observe 'editor.lineHeight', @setLineHeight
@subscribe atom.config.observe 'editor.showIndentGuide', @setShowIndentGuide
@subscribe atom.config.observe 'editor.invisibles', @setInvisibles
@subscribe atom.config.observe 'editor.showInvisibles', @setShowInvisibles
measureScrollbars: ->
@measuringScrollbars = false
@@ -300,25 +283,6 @@ 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`).
setInvisibles: (invisibles={}) ->
defaults invisibles,
eol: '\u00ac'
space: '\u00b7'
tab: '\u00bb'
cr: '\u00a4'
@setState({invisibles})
setShowInvisibles: (showInvisibles) ->
@setState({showInvisibles})
onFocus: ->
@refs.scrollView.focus()
@@ -353,43 +317,19 @@ EditorComponent = React.createClass
@pendingScrollLeft = null
onMouseWheel: (event) ->
event.preventDefault()
screenRow = @screenRowForNode(event.target)
@mouseWheelScreenRow = screenRow if screenRow?
animationFramePending = @pendingHorizontalScrollDelta isnt 0 or @pendingVerticalScrollDelta isnt 0
# Only scroll in one direction at a time
{wheelDeltaX, wheelDeltaY} = event
if Math.abs(wheelDeltaX) > Math.abs(wheelDeltaY)
@pendingHorizontalScrollDelta -= wheelDeltaX
@refs.horizontalScrollbar.getDOMNode().scrollLeft -= wheelDeltaX
else
@pendingVerticalScrollDelta -= wheelDeltaY
@refs.verticalScrollbar.getDOMNode().scrollTop -= wheelDeltaY
unless animationFramePending
requestAnimationFrame =>
{editor} = @props
editor.setScrollTop(editor.getScrollTop() + @pendingVerticalScrollDelta)
editor.setScrollLeft(editor.getScrollLeft() + @pendingHorizontalScrollDelta)
@pendingVerticalScrollDelta = 0
@pendingHorizontalScrollDelta = 0
screenRowForNode: (node) ->
while node isnt document
if screenRow = node.dataset.screenRow
return parseInt(screenRow)
node = node.parentNode
null
event.preventDefault()
onStylesheetsChanged: (stylesheet) ->
@refreshScrollbars() if @containsScrollbarSelector(stylesheet)
# Only update when the scrollbar is changed
return unless @containsScrollbarSelector(stylesheet)
containsScrollbarSelector: (stylesheet) ->
for rule in stylesheet.cssRules
if rule.selectorText?.indexOf('scrollbar') > -1
return true
false
refreshScrollbars: ->
# Believe it or not, proper handling of changes to scrollbar styles requires
# three DOM updates.
@@ -409,6 +349,19 @@ EditorComponent = React.createClass
# if the editor's content and dimensions require them to be visible.
@requestUpdate()
containsScrollbarSelector: (stylesheet) ->
for rule in stylesheet.cssRules
if rule.selectorText?.indexOf('scrollbar') > -1
return true
false
clearPreservedRowRange: ->
@preservedRowRange = null
@scrollingVertically = false
@requestUpdate()
clearPreservedRowRangeAfterDelay: null # Created lazily
onBatchedUpdatesStarted: ->
@batchingUpdates = true
@@ -424,31 +377,20 @@ EditorComponent = React.createClass
@pendingChanges.push(change)
@requestUpdate() if editor.intersectsVisibleRowRange(change.start, change.end + 1) # TODO: Use closed-open intervals for change events
onSelectionChanged: (selection) ->
{editor} = @props
if editor.selectionIntersectsVisibleRowRange(selection)
@selectionChanged = true
@requestUpdate()
onSelectionAdded: (selection) ->
{editor} = @props
if editor.selectionIntersectsVisibleRowRange(selection)
@selectionChanged = true
@selectionAdded = true
@requestUpdate()
@requestUpdate() if editor.selectionIntersectsVisibleRowRange(selection)
onScrollTopChanged: ->
# @preservedRowRange = @getRenderedRowRange()
@scrollingVertically = true
@requestUpdate()
@stopScrollingAfterDelay ?= debounce(@onStoppedScrolling, 100)
@stopScrollingAfterDelay()
onStoppedScrolling: ->
@scrollingVertically = false
@mouseWheelScreenRow = null
# @clearPreservedRowRangeAfterDelay ?= debounce(@clearPreservedRowRange, 200)
# @clearPreservedRowRangeAfterDelay()
@requestUpdate()
stopScrollingAfterDelay: null # created lazily
onSelectionRemoved: (selection) ->
{editor} = @props
@requestUpdate() if editor.selectionIntersectsVisibleRowRange(selection)
onCursorsMoved: ->
@cursorsMoved = true
@@ -467,36 +409,3 @@ EditorComponent = React.createClass
consolidateSelections: (e) ->
e.abortKeyBinding() unless @props.editor.consolidateSelections()
lineNodeForScreenRow: (screenRow) -> @refs.scrollView.lineNodeForScreenRow(screenRow)
lineNumberNodeForScreenRow: (screenRow) -> @refs.gutter.lineNumberNodeForScreenRow(screenRow)
hide: ->
@setState(visible: false)
show: ->
@setState(visible: true)
runScrollBenchmark: ->
node = @getDOMNode()
scroll = (delta, done) ->
dispatchMouseWheelEvent = ->
node.dispatchEvent(new WheelEvent('mousewheel', wheelDeltaX: -0, wheelDeltaY: -delta))
stopScrolling = ->
clearInterval(interval)
done?()
interval = setInterval(dispatchMouseWheelEvent, 10)
setTimeout(stopScrolling, 500)
console.timeline('scroll')
scroll 50, ->
scroll 100, ->
scroll 200, ->
scroll 400, ->
scroll 800, ->
scroll 1600, ->
console.timelineEnd('scroll')
+19 -15
Ver Arquivo
@@ -1,5 +1,5 @@
React = require 'react-atom-fork'
{div} = require 'reactionary-atom-fork'
React = require 'react'
{div} = require 'reactionary'
{debounce} = require 'underscore-plus'
InputComponent = require './input-component'
@@ -16,15 +16,20 @@ EditorScrollViewComponent = React.createClass
overflowChangedWhilePaused: false
render: ->
{editor, fontSize, fontFamily, lineHeight, lineHeightInPixels, showIndentGuide, invisibles, visible} = @props
{renderedRowRange, pendingChanges, scrollTop, scrollLeft, scrollHeight, scrollWidth, scrollViewHeight, scrollingVertically, mouseWheelScreenRow} = @props
{selectionChanged, selectionAdded, cursorBlinkPeriod, cursorBlinkResumeDelay, cursorsMoved, onInputFocused, onInputBlurred} = @props
{editor, fontSize, fontFamily, lineHeight, showIndentGuide} = @props
{scrollHeight, scrollWidth, renderedRowRange, pendingChanges, scrollingVertically} = @props
{cursorBlinkPeriod, cursorBlinkResumeDelay, cursorsMoved, onInputFocused, onInputBlurred} = @props
if @isMounted()
inputStyle = @getHiddenInputPosition()
inputStyle.WebkitTransform = 'translateZ(0)'
div className: 'scroll-view', onMouseDown: @onMouseDown,
contentStyle =
height: scrollHeight
minWidth: scrollWidth
WebkitTransform: "translate3d(#{-editor.getScrollLeft()}px, #{-editor.getScrollTop()}px, 0)"
div className: 'scroll-view',
InputComponent
ref: 'input'
className: 'hidden-input'
@@ -33,13 +38,14 @@ EditorScrollViewComponent = React.createClass
onFocus: onInputFocused
onBlur: onInputBlurred
CursorsComponent({editor, scrollTop, scrollLeft, cursorsMoved, selectionAdded, cursorBlinkPeriod, cursorBlinkResumeDelay})
LinesComponent {
ref: 'lines', editor, fontSize, fontFamily, lineHeight, lineHeightInPixels,
showIndentGuide, renderedRowRange, pendingChanges, scrollTop, scrollLeft, scrollingVertically,
selectionChanged, scrollHeight, scrollWidth, mouseWheelScreenRow, invisibles,
visible, scrollViewHeight
}
div className: 'scroll-view-content', style: contentStyle, onMouseDown: @onMouseDown,
CursorsComponent({editor, cursorsMoved, cursorBlinkPeriod, cursorBlinkResumeDelay})
LinesComponent {
ref: 'lines', editor, fontSize, fontFamily, lineHeight, showIndentGuide,
renderedRowRange, pendingChanges, scrollingVertically
}
div className: 'underlayer',
SelectionsComponent({editor})
componentDidMount: ->
@getDOMNode().addEventListener 'overflowchanged', @onOverflowChanged
@@ -192,5 +198,3 @@ EditorScrollViewComponent = React.createClass
focus: ->
@refs.input.focus()
lineNodeForScreenRow: (screenRow) -> @refs.lines.lineNodeForScreenRow(screenRow)
+5 -8
Ver Arquivo
@@ -50,7 +50,7 @@ class EditorView extends View
showLineNumbers: true
autoIndent: true
normalizeIndentOnPaste: true
nonWordCharacters: "/\\()\"':,.;<>~!@#$%^&*|+=[]{}`?-"
nonWordCharacters: "./\\()\"':,.;<>~!@#$%^&*|+=[]{}`?-"
preferredLineLength: 80
tabLength: 2
softWrap: false
@@ -154,8 +154,8 @@ class EditorView extends View
'editor:move-to-previous-word': => @editor.moveCursorToPreviousWord()
'editor:select-word': => @editor.selectWord()
'editor:consolidate-selections': (event) => @consolidateSelections(event)
'editor:delete-to-beginning-of-word': => @editor.deleteToBeginningOfWord()
'editor:delete-to-beginning-of-line': => @editor.deleteToBeginningOfLine()
'editor:backspace-to-beginning-of-word': => @editor.backspaceToBeginningOfWord()
'editor:backspace-to-beginning-of-line': => @editor.backspaceToBeginningOfLine()
'editor:delete-to-end-of-word': => @editor.deleteToEndOfWord()
'editor:delete-line': => @editor.deleteLine()
'editor:cut-to-end-of-line': => @editor.cutToEndOfLine()
@@ -387,7 +387,7 @@ class EditorView extends View
screenPosition = @screenPositionFromMouseEvent(e)
if clickCount == 1
if e.metaKey or (process.platform isnt 'darwin' and e.ctrlKey)
if e.metaKey
@editor.addCursorAtScreenPosition(screenPosition)
else if e.shiftKey
@editor.selectToScreenPosition(screenPosition)
@@ -460,9 +460,6 @@ class EditorView extends View
@hiddenInput.val(lastInput)
false
# Ignore paste event, on Linux is wrongly emitted when user presses ctrl-v.
@on "paste", -> false
bringHiddenInputIntoView: ->
@hiddenInput.css(top: @scrollTop(), left: @scrollLeft())
@@ -1490,7 +1487,7 @@ class EditorView extends View
position = 0
for token in tokens
@updateScopeStack(line, scopeStack, token.scopes)
hasIndentGuide = not mini and showIndentGuide and (token.hasLeadingWhitespace or (token.hasTrailingWhitespace and lineIsWhitespaceOnly))
hasIndentGuide = not mini and showIndentGuide and token.hasLeadingWhitespace or (token.hasTrailingWhitespace and lineIsWhitespaceOnly)
line.push(token.getValueAsHtml({invisibles, hasIndentGuide}))
position += token.value.length
+23 -60
Ver Arquivo
@@ -109,8 +109,8 @@ TextMateScopeSelector = require('first-mate').ScopeSelector
# - {::insertNewlineAbove}
# - {::insertNewlineBelow}
# - {::backspace}
# - {::deleteToBeginningOfWord}
# - {::deleteToBeginningOfLine}
# - {::backspaceToBeginningOfWord}
# - {::backspaceToBeginningOfLine}
# - {::delete}
# - {::deleteToEndOfWord}
# - {::deleteLine}
@@ -149,7 +149,7 @@ class Editor extends Model
'autoDecreaseIndentForBufferRow', 'toggleLineCommentForBufferRow', 'toggleLineCommentsForBufferRows',
toProperty: 'languageMode'
@delegatesProperties '$lineHeightInPixels', '$defaultCharWidth', '$height', '$width',
@delegatesProperties '$lineHeight', '$defaultCharWidth', '$height', '$width',
'$scrollTop', '$scrollLeft', 'manageScrollPosition', toProperty: 'displayBuffer'
constructor: ({@softTabs, initialLine, initialColumn, tabLength, softWrap, @displayBuffer, buffer, registerEditor, suppressCursorCreation}) ->
@@ -160,7 +160,7 @@ class Editor extends Model
@displayBuffer ?= new DisplayBuffer({buffer, tabLength, softWrap})
@buffer = @displayBuffer.buffer
@softTabs = @usesSoftTabs() ? @softTabs ? atom.config.get('editor.softTabs') ? true
@softTabs = @buffer.usesSoftTabs() ? @softTabs ? atom.config.get('editor.softTabs') ? true
for marker in @findMarkers(@getSelectionMarkerAttributes())
marker.setAttributes(preserveFolds: true)
@@ -264,7 +264,7 @@ class Editor extends Model
else
'untitled'
# Controls visibility based on the given {Boolean}.
# Controls visiblity based on the given {Boolean}.
setVisible: (visible) -> @displayBuffer.setVisible(visible)
# Set the number of characters that can be displayed horizontally in the
@@ -275,7 +275,7 @@ class Editor extends Model
setEditorWidthInChars: (editorWidthInChars) ->
@displayBuffer.setEditorWidthInChars(editorWidthInChars)
# Public: Sets the column at which column will soft wrap
# Public: Sets the column at which columsn will soft wrap
getSoftWrapColumn: -> @displayBuffer.getSoftWrapColumn()
# Public: Returns a {Boolean} indicating whether softTabs are enabled for this
@@ -317,19 +317,6 @@ class Editor extends Model
# Public: Set the on-screen length of tab characters.
setTabLength: (tabLength) -> @displayBuffer.setTabLength(tabLength)
# Public: Determine if the buffer uses hard or soft tabs.
#
# Returns `true` if the first non-comment line with leading whitespace starts
# with a space character. Returns `false` if it starts with a hard tab (`\t`).
#
# Returns a {Boolean},
usesSoftTabs: ->
for bufferRow in [0..@buffer.getLastRow()]
continue if @displayBuffer.tokenizedBuffer.lineForScreenRow(bufferRow).isComment()
if match = @buffer.lineForRow(bufferRow).match(/^\s/)
return match[0][0] != '\t'
undefined
# Public: Clip the given {Point} to a valid position in the buffer.
#
# If the given {Point} describes a position that is actually reachable by the
@@ -576,8 +563,8 @@ class Editor extends Model
bufferRowForScreenRow: (row) -> @displayBuffer.bufferRowForScreenRow(row)
# Public: Get the syntactic scopes for the given position in buffer
# coordinates.
# Public: Get the syntactic scopes for the most the given position in buffer
# coorditanates.
#
# For example, if called with a position inside the parameter list of an
# anonymous CoffeeScript function, the method returns the following array:
@@ -658,27 +645,17 @@ class Editor extends Model
backspace: ->
@mutateSelectedText (selection) -> selection.backspace()
# Deprecated: Use {::deleteToBeginningOfWord} instead.
backspaceToBeginningOfWord: ->
deprecate("Use Editor::deleteToBeginningOfWord() instead")
@deleteToBeginningOfWord()
# Deprecated: Use {::deleteToBeginningOfLine} instead.
backspaceToBeginningOfLine: ->
deprecate("Use Editor::deleteToBeginningOfLine() instead")
@deleteToBeginningOfLine()
# Public: For each selection, if the selection is empty, delete all characters
# of the containing word that precede the cursor. Otherwise delete the
# selected text.
deleteToBeginningOfWord: ->
@mutateSelectedText (selection) -> selection.deleteToBeginningOfWord()
backspaceToBeginningOfWord: ->
@mutateSelectedText (selection) -> selection.backspaceToBeginningOfWord()
# Public: For each selection, if the selection is empty, delete all characters
# of the containing line that precede the cursor. Otherwise delete the
# selected text.
deleteToBeginningOfLine: ->
@mutateSelectedText (selection) -> selection.deleteToBeginningOfLine()
backspaceToBeginningOfLine: ->
@mutateSelectedText (selection) -> selection.backspaceToBeginningOfLine()
# Public: For each selection, if the selection is empty, delete the character
# preceding the cursor. Otherwise delete the selected text.
@@ -748,24 +725,13 @@ class Editor extends Model
# Public: For each selection, replace the selected text with the contents of
# the clipboard.
#
# If the clipboard contains the same number of selections as the current
# editor, each selection will be replaced with the content of the
# corresponding clipboard selection text.
#
# options - See {Selection::insertText}.
pasteText: (options={}) ->
{text, metadata} = atom.clipboard.readWithMetadata()
containsNewlines = text.indexOf('\n') isnt -1
if metadata?.selections? and metadata.selections.length is @getSelections().length
@mutateSelectedText (selection, index) ->
text = metadata.selections[index]
selection.insertText(text, options)
return
else if atom.config.get("editor.normalizeIndentOnPaste") and metadata?.indentBasis?
if atom.config.get('editor.normalizeIndentOnPaste') and metadata
if !@getCursor().hasPrecedingCharactersOnLine() or containsNewlines
options.indentBasis ?= metadata.indentBasis
@@ -1041,7 +1007,7 @@ class Editor extends Model
#
# fn - A {Function} that will be called with each {Selection}.
mutateSelectedText: (fn) ->
@transact => fn(selection,index) for selection,index in @getSelections()
@transact => fn(selection) for selection in @getSelections()
replaceSelectedText: (options={}, fn) ->
{selectWordIfEmpty} = options
@@ -1269,9 +1235,6 @@ class Editor extends Model
# Returns: An {Array} of {Selection}s.
getSelections: -> new Array(@selections...)
selectionsForScreenRows: (startRow, endRow) ->
@getSelections().filter (selection) -> selection.intersectsScreenRowRange(startRow, endRow)
# Public: Get the most recent {Selection} or the selection at the given
# index.
#
@@ -1306,7 +1269,7 @@ class Editor extends Model
# Public: Determine if a given range in buffer coordinates intersects a
# selection.
#
# bufferRange - A {Range} or range-compatible {Array}.
# bufferRange - A {Range} or range-comptatible {Array}.
#
# Returns a {Boolean}.
selectionIntersectsBufferRange: (bufferRange) ->
@@ -1580,28 +1543,28 @@ class Editor extends Model
# cursor is already on the first character of the line, move it to the
# beginning of the line.
#
# This method may merge selections that end up intersecting.
# This method may merge selections that end up intesecting.
selectToFirstCharacterOfLine: ->
@expandSelectionsBackward (selection) => selection.selectToFirstCharacterOfLine()
# Public: Move the cursor of each selection to the end of its line while
# preserving the selection's tail position.
#
# This method may merge selections that end up intersecting.
# This method may merge selections that end up intesecting.
selectToEndOfLine: ->
@expandSelectionsForward (selection) => selection.selectToEndOfLine()
# Public: For each selection, move its cursor to the preceding word boundary
# while maintaining the selection's tail position.
#
# This method may merge selections that end up intersecting.
# This method may merge selections that end up intesecting.
selectToPreviousWordBoundary: ->
@expandSelectionsBackward (selection) => selection.selectToPreviousWordBoundary()
# Public: For each selection, move its cursor to the next word boundary while
# maintaining the selection's tail position.
#
# This method may merge selections that end up intersecting.
# This method may merge selections that end up intesecting.
selectToNextWordBoundary: ->
@expandSelectionsForward (selection) => selection.selectToNextWordBoundary()
@@ -1611,7 +1574,7 @@ class Editor extends Model
selectLine: ->
@expandSelectionsForward (selection) => selection.selectLine()
# Public: Add a similarly-shaped selection to the next eligible line below
# Public: Add a similarly-shaped selection to the next elibible line below
# each selection.
#
# Operates on all selections. If the selection is empty, adds an empty
@@ -1622,7 +1585,7 @@ class Editor extends Model
addSelectionBelow: ->
@expandSelectionsForward (selection) => selection.addSelectionBelow()
# Public: Add a similarly-shaped selection to the next eligible line above
# Public: Add a similarly-shaped selection to the next elibible line above
# each selection.
#
# Operates on all selections. If the selection is empty, adds an empty
@@ -1859,8 +1822,8 @@ class Editor extends Model
getHorizontalScrollMargin: -> @displayBuffer.getHorizontalScrollMargin()
setHorizontalScrollMargin: (horizontalScrollMargin) -> @displayBuffer.setHorizontalScrollMargin(horizontalScrollMargin)
getLineHeightInPixels: -> @displayBuffer.getLineHeightInPixels()
setLineHeightInPixels: (lineHeightInPixels) -> @displayBuffer.setLineHeightInPixels(lineHeightInPixels)
getLineHeight: -> @displayBuffer.getLineHeight()
setLineHeight: (lineHeight) -> @displayBuffer.setLineHeight(lineHeight)
getScopedCharWidth: (scopeNames, char) -> @displayBuffer.getScopedCharWidth(scopeNames, char)
setScopedCharWidth: (scopeNames, char, width) -> @displayBuffer.setScopedCharWidth(scopeNames, char, width)
+1 -1
Ver Arquivo
@@ -13,7 +13,7 @@ Task = require './task'
# `atom.project` global and calling `getRepo()`. Note that this will only be
# available when the project is backed by a Git repository.
#
# This class handles submodules automatically by taking a `path` argument to many
# This class handles submodules automically by taking a `path` argument to many
# of the methods. This `path` argument will determine which underlying
# repository is used.
#
+56 -135
Ver Arquivo
@@ -1,166 +1,87 @@
React = require 'react-atom-fork'
{div} = require 'reactionary-atom-fork'
{isEqual, isEqualForProperties, multiplyString, toArray} = require 'underscore-plus'
React = require 'react'
{div} = require 'reactionary'
{isEqual, isEqualForProperties, multiplyString} = require 'underscore-plus'
SubscriberMixin = require './subscriber-mixin'
WrapperDiv = document.createElement('div')
module.exports =
GutterComponent = React.createClass
displayName: 'GutterComponent'
mixins: [SubscriberMixin]
lastMeasuredWidth: null
dummyLineNumberNode: null
render: ->
{scrollHeight, scrollTop} = @props
div className: 'gutter',
div className: 'line-numbers', ref: 'lineNumbers', style:
height: scrollHeight
WebkitTransform: "translate3d(0px, #{-scrollTop}px, 0px)"
@renderLineNumbers() if @isMounted()
componentWillMount: ->
@lineNumberNodesById = {}
@lineNumberIdsByScreenRow = {}
@screenRowsByLineNumberId = {}
renderLineNumbers: ->
{editor, renderedRowRange, maxLineNumberDigits, scrollTop, scrollHeight} = @props
[startRow, endRow] = renderedRowRange
charWidth = editor.getDefaultCharWidth()
lineHeight = editor.getLineHeight()
style =
width: charWidth * (maxLineNumberDigits + 1.5)
height: scrollHeight
WebkitTransform: "translate3d(0, #{-scrollTop}px, 0)"
componentDidMount: ->
@appendDummyLineNumber()
lineNumbers = []
tokenizedLines = editor.linesForScreenRows(startRow, endRow - 1)
tokenizedLines.push({id: 0}) if tokenizedLines.length is 0
for bufferRow, i in editor.bufferRowsForScreenRows(startRow, endRow - 1)
if bufferRow is lastBufferRow
lineNumber = ''
else
lastBufferRow = bufferRow
lineNumber = (bufferRow + 1).toString()
key = tokenizedLines[i].id
screenRow = startRow + i
lineNumbers.push(LineNumberComponent({key, lineNumber, maxLineNumberDigits, bufferRow, screenRow, lineHeight}))
lastBufferRow = bufferRow
div className: 'line-numbers', style: style,
lineNumbers
# Only update the gutter if the visible row range has changed or if a
# non-zero-delta change to the screen lines has occurred within the current
# visible row range.
shouldComponentUpdate: (newProps) ->
return true unless isEqualForProperties(newProps, @props, 'renderedRowRange', 'scrollTop', 'lineHeightInPixels', 'fontSize')
return true unless isEqualForProperties(newProps, @props, 'renderedRowRange', 'scrollTop', 'lineHeight', 'fontSize')
{renderedRowRange, pendingChanges} = newProps
for change in pendingChanges when Math.abs(change.screenDelta) > 0 or Math.abs(change.bufferDelta) > 0
for change in pendingChanges when change.screenDelta > 0 or change.bufferDelta > 0
return true unless change.end <= renderedRowRange.start or renderedRowRange.end <= change.start
false
componentDidUpdate: (oldProps) ->
unless oldProps.maxLineNumberDigits is @props.maxLineNumberDigits
@updateDummyLineNumber()
@removeLineNumberNodes()
unless @lastMeasuredWidth? and isEqualForProperties(oldProps, @props, 'maxLineNumberDigits', 'fontSize', 'fontFamily')
width = @getDOMNode().offsetWidth
if width isnt @lastMeasuredWidth
@lastMeasuredWidth = width
@props.onWidthChanged(width)
@measureWidth() unless @lastMeasuredWidth? and isEqualForProperties(oldProps, @props, 'maxLineNumberDigits', 'fontSize', 'fontFamily')
@clearScreenRowCaches() unless oldProps.lineHeightInPixels is @props.lineHeightInPixels
@updateLineNumbers()
LineNumberComponent = React.createClass
displayName: 'LineNumberComponent'
clearScreenRowCaches: ->
@lineNumberIdsByScreenRow = {}
@screenRowsByLineNumberId = {}
render: ->
{bufferRow, screenRow, lineHeight} = @props
div
className: "line-number line-number-#{bufferRow}"
style: {top: screenRow * lineHeight}
'data-buffer-row': bufferRow
'data-screen-row': screenRow
dangerouslySetInnerHTML: {__html: @buildInnerHTML()}
# This dummy line number element holds the gutter to the appropriate width,
# since the real line numbers are absolutely positioned for performance reasons.
appendDummyLineNumber: ->
{maxLineNumberDigits} = @props
WrapperDiv.innerHTML = @buildLineNumberHTML(0, false, maxLineNumberDigits)
@dummyLineNumberNode = WrapperDiv.children[0]
@refs.lineNumbers.getDOMNode().appendChild(@dummyLineNumberNode)
updateDummyLineNumber: ->
@dummyLineNumberNode.innerHTML = @buildLineNumberInnerHTML(0, false, @props.maxLineNumberDigits)
updateLineNumbers: ->
lineNumberIdsToPreserve = @appendOrUpdateVisibleLineNumberNodes()
@removeLineNumberNodes(lineNumberIdsToPreserve)
appendOrUpdateVisibleLineNumberNodes: ->
{editor, renderedRowRange, scrollTop, maxLineNumberDigits} = @props
[startRow, endRow] = renderedRowRange
newLineNumberIds = null
newLineNumbersHTML = null
visibleLineNumberIds = new Set
wrapCount = 0
for bufferRow, index in editor.bufferRowsForScreenRows(startRow, endRow - 1)
screenRow = startRow + index
if bufferRow is lastBufferRow
id = "#{bufferRow}-#{wrapCount++}"
else
id = bufferRow.toString()
lastBufferRow = bufferRow
wrapCount = 0
visibleLineNumberIds.add(id)
if @hasLineNumberNode(id)
@updateLineNumberNode(id, screenRow)
else
newLineNumberIds ?= []
newLineNumbersHTML ?= ""
newLineNumberIds.push(id)
newLineNumbersHTML += @buildLineNumberHTML(bufferRow, wrapCount > 0, maxLineNumberDigits, screenRow)
@screenRowsByLineNumberId[id] = screenRow
@lineNumberIdsByScreenRow[screenRow] = id
if newLineNumberIds?
WrapperDiv.innerHTML = newLineNumbersHTML
newLineNumberNodes = toArray(WrapperDiv.children)
node = @refs.lineNumbers.getDOMNode()
for lineNumberId, i in newLineNumberIds
lineNumberNode = newLineNumberNodes[i]
@lineNumberNodesById[lineNumberId] = lineNumberNode
node.appendChild(lineNumberNode)
visibleLineNumberIds
removeLineNumberNodes: (lineNumberIdsToPreserve) ->
{mouseWheelScreenRow} = @props
node = @refs.lineNumbers.getDOMNode()
for lineNumberId, lineNumberNode of @lineNumberNodesById when not lineNumberIdsToPreserve?.has(lineNumberId)
screenRow = @screenRowsByLineNumberId[lineNumberId]
unless screenRow is mouseWheelScreenRow
delete @lineNumberNodesById[lineNumberId]
delete @lineNumberIdsByScreenRow[screenRow] if @lineNumberIdsByScreenRow[screenRow] is lineNumberId
delete @screenRowsByLineNumberId[lineNumberId]
node.removeChild(lineNumberNode)
buildLineNumberHTML: (bufferRow, softWrapped, maxLineNumberDigits, screenRow) ->
if screenRow?
{lineHeightInPixels} = @props
style = "position: absolute; top: #{screenRow * lineHeightInPixels}px;"
buildInnerHTML: ->
{lineNumber, maxLineNumberDigits} = @props
if lineNumber.length < maxLineNumberDigits
padding = multiplyString('&nbsp;', maxLineNumberDigits - lineNumber.length)
padding + lineNumber + @iconDivHTML
else
style = "visibility: hidden;"
innerHTML = @buildLineNumberInnerHTML(bufferRow, softWrapped, maxLineNumberDigits)
lineNumber + @iconDivHTML
"<div class=\"line-number\" style=\"#{style}\" data-screen-row=\"#{screenRow}\">#{innerHTML}</div>"
iconDivHTML: '<div class="icon-right"></div>'
buildLineNumberInnerHTML: (bufferRow, softWrapped, maxLineNumberDigits) ->
if softWrapped
lineNumber = ""
else
lineNumber = (bufferRow + 1).toString()
padding = multiplyString('&nbsp;', maxLineNumberDigits - lineNumber.length)
iconHTML = '<div class="icon-right"></div>'
padding + lineNumber + iconHTML
updateLineNumberNode: (lineNumberId, screenRow) ->
unless @screenRowsByLineNumberId[lineNumberId] is screenRow
{lineHeightInPixels} = @props
@lineNumberNodesById[lineNumberId].style.top = screenRow * lineHeightInPixels + 'px'
@lineNumberNodesById[lineNumberId].dataset.screenRow = screenRow
@screenRowsByLineNumberId[lineNumberId] = screenRow
@lineNumberIdsByScreenRow[screenRow] = lineNumberId
hasLineNumberNode: (lineNumberId) ->
@lineNumberNodesById.hasOwnProperty(lineNumberId)
lineNumberNodeForScreenRow: (screenRow) ->
@lineNumberNodesById[@lineNumberIdsByScreenRow[screenRow]]
measureWidth: ->
lineNumberNode = @refs.lineNumbers.getDOMNode().firstChild
# return unless lineNumberNode?
width = lineNumberNode.offsetWidth
if width isnt @lastMeasuredWidth
@props.onWidthChanged(@lastMeasuredWidth = width)
shouldComponentUpdate: (newProps) ->
not isEqualForProperties(newProps, @props, 'lineHeight', 'screenRow', 'maxLineNumberDigits')
+3 -7
Ver Arquivo
@@ -1,7 +1,7 @@
punycode = require 'punycode'
{last, isEqual} = require 'underscore-plus'
React = require 'react-atom-fork'
{input} = require 'reactionary-atom-fork'
React = require 'react'
{input} = require 'reactionary'
module.exports =
InputComponent = React.createClass
@@ -10,13 +10,12 @@ InputComponent = React.createClass
render: ->
{className, style, onFocus, onBlur} = @props
input {className, style, onFocus, onBlur, 'data-react-skip-selection-restoration': true}
input {className, style, onFocus, onBlur}
getInitialState: ->
{lastChar: ''}
componentDidMount: ->
@getDOMNode().addEventListener 'paste', @onPaste
@getDOMNode().addEventListener 'input', @onInput
@getDOMNode().addEventListener 'compositionupdate', @onCompositionUpdate
@@ -33,9 +32,6 @@ InputComponent = React.createClass
shouldComponentUpdate: (newProps) ->
not isEqual(newProps.style, @props.style)
onPaste: (e) ->
e.preventDefault()
onInput: (e) ->
e.stopPropagation()
valueCharCodes = punycode.ucs2.decode(@getDOMNode().value)
+86 -191
Ver Arquivo
@@ -1,47 +1,27 @@
React = require 'react-atom-fork'
{div, span} = require 'reactionary-atom-fork'
React = require 'react'
{div, span} = require 'reactionary'
{debounce, isEqual, isEqualForProperties, multiplyString, toArray} = require 'underscore-plus'
{$$} = require 'space-pen'
SelectionsComponent = require './selections-component'
EditorView = require './editor-view'
DummyLineNode = $$(-> @div className: 'line', style: 'position: absolute; visibility: hidden;', => @span 'x')[0]
AcceptFilter = {acceptNode: -> NodeFilter.FILTER_ACCEPT}
WrapperDiv = document.createElement('div')
module.exports =
LinesComponent = React.createClass
displayName: 'LinesComponent'
measureWhenShown: false
render: ->
if @isMounted()
{editor, scrollTop, scrollLeft, scrollHeight, scrollWidth, lineHeightInPixels, scrollViewHeight} = @props
style =
height: Math.max(scrollHeight, scrollViewHeight)
width: scrollWidth
WebkitTransform: "translate3d(#{-scrollLeft}px, #{-scrollTop}px, 0px)"
div {className: 'lines', style},
SelectionsComponent({editor, lineHeightInPixels}) if @isMounted()
div className: 'lines'
componentWillMount: ->
@measuredLines = new WeakSet
@lineNodesByLineId = {}
@screenRowsByLineId = {}
@lineIdsByScreenRow = {}
componentDidMount: ->
@measureLineHeightInPixelsAndCharWidth()
@measureLineHeightAndCharWidth()
shouldComponentUpdate: (newProps) ->
return true if newProps.selectionChanged
return true unless isEqualForProperties(newProps, @props,
'renderedRowRange', 'fontSize', 'fontFamily', 'lineHeight', 'lineHeightInPixels',
'scrollTop', 'scrollLeft', 'showIndentGuide', 'scrollingVertically', 'invisibles',
'visible', 'scrollViewHeight'
)
return true unless isEqualForProperties(newProps, @props, 'renderedRowRange', 'fontSize', 'fontFamily', 'lineHeight', 'showIndentGuide')
{renderedRowRange, pendingChanges} = newProps
for change in pendingChanges
@@ -50,187 +30,102 @@ LinesComponent = React.createClass
false
componentDidUpdate: (prevProps) ->
@measureLineHeightInPixelsAndCharWidthIfNeeded(prevProps)
@clearScreenRowCaches() unless prevProps.lineHeightInPixels is @props.lineHeightInPixels
@removeLineNodes() unless isEqualForProperties(prevProps, @props, 'showIndentGuide', 'invisibles')
@updateLines()
@clearScopedCharWidths() unless isEqualForProperties(prevProps, @props, 'fontSize', 'fontFamily')
@measureCharactersInNewLines() unless @props.scrollingVertically
clearScreenRowCaches: ->
@screenRowsByLineId = {}
@lineIdsByScreenRow = {}
updateLines: ->
{editor, renderedRowRange, showIndentGuide, selectionChanged} = @props
[startRow, endRow] = renderedRowRange
visibleLines = editor.linesForScreenRows(startRow, endRow - 1)
@removeLineNodes(visibleLines)
@appendOrUpdateVisibleLineNodes(visibleLines, startRow)
removeLineNodes: (visibleLines=[]) ->
{mouseWheelScreenRow} = @props
visibleLineIds = new Set
visibleLineIds.add(line.id.toString()) for line in visibleLines
node = @getDOMNode()
for lineId, lineNode of @lineNodesByLineId when not visibleLineIds.has(lineId)
screenRow = @screenRowsByLineId[lineId]
unless screenRow is mouseWheelScreenRow
delete @lineNodesByLineId[lineId]
delete @lineIdsByScreenRow[screenRow] if @lineIdsByScreenRow[screenRow] is lineId
delete @screenRowsByLineId[lineId]
node.removeChild(lineNode)
appendOrUpdateVisibleLineNodes: (visibleLines, startRow) ->
newLines = null
newLinesHTML = null
for line, index in visibleLines
screenRow = startRow + index
if @hasLineNode(line.id)
@updateLineNode(line, screenRow)
else
newLines ?= []
newLinesHTML ?= ""
newLines.push(line)
newLinesHTML += @buildLineHTML(line, screenRow)
@screenRowsByLineId[line.id] = screenRow
@lineIdsByScreenRow[screenRow] = line.id
return unless newLines?
WrapperDiv.innerHTML = newLinesHTML
newLineNodes = toArray(WrapperDiv.children)
node = @getDOMNode()
for line, i in newLines
lineNode = newLineNodes[i]
@lineNodesByLineId[line.id] = lineNode
node.appendChild(lineNode)
hasLineNode: (lineId) ->
@lineNodesByLineId.hasOwnProperty(lineId)
buildLineHTML: (line, screenRow) ->
{editor, mini, showIndentGuide, lineHeightInPixels} = @props
{tokens, text, lineEnding, fold, isSoftWrapped, indentLevel} = line
top = screenRow * lineHeightInPixels
lineHTML = "<div class=\"line\" style=\"position: absolute; top: #{top}px;\" data-screen-row=\"#{screenRow}\">"
if text is ""
lineHTML += @buildEmptyLineInnerHTML(line)
if not prevProps.renderedRowRange? or prevProps.lineHeight isnt @props.lineHeight
@renderLines()
else
lineHTML += @buildLineInnerHTML(line)
@updateRenderedLines(prevProps.renderedRowRange)
lineHTML += "</div>"
lineHTML
@measureLineHeightAndCharWidth() unless isEqualForProperties(prevProps, @props, 'fontSize', 'fontFamily', 'lineHeight')
# @clearScopedCharWidths() unless isEqualForProperties(prevProps, @props, 'fontSize', 'fontFamily')
# @measureCharactersInNewLines() unless @props.scrollingVertically
buildEmptyLineInnerHTML: (line) ->
{showIndentGuide} = @props
{indentLevel, tabLength} = line
if showIndentGuide and indentLevel > 0
indentSpan = "<span class='indent-guide'>#{multiplyString(' ', tabLength)}</span>"
multiplyString(indentSpan, indentLevel + 1)
else
"&nbsp;"
buildLineInnerHTML: (line) ->
{invisibles, mini, showIndentGuide, invisibles} = @props
{tokens, text} = line
innerHTML = ""
scopeStack = []
firstTrailingWhitespacePosition = text.search(/\s*$/)
lineIsWhitespaceOnly = firstTrailingWhitespacePosition is 0
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 += @popScope(scopeStack) while scopeStack.length > 0
innerHTML += @buildEndOfLineHTML(line, invisibles)
innerHTML
buildEndOfLineHTML: (line, invisibles) ->
return '' if @props.mini or line.isSoftWrapped()
html = ''
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>"
html
updateScopeStack: (scopeStack, desiredScopes) ->
html = ""
# Find a common prefix
for scope, i in desiredScopes
break unless scopeStack[i]?.scope is desiredScopes[i]
# Pop scopes until we're at the common prefx
until scopeStack.length is i
html += @popScope(scopeStack)
# Push onto common prefix until scopeStack equals desiredScopes
for j in [i...desiredScopes.length]
html += @pushScope(scopeStack, desiredScopes[j])
html
popScope: (scopeStack) ->
scopeStack.pop()
"</span>"
pushScope: (scopeStack, scope) ->
scopeStack.push(scope)
"<span class=\"#{scope.replace(/\.+/g, ' ')}\">"
updateLineNode: (line, screenRow) ->
unless @screenRowsByLineId[line.id] is screenRow
{lineHeightInPixels} = @props
lineNode = @lineNodesByLineId[line.id]
lineNode.style.top = screenRow * lineHeightInPixels + 'px'
lineNode.dataset.screenRow = screenRow
@screenRowsByLineId[line.id] = screenRow
@lineIdsByScreenRow[screenRow] = line.id
lineNodeForScreenRow: (screenRow) ->
@lineNodesByLineId[@lineIdsByScreenRow[screenRow]]
measureLineHeightInPixelsAndCharWidthIfNeeded: (prevProps) ->
{visible} = @props
unless isEqualForProperties(prevProps, @props, 'fontSize', 'fontFamily', 'lineHeight')
if visible
@measureLineHeightInPixelsAndCharWidth()
else
@measureWhenShown = true
@measureLineHeightInPixelsAndCharWidth() if visible and not prevProps.visible and @measureWhenShown
measureLineHeightInPixelsAndCharWidth: ->
@measureWhenShown = false
measureLineHeightAndCharWidth: ->
node = @getDOMNode()
node.appendChild(DummyLineNode)
lineHeightInPixels = DummyLineNode.getBoundingClientRect().height
lineHeight = DummyLineNode.getBoundingClientRect().height
charWidth = DummyLineNode.firstChild.getBoundingClientRect().width
node.removeChild(DummyLineNode)
{editor} = @props
editor.setLineHeightInPixels(lineHeightInPixels)
editor.setLineHeight(lineHeight)
editor.setDefaultCharWidth(charWidth)
renderLines: ->
[startRow, endRow] = @props.renderedRowRange
@getDOMNode().innerHTML = @buildHTMLForScreenRowRange(startRow, endRow)
updateRenderedLines: (oldRenderedRowRange) ->
[oldStartRow, oldEndRow] = oldRenderedRowRange
[newStartRow, newEndRow] = @props.renderedRowRange
node = @getDOMNode()
if newEndRow <= oldStartRow or newStartRow >= oldEndRow
@renderLines()
return
if newEndRow > oldEndRow
for lineNode in @buildLineNodesForScreenRowRange(oldEndRow, newEndRow)
node.appendChild(lineNode)
else if newEndRow < oldEndRow
extraLineCount = oldEndRow - newEndRow
while extraLineCount > 0
node.removeChild(node.lastChild)
extraLineCount--
if newStartRow < oldStartRow
oldFirstLineNode = node.firstChild
for lineNode in @buildLineNodesForScreenRowRange(newStartRow, Math.min(newEndRow, oldStartRow))
node.insertBefore(lineNode, oldFirstLineNode)
else if newStartRow > oldStartRow
extraLineCount = newStartRow - oldStartRow
while extraLineCount > 0
node.removeChild(node.firstChild)
extraLineCount--
buildLineNodesForScreenRowRange: (startRow, endRow) ->
wrapper = document.createElement('div')
wrapper.innerHTML = @buildHTMLForScreenRowRange(startRow, endRow)
toArray(wrapper.children)
buildHTMLForScreenRowRange: (startRow, endRow) ->
{editor} = @props
linesHTML = ""
for tokenizedLine, i in editor.linesForScreenRows(startRow, endRow - 1)
linesHTML += @buildHTMLForTokenizedLine(tokenizedLine, startRow + i)
linesHTML
buildHTMLForTokenizedLine: (screenLine, screenRow) ->
{tokens, text, lineEnding, fold, isSoftWrapped} = screenLine
{editor, lineHeight, showIndentGuide, mini} = @props
attributes =
class: "line"
style: "-webkit-transform: translate3d(0, #{screenRow * lineHeight}px, 0)"
if fold
attributes.class += " fold"
attributes['fold-id'] = fold.id
# invisibles = @invisibles if @showInvisibles
# eolInvisibles = @getEndOfLineInvisibles(screenLine)
# htmlEolInvisibles = @buildHtmlEndOfLineInvisibles(screenLine)
invisibles = {}
eolInvisibles = {}
htmlEolInvisibles = ""
indentation = EditorView.buildIndentation(screenRow, editor)
EditorView.buildLineHtml({tokens, text, lineEnding, fold, isSoftWrapped, invisibles, eolInvisibles, htmlEolInvisibles, attributes, showIndentGuide, indentation, editor, mini})
measureCharactersInNewLines: ->
[visibleStartRow, visibleEndRow] = @props.renderedRowRange
node = @getDOMNode()
for tokenizedLine in @props.editor.linesForScreenRows(visibleStartRow, visibleEndRow - 1)
for tokenizedLine, i in @props.editor.linesForScreenRows(visibleStartRow, visibleEndRow - 1)
unless @measuredLines.has(tokenizedLine)
lineNode = @lineNodesByLineId[tokenizedLine.id]
lineNode = node.children[i]
@measureCharactersInLine(tokenizedLine, lineNode)
measureCharactersInLine: (tokenizedLine, lineNode) ->
+2 -7
Ver Arquivo
@@ -58,7 +58,7 @@ class MenuManager
testBody = document.createElement('body')
testBody.classList.add(@classesForElement(document.body)...)
testWorkspace = document.createElement('div')
testWorkspace = document.createElement('body')
workspaceClasses = @classesForElement(document.body.querySelector('.workspace'))
workspaceClasses = ['workspace'] if workspaceClasses.length is 0
testWorkspace.classList.add(workspaceClasses...)
@@ -69,12 +69,7 @@ class MenuManager
@testEditor.classList.add('editor')
testWorkspace.appendChild(@testEditor)
element = @testEditor
while element
return true if element.webkitMatchesSelector(selector)
element = element.parentElement
false
@testEditor.webkitMatchesSelector(selector)
# Public: Refreshes the currently visible menu.
update: ->
+1 -3
Ver Arquivo
@@ -43,9 +43,7 @@ class PackageManager
# Public: Get the path to the apm command
getApmPath: ->
commandName = 'apm'
commandName += '.cmd' if process.platform is 'win32'
@apmPath ?= path.resolve(__dirname, '..', 'apm', 'node_modules', 'atom-package-manager', 'bin', commandName)
@apmPath ?= path.resolve(__dirname, '..', 'apm', 'node_modules', 'atom-package-manager', 'bin', 'apm')
# Public: Get the paths being used to look for packages.
#
+2 -2
Ver Arquivo
@@ -10,7 +10,7 @@ Pane = require './pane'
# Items can be almost anything however most commonly they're {EditorView}s.
#
# Most packages won't need to use this class, unless you're interested in
# building a package that deals with switching between panes or items.
# building a package that deals with switching between panes or tiems.
module.exports =
class PaneView extends View
Delegator.includeInto(this)
@@ -149,7 +149,7 @@ class PaneView extends View
hasFocus = @hasFocus()
item.on? 'title-changed', @activeItemTitleChanged
view = @viewForItem(item)
otherView.hide() for otherView in @itemViews.children().not(view).views()
@itemViews.children().not(view).hide()
@itemViews.append(view) unless view.parent().is(@itemViews)
view.show() if @attached
view.focus() if hasFocus
+6 -17
Ver Arquivo
@@ -1,7 +1,6 @@
{View, $} = require 'space-pen'
React = require 'react-atom-fork'
React = require 'react'
EditorComponent = require './editor-component'
{defaults} = require 'underscore-plus'
module.exports =
class ReactEditorView extends View
@@ -9,12 +8,12 @@ class ReactEditorView extends View
focusOnAttach: false
constructor: (@editor, @props) ->
constructor: (@editor) ->
super
getEditor: -> @editor
Object.defineProperty @::, 'lineHeight', get: -> @editor.getLineHeightInPixels()
Object.defineProperty @::, 'lineHeight', get: -> @editor.getLineHeight()
Object.defineProperty @::, 'charWidth', get: -> @editor.getDefaultCharWidth()
scrollTop: (scrollTop) ->
@@ -38,12 +37,11 @@ class ReactEditorView extends View
afterAttach: (onDom) ->
return unless onDom
@attached = true
props = defaults({@editor, parentView: this}, @props)
@component = React.renderComponent(EditorComponent(props), @element)
@component = React.renderComponent(EditorComponent({@editor, parentView: this}), @element)
node = @component.getDOMNode()
@underlayer = $(node).find('.selections')
@underlayer = $(node).find('.underlayer')
@gutter = $(node).find('.gutter')
@gutter.removeClassFromAllLines = (klass) =>
@@ -66,8 +64,7 @@ class ReactEditorView extends View
appendToLinesView: (view) ->
view.css('position', 'absolute')
view.css('z-index', 1)
@find('.lines').prepend(view)
@find('.scroll-view-content').prepend(view)
beforeRemove: ->
React.unmountComponentAtNode(@element)
@@ -82,11 +79,3 @@ class ReactEditorView extends View
@component.onFocus()
else
@focusOnAttach = true
hide: ->
super
@component.hide()
show: ->
super
@component.show()
+2 -2
Ver Arquivo
@@ -1,5 +1,5 @@
React = require 'react-atom-fork'
{div} = require 'reactionary-atom-fork'
React = require 'react'
{div} = require 'reactionary'
{extend, isEqualForProperties} = require 'underscore-plus'
module.exports =
+2 -2
Ver Arquivo
@@ -1,5 +1,5 @@
React = require 'react-atom-fork'
{div} = require 'reactionary-atom-fork'
React = require 'react'
{div} = require 'reactionary'
module.exports =
ScrollbarComponent = React.createClass
+4 -58
Ver Arquivo
@@ -1,65 +1,11 @@
React = require 'react-atom-fork'
{div} = require 'reactionary-atom-fork'
React = require 'react'
{div} = require 'reactionary'
module.exports =
SelectionComponent = React.createClass
displayName: 'SelectionComponent'
render: ->
{editor, screenRange, lineHeightInPixels} = @props
{start, end} = screenRange
rowCount = end.row - start.row + 1
startPixelPosition = editor.pixelPositionForScreenPosition(start)
endPixelPosition = editor.pixelPositionForScreenPosition(end)
div className: 'selection',
if rowCount is 1
@renderSingleLineRegions(startPixelPosition, endPixelPosition)
else
@renderMultiLineRegions(startPixelPosition, endPixelPosition, rowCount)
renderSingleLineRegions: (startPixelPosition, endPixelPosition) ->
{lineHeightInPixels} = @props
[
div className: 'region', key: 0, style:
top: startPixelPosition.top
height: lineHeightInPixels
left: startPixelPosition.left
width: endPixelPosition.left - startPixelPosition.left
]
renderMultiLineRegions: (startPixelPosition, endPixelPosition, rowCount) ->
{lineHeightInPixels} = @props
regions = []
index = 0
# First row, extending from selection start to the right side of screen
regions.push(
div className: 'region', key: index++, style:
top: startPixelPosition.top
left: startPixelPosition.left
height: lineHeightInPixels
right: 0
)
# Middle rows, extending from left side to right side of screen
if rowCount > 2
regions.push(
div className: 'region', key: index++, style:
top: startPixelPosition.top + lineHeightInPixels
height: (rowCount - 2) * lineHeightInPixels
left: 0
right: 0
)
# Last row, extending from left side of screen to selection end
regions.push(
div className: 'region', key: index, style:
top: endPixelPosition.top
height: lineHeightInPixels
left: 0
width: endPixelPosition.left
)
regions
for regionRect, i in @props.selection.getRegionRects()
div className: 'region', key: i, style: regionRect
+44 -31
Ver Arquivo
@@ -382,25 +382,15 @@ class Selection extends Model
@selectLeft() if @isEmpty() and not @editor.isFoldedAtScreenRow(@cursor.getScreenRow())
@deleteSelectedText()
# Deprecated: Use {::deleteToBeginningOfWord} instead.
backspaceToBeginningOfWord: ->
deprecate("Use Selection::deleteToBeginningOfWord() instead")
@deleteToBeginningOfWord()
# Deprecated: Use {::deleteToBeginningOfLine} instead.
backspaceToBeginningOfLine: ->
deprecate("Use Selection::deleteToBeginningOfLine() instead")
@deleteToBeginningOfLine()
# Public: Removes from the start of the selection to the beginning of the
# current word if the selection is empty otherwise it deletes the selection.
deleteToBeginningOfWord: ->
backspaceToBeginningOfWord: ->
@selectToBeginningOfWord() if @isEmpty()
@deleteSelectedText()
# Public: Removes from the beginning of the line which the selection begins on
# all the way through to the end of the selection.
deleteToBeginningOfLine: ->
backspaceToBeginningOfLine: ->
if @isEmpty() and @cursor.isAtBeginningOfLine()
@selectLeft()
else
@@ -513,23 +503,11 @@ class Selection extends Model
@delete()
# Public: Copies the current selection to the clipboard.
#
# If the `maintainClipboard` is set to `true`, a specific metadata property
# is created to store each content copied to the clipboard. The clipboard
# `text` still contains the concatenation of the clipboard with the
# current selection.
copy: (maintainClipboard=false) ->
return if @isEmpty()
text = @editor.buffer.getTextInRange(@getBufferRange())
if maintainClipboard
{text: clipboardText, metadata} = atom.clipboard.readWithMetadata()
if metadata?.selections?
metadata.selections.push(text)
else
metadata = { selections: [clipboardText, text] }
text = "" + (clipboardText) + "\n" + text
text = "#{atom.clipboard.read()}\n#{text}"
else
metadata = { indentBasis: @editor.indentationForBufferRow(@getBufferRange().start.row) }
@@ -563,12 +541,6 @@ class Selection extends Model
intersectsBufferRange: (bufferRange) ->
@getBufferRange().intersectsWith(bufferRange)
intersectsScreenRowRange: (startRow, endRow) ->
@getScreenRange().intersectsRowRange(startRow, endRow)
intersectsScreenRow: (screenRow) ->
@getScreenRange().intersectsRow(screenRow)
# Public: Identifies if a selection intersects with another selection.
#
# otherSelection - A {Selection} to check against.
@@ -601,6 +573,47 @@ class Selection extends Model
compare: (otherSelection) ->
@getBufferRange().compare(otherSelection.getBufferRange())
# Get the pixel dimensions of rectangular regions that cover selection's area
# on the screen. Used by SelectionComponent for rendering.
getRegionRects: ->
lineHeight = @editor.getLineHeight()
{start, end} = @getScreenRange()
rowCount = end.row - start.row + 1
startPixelPosition = @editor.pixelPositionForScreenPosition(start)
endPixelPosition = @editor.pixelPositionForScreenPosition(end)
if rowCount is 1
# Single line selection
rects = [{
top: startPixelPosition.top
height: lineHeight
left: startPixelPosition.left
width: endPixelPosition.left - startPixelPosition.left
}]
else
# Multi-line selection
rects = []
# First row, extending from selection start to the right side of screen
rects.push {
top: startPixelPosition.top
left: startPixelPosition.left
height: lineHeight
right: 0
}
if rowCount > 2
# Middle rows, extending from left side to right side of screen
rects.push {
top: startPixelPosition.top + lineHeight
height: (rowCount - 2) * lineHeight
left: 0
right: 0
}
# Last row, extending from left side of screen to selection end
rects.push {top: endPixelPosition.top, height: lineHeight, left: 0, width: endPixelPosition.left }
rects
screenRangeChanged: ->
screenRange = @getScreenRange()
@emit 'screen-range-changed', screenRange
+7 -34
Ver Arquivo
@@ -1,5 +1,5 @@
React = require 'react-atom-fork'
{div} = require 'reactionary-atom-fork'
React = require 'react'
{div} = require 'reactionary'
SelectionComponent = require './selection-component'
module.exports =
@@ -7,37 +7,10 @@ SelectionsComponent = React.createClass
displayName: 'SelectionsComponent'
render: ->
div className: 'selections', @renderSelections()
renderSelections: ->
{editor, lineHeightInPixels} = @props
selectionComponents = []
for selectionId, screenRange of @selectionRanges
selectionComponents.push(SelectionComponent({key: selectionId, screenRange, editor, lineHeightInPixels}))
selectionComponents
componentWillMount: ->
@selectionRanges = {}
shouldComponentUpdate: ->
{editor} = @props
oldSelectionRanges = @selectionRanges
newSelectionRanges = {}
@selectionRanges = newSelectionRanges
for selection, index in editor.getSelections()
# Rendering artifacts occur on the lines GPU layer if we remove the last selection
if index is 0 or (not selection.isEmpty() and editor.selectionIntersectsVisibleRowRange(selection))
newSelectionRanges[selection.id] = selection.getScreenRange()
for id, range of newSelectionRanges
if oldSelectionRanges.hasOwnProperty(id)
return true unless range.isEqual(oldSelectionRanges[id])
else
return true
for id of oldSelectionRanges
return true unless newSelectionRanges.hasOwnProperty(id)
false
div className: 'selections',
if @isMounted()
for selection in editor.getSelections()
if not selection.isEmpty() and editor.selectionIntersectsVisibleRowRange(selection)
SelectionComponent({key: selection.id, selection})
+2 -13
Ver Arquivo
@@ -7,22 +7,11 @@ class TokenizedLine
constructor: ({tokens, @lineEnding, @ruleStack, @startBufferColumn, @fold, @tabLength, @indentLevel}) ->
@tokens = @breakOutAtomicTokens(tokens)
@startBufferColumn ?= 0
@text = @buildText()
@bufferDelta = @buildBufferDelta()
@text = _.pluck(@tokens, 'value').join('')
@bufferDelta = _.sum(_.pluck(@tokens, 'bufferDelta'))
@id = idCounter++
@markLeadingAndTrailingWhitespaceTokens()
buildText: ->
text = ""
text += token.value for token in @tokens
text
buildBufferDelta: ->
delta = 0
delta += token.bufferDelta for token in @tokens
delta
copy: ->
new TokenizedLine({@tokens, @lineEnding, @ruleStack, @startBufferColumn, @fold})
+3 -4
Ver Arquivo
@@ -24,9 +24,9 @@ Editor = require './editor'
# with the model object when possible, but it won't always be possible with the
# current API.
#
# ## Adding Perimeter Panels
# ## Adding Perimiter Panels
#
# Use the following methods if possible to attach panels to the perimeter of the
# Use the following methods if possible to attach panels to the perimiter of the
# workspace rather than manipulating the DOM directly to better insulate you to
# changes in the workspace markup:
#
@@ -64,7 +64,7 @@ class WorkspaceView extends View
@version: 4
@configDefaults:
ignoredNames: [".git", ".hg", ".svn", ".DS_Store", "Thumbs.db"]
ignoredNames: [".git", ".svn", ".DS_Store"]
excludeVcsIgnoredPaths: true
disabledPackages: []
themes: ['atom-dark-ui', 'atom-dark-syntax']
@@ -113,7 +113,6 @@ class WorkspaceView extends View
@command 'application:quit', -> ipc.send('command', 'application:quit')
@command 'application:hide', -> ipc.send('command', 'application:hide')
@command 'application:hide-other-applications', -> ipc.send('command', 'application:hide-other-applications')
@command 'application:install-update', -> ipc.send('command', 'application:install-update')
@command 'application:unhide-all-applications', -> ipc.send('command', 'application:unhide-all-applications')
@command 'application:new-window', -> ipc.send('command', 'application:new-window')
@command 'application:new-file', -> ipc.send('command', 'application:new-file')
+11 -14
Ver Arquivo
@@ -13,15 +13,11 @@
}
.lines {
min-width: 100%;
}
z-index: -1;
.cursor {
z-index: 1;
}
&.is-focused .cursors.blink-off .cursor {
visibility: hidden;
.line {
position: absolute;
}
}
.horizontal-scrollbar {
@@ -53,7 +49,6 @@
.scroll-view {
overflow: hidden;
z-index: 0;
}
.scroll-view-content {
@@ -62,9 +57,15 @@
}
.gutter {
padding-left: 0.5em;
padding-right: 0.5em;
.line-number {
position: absolute;
left: 0;
right: 0;
padding: 0;
white-space: nowrap;
padding: 0 .5em;
.icon-right {
padding: 0;
@@ -229,10 +230,6 @@
visibility: visible;
}
.cursor.hidden-cursor {
display: none;
}
.editor .hidden-input {
padding: 0;
border: 0;