Comparar commits
179 Commits
| Autor | SHA1 | Data | |
|---|---|---|---|
| 85b95ebda5 | |||
| c6beefc3c2 | |||
| eb9b3eddd8 | |||
| d33cad1a06 | |||
| 2688e7ff56 | |||
| 3810167feb | |||
| efc336bf8e | |||
| dfcf2af1e1 | |||
| 084dae1775 | |||
| 1270af928f | |||
| 644d0c72c6 | |||
| bbef96d583 | |||
| df373a0024 | |||
| db70a23c1a | |||
| c5f73840f8 | |||
| f95e06cf64 | |||
| 4f62352565 | |||
| 3f4274f724 | |||
| 42c645c98e | |||
| 55af1c1a46 | |||
| 1ad394b1ea | |||
| 7a88376d78 | |||
| 11eae4d5db | |||
| 0b786427f4 | |||
| 4900dc6bcd | |||
| 637410a8c5 | |||
| 1d31a10dc4 | |||
| db61de6cf3 | |||
| c75d36ef93 | |||
| 7bb6cd99eb | |||
| 3dbdaee25c | |||
| b458de0f2d | |||
| 240747ed76 | |||
| 8b5fd64dd4 | |||
| 1c514bdc6b | |||
| f4d9abc789 | |||
| e5197f6f0f | |||
| 8f57246571 | |||
| 7658107e3b | |||
| c33227830e | |||
| 43f2153c86 | |||
| 084d84660a | |||
| 4120b34d22 | |||
| c4a0bce92f | |||
| 858c18114b | |||
| 91f9302fc4 | |||
| 4f3bf04668 | |||
| 11c9417e8d | |||
| db141d9d7f | |||
| 5624596c88 | |||
| cda7ca047c | |||
| ac25ad3985 | |||
| 1bf4e7ab96 | |||
| 49587ace05 | |||
| 54fb06d4b0 | |||
| 8f81b5dc63 | |||
| d5e1649607 | |||
| e2c1f6c0e2 | |||
| 8ec7d1273c | |||
| 7ffc5cc02b | |||
| aac27db552 | |||
| 03acb1c40a | |||
| 5eb332042e | |||
| 66943c4820 | |||
| 4ed9e34893 | |||
| 4f4da78e54 | |||
| 832dfd057e | |||
| dd74280146 | |||
| a7d1a68fb8 | |||
| 6b8b454625 | |||
| 5c5b7df70d | |||
| 7d3abda86f | |||
| 7f824ffbb3 | |||
| 0b7475a4c1 | |||
| cf62d3212c | |||
| b260cbb43a | |||
| 1367f08de8 | |||
| 27b02a7981 | |||
| e62ae02c00 | |||
| 233402dd33 | |||
| 69821b7a6b | |||
| efcffe5205 | |||
| 802e651b6e | |||
| 0e8b951050 | |||
| 8ef97bd78e | |||
| 6749988de1 | |||
| 4a26f8f28b | |||
| a4ee412e96 | |||
| 4f655d7de5 | |||
| 33c02ef3e1 | |||
| aa4749f175 | |||
| 6ace49b0e8 | |||
| 9cf642e910 | |||
| 2990f36595 | |||
| 032fc86a4d | |||
| 868cbb680c | |||
| 98d2aaf10e | |||
| f7dead17c0 | |||
| f3168b2672 | |||
| e8c62b501f | |||
| 6ff2b2a01e | |||
| 960285a270 | |||
| 17cd979299 | |||
| b5846f9755 | |||
| dd39ffdf3b | |||
| 368b871270 | |||
| 9c06b4d344 | |||
| f48241bc5e | |||
| a7b94e1709 | |||
| 3d2dedb49f | |||
| dd5ab8098e | |||
| f5b833c49c | |||
| ba032be402 | |||
| a96a448063 | |||
| faeed9f604 | |||
| 0a8f2422d3 | |||
| 24dbe19a82 | |||
| 7d8901072c | |||
| 848a4e2052 | |||
| e8090b16f3 | |||
| 950964eee3 | |||
| b403f76d81 | |||
| 8f2cdae0eb | |||
| fa4b3c8dea | |||
| e76bbc0f13 | |||
| c9a377d4ac | |||
| c7e308bca0 | |||
| 5193e6e46b | |||
| 66628e8c52 | |||
| bec65cf2ac | |||
| 606b249430 | |||
| 8bc1b7e955 | |||
| 2ceccf5239 | |||
| ad8bd98c9a | |||
| 6c4e138ec0 | |||
| 9ad1021c2d | |||
| c03dec2783 | |||
| 9d92a27ccf | |||
| b652dc8fd8 | |||
| c1929540a3 | |||
| 1601423f30 | |||
| 1de2c14e50 | |||
| c1907054b7 | |||
| 5f524c1181 | |||
| b897603b66 | |||
| 0e5c530006 | |||
| 4a60b5787a | |||
| 88cc69f87a | |||
| 42e91defb9 | |||
| aeb5a84696 | |||
| 228836447c | |||
| 832cc40a7f | |||
| d89b4534f1 | |||
| 725f6f7cf2 | |||
| b760d3e4fc | |||
| 1d634e471e | |||
| babbdbf9e5 | |||
| e9d820e8a8 | |||
| 16e05347a7 | |||
| 2574ee5936 | |||
| 38c25feee0 | |||
| a15bb260c0 | |||
| 6b833043db | |||
| b30a2c9442 | |||
| 3eb99c9391 | |||
| 10636b96bc | |||
| b5ac7c89a3 | |||
| 01298bb470 | |||
| 3bd7bfcbf1 | |||
| 3e94c0be22 | |||
| db0cce6234 | |||
| f3d4cbbd8f | |||
| 81df4ed238 | |||
| 7b756ec3f3 | |||
| 0d95718d1f | |||
| 1da23e8d04 | |||
| 43792d019a | |||
| ec0b4a2dc6 | |||
| 1083136dec |
@@ -12,4 +12,3 @@ debug.log
|
||||
docs/output
|
||||
docs/includes
|
||||
spec/fixtures/evil-files/
|
||||
/apm
|
||||
|
||||
@@ -1,3 +0,0 @@
|
||||
[submodule "vendor/apm"]
|
||||
path = vendor/apm
|
||||
url = https://github.com/atom/apm.git
|
||||
@@ -1 +0,0 @@
|
||||
Copyright 2014 GitHub, Inc.
|
||||
@@ -0,0 +1,20 @@
|
||||
Copyright (c) 2014 GitHub Inc.
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining
|
||||
a copy of this software and associated documentation files (the
|
||||
"Software"), to deal in the Software without restriction, including
|
||||
without limitation the rights to use, copy, modify, merge, publish,
|
||||
distribute, sublicense, and/or sell copies of the Software, and to
|
||||
permit persons to whom the Software is furnished to do so, subject to
|
||||
the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be
|
||||
included in all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
||||
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
+17
-5
@@ -1,8 +1,15 @@
|
||||
# Atom — The hackable editor
|
||||

|
||||
|
||||

|
||||
Atom is a hackable text editor for the 21st century.
|
||||
|
||||
Check out our [guides and API documentation](https://atom.io/docs/latest).
|
||||
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,6 +19,11 @@ Atom will automatically update when a new release is available.
|
||||
|
||||
## Building
|
||||
|
||||
Follow the instructions in the [build docs][building].
|
||||
```sh
|
||||
git clone git@github.com:atom/atom.git
|
||||
cd atom
|
||||
script/build # Creates application at /Applications/Atom.app
|
||||
```
|
||||
|
||||
[building]: https://github.com/atom/atom/blob/master/docs/building-atom.md
|
||||
## Developing
|
||||
Check out the [guides](https://atom.io/docs/latest) and the [API reference](atom.io/docs/api).
|
||||
|
||||
@@ -0,0 +1,2 @@
|
||||
This folder is where [apm](https://github.com/atom/apm) is installed to so that
|
||||
it is bundled with Atom.
|
||||
@@ -0,0 +1,11 @@
|
||||
{
|
||||
"name": "atom-bundled-apm",
|
||||
"description": "Atom's bundled APM",
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/atom/atom.git"
|
||||
},
|
||||
"dependencies": {
|
||||
"atom-package-manager": "0.45.0"
|
||||
}
|
||||
}
|
||||
@@ -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": "git+https://atom-bot:467bac80a0017b96fb5be5cfc686f5e0cc607b10@github.com/atom/grunt-download-atom-shell#v0.6.1",
|
||||
"grunt-download-atom-shell": "~0.7.0",
|
||||
"grunt-lesslint": "0.13.0",
|
||||
"grunt-markdown": "~0.4.0",
|
||||
"grunt-peg": "~1.1.0",
|
||||
|
||||
@@ -17,7 +17,7 @@ module.exports = (grunt) ->
|
||||
|
||||
licenseText = getLicenseText(dependencyLicenses)
|
||||
if mode is 'save'
|
||||
targetPath = path.join(grunt.config.get('atom.appDir'), 'LICENSE')
|
||||
targetPath = path.join(grunt.config.get('atom.appDir'), 'LICENSE.md')
|
||||
fs.writeFileSync(targetPath, licenseText)
|
||||
else
|
||||
console.log licenseText
|
||||
@@ -26,7 +26,7 @@ module.exports = (grunt) ->
|
||||
getLicenseText = (dependencyLicenses) ->
|
||||
{keys} = require 'underscore-plus'
|
||||
text = """
|
||||
Copyright 2014 GitHub, Inc.
|
||||
#{fs.readFileSync('LICENSE.md')}
|
||||
|
||||
This application bundles the following third-party packages in accordance
|
||||
with the following licenses:\n\n
|
||||
|
||||
@@ -29,21 +29,14 @@ module.exports = (gruntObject) ->
|
||||
done = @async()
|
||||
buildDir = grunt.config.get('atom.buildDir')
|
||||
|
||||
createBuildRelease (error, release) ->
|
||||
zipApps buildDir, assets, (error) ->
|
||||
return done(error) if error?
|
||||
|
||||
zipApps buildDir, assets, (error) ->
|
||||
getAtomDraftRelease (error, release) ->
|
||||
return done(error) if error?
|
||||
uploadAssets release, buildDir, assets, (error) ->
|
||||
assetNames = (asset.assetName for asset in assets)
|
||||
deleteExistingAssets release, assetNames, (error) ->
|
||||
return done(error) if error?
|
||||
publishRelease release, (error) ->
|
||||
return done(error) if error?
|
||||
getAtomDraftRelease (error, release) ->
|
||||
return done(error) if error?
|
||||
assetNames = (asset.assetName for asset in assets)
|
||||
deleteExistingAssets release, assetNames, (error) ->
|
||||
return done(error) if error?
|
||||
uploadAssets(release, buildDir, assets, done)
|
||||
uploadAssets(release, buildDir, assets, done)
|
||||
|
||||
logError = (message, error, details) ->
|
||||
grunt.log.error(message)
|
||||
@@ -64,25 +57,6 @@ zipApps = (buildDir, assets, callback) ->
|
||||
tasks.push(zip.bind(this, buildDir, sourceName, assetName))
|
||||
async.parallel(tasks, callback)
|
||||
|
||||
getRelease = (callback) ->
|
||||
options =
|
||||
uri: 'https://api.github.com/repos/atom/atom-master-builds/releases'
|
||||
method: 'GET'
|
||||
headers: defaultHeaders
|
||||
json: true
|
||||
request options, (error, response, releases=[]) ->
|
||||
if error? or response.statusCode isnt 200
|
||||
logError('Fetching releases failed', error, releases)
|
||||
callback(error ? new Error(response.statusCode))
|
||||
else
|
||||
if releases.length > maxReleases
|
||||
deleteRelease(release) for release in releases[maxReleases..]
|
||||
|
||||
for release in releases when release.name is commitSha
|
||||
callback(null, release)
|
||||
return
|
||||
callback()
|
||||
|
||||
getAtomDraftRelease = (callback) ->
|
||||
atomRepo = new GitHub({repo: 'atom/atom', token})
|
||||
atomRepo.getReleases (error, releases=[]) ->
|
||||
@@ -125,35 +99,6 @@ deleteExistingAssets = (release, assetNames, callback) ->
|
||||
tasks.push(deleteAsset.bind(this, asset.url))
|
||||
async.parallel(tasks, callback)
|
||||
|
||||
createBuildRelease = (callback) ->
|
||||
getRelease (error, release) ->
|
||||
if error?
|
||||
callback(error)
|
||||
return
|
||||
|
||||
if release?
|
||||
deleteExistingAssets release, (error) ->
|
||||
callback(error, release)
|
||||
return
|
||||
|
||||
options =
|
||||
uri: 'https://api.github.com/repos/atom/atom-master-builds/releases'
|
||||
method: 'POST'
|
||||
headers: defaultHeaders
|
||||
json:
|
||||
tag_name: "v#{commitSha}"
|
||||
target_commitish: 'master'
|
||||
name: commitSha
|
||||
body: "Build of [atom@#{commitSha.substring(0, 7)}](https://github.com/atom/atom/commits/#{commitSha})"
|
||||
draft: true
|
||||
prerelease: true
|
||||
request options, (error, response, release={}) ->
|
||||
if error? or response.statusCode isnt 201
|
||||
logError('Creating release failed', error, release)
|
||||
callback(error ? new Error(response.statusCode))
|
||||
else
|
||||
callback(null, release)
|
||||
|
||||
uploadAssets = (release, buildDir, assets, callback) ->
|
||||
upload = (release, assetName, assetPath, callback) ->
|
||||
options =
|
||||
@@ -178,17 +123,3 @@ uploadAssets = (release, buildDir, assets, callback) ->
|
||||
assetPath = path.join(buildDir, assetName)
|
||||
tasks.push(upload.bind(this, release, assetName, assetPath))
|
||||
async.parallel(tasks, callback)
|
||||
|
||||
publishRelease = (release, callback) ->
|
||||
options =
|
||||
uri: release.url
|
||||
method: 'POST'
|
||||
headers: defaultHeaders
|
||||
json:
|
||||
draft: false
|
||||
request options, (error, response, body={}) ->
|
||||
if error? or response.statusCode isnt 200
|
||||
logError('Creating release failed', error, body)
|
||||
callback(error ? new Error(response.statusCode))
|
||||
else
|
||||
callback()
|
||||
|
||||
@@ -1,108 +0,0 @@
|
||||
async = require 'async'
|
||||
request = require 'request'
|
||||
|
||||
# Configure and publish all packages in package.json to atom.io
|
||||
#
|
||||
# This task should be run whenever you want to be sure that atom.io contains
|
||||
# all the packages and versions referenced in Atom's package.json file.
|
||||
module.exports = (grunt) ->
|
||||
{spawn} = require('./task-helpers')(grunt)
|
||||
|
||||
baseUrl = "https://atom.io/api/packages"
|
||||
|
||||
packageExists = (packageName, token, callback) ->
|
||||
requestSettings =
|
||||
url: "#{baseUrl}/#{packageName}"
|
||||
json: true
|
||||
headers:
|
||||
authorization: token
|
||||
request.get requestSettings, (error, response, body={}) ->
|
||||
if error?
|
||||
callback(error)
|
||||
else
|
||||
callback(null, response.statusCode is 404)
|
||||
|
||||
createPackage = (packageName, token, callback) ->
|
||||
requestSettings =
|
||||
url: baseUrl
|
||||
json: true
|
||||
headers:
|
||||
authorization: token
|
||||
method: 'POST'
|
||||
body:
|
||||
repository: "atom/#{packageName}"
|
||||
|
||||
request.get requestSettings, (error, response, body={}) ->
|
||||
if error?
|
||||
callback(error)
|
||||
else if response.statusCode isnt 201
|
||||
message = body.message ? body.error ? body
|
||||
callback(new Error("Creating package failed: #{message}"))
|
||||
else
|
||||
callback()
|
||||
|
||||
createPackageVersion = (packageName, tag, token, callback) ->
|
||||
requestSettings =
|
||||
url: "#{baseUrl}/#{packageName}/versions"
|
||||
json: true
|
||||
method: 'POST'
|
||||
headers:
|
||||
authorization: token
|
||||
body:
|
||||
tag: tag
|
||||
|
||||
request.get requestSettings, (error, response, body={}) ->
|
||||
if error?
|
||||
callback(error)
|
||||
else if response.statusCode isnt 201
|
||||
message = body.message ? body.error ? body
|
||||
if message is 'Version exists'
|
||||
callback()
|
||||
else
|
||||
callback(new Error("Creating new version failed: #{message}"))
|
||||
else
|
||||
callback()
|
||||
|
||||
getToken = (callback) ->
|
||||
if token = process.env.ATOM_ACCESS_TOKEN
|
||||
callback(null, token)
|
||||
else
|
||||
spawn {cmd: 'security', args: ['-q', 'find-generic-password', '-ws', 'GitHub API Token']}, (error, result, code) ->
|
||||
token = result.toString() unless error?
|
||||
callback(error, token)
|
||||
|
||||
grunt.registerTask 'publish-packages', 'Publish all bundled packages', ->
|
||||
done = @async()
|
||||
|
||||
getToken (error, token) ->
|
||||
unless token
|
||||
grunt.log.error('Token not found in keychain or ATOM_ACCESS_TOKEN environment variable')
|
||||
done(false)
|
||||
|
||||
{packageDependencies} = grunt.file.readJSON('package.json') ? {}
|
||||
tasks = []
|
||||
for name, version of packageDependencies
|
||||
do (name, version) ->
|
||||
tasks.push (callback) ->
|
||||
grunt.verbose.writeln("Publishing #{name}@#{version}")
|
||||
tag = "v#{version}"
|
||||
packageExists name, token, (error, exists) ->
|
||||
if error?
|
||||
callback(error)
|
||||
return
|
||||
|
||||
if exists
|
||||
createPackage name, token, (error) ->
|
||||
if error?
|
||||
callback(error)
|
||||
else
|
||||
createPackageVersion(name, tag, token, callback)
|
||||
else
|
||||
createPackageVersion(name, tag, token, callback)
|
||||
|
||||
async.waterfall tasks, (error) ->
|
||||
if error?
|
||||
grunt.log.error(error.message)
|
||||
done(false)
|
||||
else
|
||||
done()
|
||||
+1
-1
@@ -1,6 +1,6 @@
|
||||
# Welcome to the Atom API Documentation
|
||||
|
||||

|
||||

|
||||
|
||||
## FAQ
|
||||
|
||||
|
||||
@@ -21,7 +21,7 @@ To begin, press `cmd-shift-P` to bring up the [Command
|
||||
Palette](https://github.com/atom/command-palette). Type "generate package" and
|
||||
select the "Package Generator: Generate Package" command. Now we need to name
|
||||
the package. Try to avoid naming your package with the *atom-* prefix, for
|
||||
example we are going to call this package _ascii-art_.
|
||||
example we are going to call this package _ascii-art_.
|
||||
|
||||
Atom will open a new window with the contents of our new _ascii-art_ package
|
||||
displayed in the Tree View. Because this window is opened **after** the package
|
||||
@@ -152,5 +152,5 @@ ASCII art professional!
|
||||
* [Creating a package guide](creating-a-package.html) for more information
|
||||
on the mechanics of packages
|
||||
|
||||
* [Publishing a package guide](publish-a-package.html) for more information
|
||||
* [Publishing a package guide](publishing-a-package.html) for more information
|
||||
on publishing your package to [atom.io](https://atom.io)
|
||||
|
||||
@@ -0,0 +1,5 @@
|
||||
storage
|
||||
compile-cache
|
||||
dev
|
||||
.npm
|
||||
.node-gyp
|
||||
@@ -134,6 +134,25 @@
|
||||
submenu: [
|
||||
{ label: 'Reload', command: 'window:reload' }
|
||||
{ label: 'Toggle Full Screen', command: 'window:toggle-full-screen' }
|
||||
{
|
||||
label: 'Panes'
|
||||
submenu: [
|
||||
{ label: 'Split Up', command: 'pane:split-up' }
|
||||
{ label: 'Split Down', command: 'pane:split-down' }
|
||||
{ label: 'Split Left', command: 'pane:split-left' }
|
||||
{ label: 'Split Right', command: 'pane:split-right' }
|
||||
{ type: 'separator' }
|
||||
{ label: 'Focus Next Pane', command: 'window:focus-next-pane' }
|
||||
{ label: 'Focus Previous Pane', command: 'window:focus-previous-pane' }
|
||||
{ type: 'separator' }
|
||||
{ label: 'Focus Pane Above', command: 'window:focus-pane-above' }
|
||||
{ label: 'Focus Pane Below', command: 'window:focus-pane-below' }
|
||||
{ label: 'Focus Pane On Left', command: 'window:focus-pane-on-left' }
|
||||
{ label: 'Focus Pane On Right', command: 'window:focus-pane-on-right' }
|
||||
{ type: 'separator' }
|
||||
{ label: 'Close Pane', command: 'pane:close' }
|
||||
]
|
||||
}
|
||||
{
|
||||
label: 'Developer'
|
||||
submenu: [
|
||||
|
||||
@@ -88,6 +88,25 @@
|
||||
submenu: [
|
||||
{ label: '&Reload', command: 'window:reload' }
|
||||
{ label: 'Toggle &Full Screen', command: 'window:toggle-full-screen' }
|
||||
{
|
||||
label: 'Panes'
|
||||
submenu: [
|
||||
{ label: 'Split Up', command: 'pane:split-up' }
|
||||
{ label: 'Split Down', command: 'pane:split-down' }
|
||||
{ label: 'Split Left', command: 'pane:split-left' }
|
||||
{ label: 'Split Right', command: 'pane:split-right' }
|
||||
{ type: 'separator' }
|
||||
{ label: 'Focus Next Pane', command: 'window:focus-next-pane' }
|
||||
{ label: 'Focus Previous Pane', command: 'window:focus-previous-pane' }
|
||||
{ type: 'separator' }
|
||||
{ label: 'Focus Pane Above', command: 'window:focus-pane-above' }
|
||||
{ label: 'Focus Pane Below', command: 'window:focus-pane-below' }
|
||||
{ label: 'Focus Pane On Left', command: 'window:focus-pane-on-left' }
|
||||
{ label: 'Focus Pane On Right', command: 'window:focus-pane-on-right' }
|
||||
{ type: 'separator' }
|
||||
{ label: 'Close pane', command: 'pane:close' }
|
||||
]
|
||||
}
|
||||
{
|
||||
label: 'Developer'
|
||||
submenu: [
|
||||
|
||||
+35
-30
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "atom",
|
||||
"productName": "Atom",
|
||||
"version": "0.91.0",
|
||||
"version": "0.93.0",
|
||||
"description": "A hackable text editor for the 21st Century.",
|
||||
"main": "./src/browser/main.js",
|
||||
"repository": {
|
||||
@@ -11,48 +11,53 @@
|
||||
"bugs": {
|
||||
"url": "https://github.com/atom/atom/issues"
|
||||
},
|
||||
"license": "All Rights Reserved",
|
||||
"atomShellVersion": "0.11.10",
|
||||
"licenses": [
|
||||
{
|
||||
"type": "MIT",
|
||||
"url": "http://github.com/atom/atom/raw/master/LICENSE.md"
|
||||
}
|
||||
],
|
||||
"atomShellVersion": "0.12.0",
|
||||
"dependencies": {
|
||||
"async": "0.2.6",
|
||||
"atom-keymap": "^0.18.0",
|
||||
"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.x",
|
||||
"delegato": "^1",
|
||||
"emissary": "^1.2.1",
|
||||
"first-mate": "^1.5.2",
|
||||
"first-mate": "^1.5.3",
|
||||
"fs-plus": "^2.2.2",
|
||||
"fstream": "0.1.24",
|
||||
"fuzzaldrin": "~1.1",
|
||||
"git-utils": "^1.2.2",
|
||||
"grim": "0.9.0",
|
||||
"fuzzaldrin": "^1.1",
|
||||
"git-utils": "^1.3",
|
||||
"grim": "0.10.0",
|
||||
"guid": "0.0.10",
|
||||
"jasmine-tagged": "^1.1.1",
|
||||
"less-cache": "0.12.0",
|
||||
"mixto": "1.x",
|
||||
"mixto": "^1",
|
||||
"mkdirp": "0.3.5",
|
||||
"nslog": "0.5.0",
|
||||
"oniguruma": "^1.0.6",
|
||||
"optimist": "0.4.0",
|
||||
"pathwatcher": "^1.2.1",
|
||||
"property-accessors": "1.x",
|
||||
"property-accessors": "^1",
|
||||
"q": "^1.0.1",
|
||||
"random-words": "0.0.1",
|
||||
"react": "^0.10.0",
|
||||
"reactionary": "^0.8.0",
|
||||
"runas": "0.5.x",
|
||||
"runas": "^0.5",
|
||||
"scandal": "0.15.2",
|
||||
"scoped-property-store": "^0.8.0",
|
||||
"scoped-property-store": "^0.9.0",
|
||||
"scrollbar-style": "^0.1.0",
|
||||
"season": "^1.0.2",
|
||||
"semver": "1.1.4",
|
||||
"serializable": "1.x",
|
||||
"serializable": "^1",
|
||||
"space-pen": "3.1.1",
|
||||
"temp": "0.5.0",
|
||||
"text-buffer": "^2.1.0",
|
||||
"theorist": "1.x",
|
||||
"text-buffer": "^2.2.0",
|
||||
"theorist": "^1",
|
||||
"underscore-plus": "^1.2.1",
|
||||
"vm-compatibility-layer": "0.1.0"
|
||||
},
|
||||
@@ -76,41 +81,41 @@
|
||||
"dev-live-reload": "0.30.0",
|
||||
"exception-reporting": "0.17.0",
|
||||
"feedback": "0.30.0",
|
||||
"find-and-replace": "0.99.0",
|
||||
"find-and-replace": "0.100.0",
|
||||
"fuzzy-finder": "0.50.0",
|
||||
"git-diff": "0.28.0",
|
||||
"go-to-line": "0.19.0",
|
||||
"grammar-selector": "0.24.0",
|
||||
"grammar-selector": "0.26.0",
|
||||
"image-view": "0.33.0",
|
||||
"keybinding-resolver": "0.17.0",
|
||||
"link": "0.22.0",
|
||||
"markdown-preview": "0.64.0",
|
||||
"markdown-preview": "0.69.0",
|
||||
"metrics": "0.32.0",
|
||||
"open-on-github": "0.28.0",
|
||||
"package-generator": "0.30.0",
|
||||
"release-notes": "0.27.0",
|
||||
"settings-view": "0.110.0",
|
||||
"snippets": "0.41.0",
|
||||
"release-notes": "0.28.0",
|
||||
"settings-view": "0.114.0",
|
||||
"snippets": "0.43.0",
|
||||
"spell-check": "0.34.0",
|
||||
"status-bar": "0.40.0",
|
||||
"styleguide": "0.29.0",
|
||||
"symbols-view": "0.49.0",
|
||||
"tabs": "0.37.0",
|
||||
"symbols-view": "0.50.0",
|
||||
"tabs": "0.39.0",
|
||||
"timecop": "0.18.0",
|
||||
"tree-view": "0.90.0",
|
||||
"tree-view": "0.92.0",
|
||||
"update-package-dependencies": "0.6.0",
|
||||
"welcome": "0.12.0",
|
||||
"whitespace": "0.22.0",
|
||||
"wrap-guide": "0.18.0",
|
||||
"language-c": "0.14.0",
|
||||
"language-c": "0.15.0",
|
||||
"language-coffee-script": "0.22.0",
|
||||
"language-css": "0.16.0",
|
||||
"language-gfm": "0.31.0",
|
||||
"language-gfm": "0.33.0",
|
||||
"language-git": "0.9.0",
|
||||
"language-go": "0.9.0",
|
||||
"language-go": "0.10.0",
|
||||
"language-html": "0.19.0",
|
||||
"language-hyperlink": "0.9.0",
|
||||
"language-java": "0.9.0",
|
||||
"language-java": "0.10.0",
|
||||
"language-javascript": "0.24.0",
|
||||
"language-json": "0.8.0",
|
||||
"language-less": "0.8.0",
|
||||
@@ -120,7 +125,7 @@
|
||||
"language-php": "0.14.0",
|
||||
"language-property-list": "0.7.0",
|
||||
"language-python": "0.15.0",
|
||||
"language-ruby": "0.22.0",
|
||||
"language-ruby": "0.23.0",
|
||||
"language-ruby-on-rails": "0.12.0",
|
||||
"language-sass": "0.10.0",
|
||||
"language-shellscript": "0.8.0",
|
||||
|
||||
Arquivo binário não exibido.
|
Antes Largura: | Altura: | Tamanho: 191 KiB Depois Largura: | Altura: | Tamanho: 284 KiB |
+267
-89
Diferenças do arquivo suprimidas por serem muito extensas
Carregar Diff
Arquivo binário não exibido.
Arquivo binário não exibido.
+1
-5
@@ -25,7 +25,6 @@ function executeCommands(commands, done, index) {
|
||||
done(null);
|
||||
}
|
||||
|
||||
var apmVendorPath = path.resolve(__dirname, '..', 'vendor', 'apm');
|
||||
var apmInstallPath = path.resolve(__dirname, '..', 'apm');
|
||||
if (!fs.existsSync(apmInstallPath))
|
||||
fs.mkdirSync(apmInstallPath);
|
||||
@@ -42,11 +41,8 @@ var packagesToDedupe = ['fs-plus', 'humanize-plus', 'oniguruma', 'roaster', 'sea
|
||||
var echoNewLine = process.platform == 'win32' ? 'echo.' : 'echo';
|
||||
|
||||
var commands = [
|
||||
'git submodule --quiet sync',
|
||||
'git submodule --quiet update --recursive --init',
|
||||
{command: 'npm' + npmFlags + 'install --quiet', options: {cwd: path.resolve(__dirname, '..', 'build'), ignoreStdout: true}},
|
||||
{command: npmPath + npmFlags + 'install --quiet', options: {cwd: apmVendorPath, ignoreStdout: true}},
|
||||
{command: npmPath + npmFlags + 'install --quiet ' + apmVendorPath, options: {cwd: apmInstallPath, ignoreStdout: true}},
|
||||
{command: npmPath + npmFlags + 'install --quiet', options: {cwd: apmInstallPath, ignoreStdout: true}},
|
||||
echoNewLine,
|
||||
apmPath + ' clean ' + apmFlags,
|
||||
apmPath + ' install --quiet ' + apmFlags,
|
||||
|
||||
@@ -18,7 +18,6 @@ var commands = [
|
||||
[__dirname, '..', 'node_modules'],
|
||||
[__dirname, '..', 'build', 'node_modules'],
|
||||
[__dirname, '..', 'apm', 'node_modules'],
|
||||
[__dirname, '..', 'vendor', 'apm', 'node_modules'],
|
||||
[__dirname, '..', 'atom-shell'],
|
||||
[home, '.atom', '.node-gyp'],
|
||||
[home, '.atom', 'storage'],
|
||||
|
||||
+27
-24
@@ -113,18 +113,21 @@ describe "the `atom` global", ->
|
||||
promise
|
||||
|
||||
it "triggers the activation event on all handlers registered during activation", ->
|
||||
atom.workspaceView.openSync()
|
||||
editorView = atom.workspaceView.getActiveView()
|
||||
eventHandler = jasmine.createSpy("activation-event")
|
||||
editorView.command 'activation-event', eventHandler
|
||||
editorView.trigger 'activation-event'
|
||||
expect(mainModule.activate.callCount).toBe 1
|
||||
expect(mainModule.activationEventCallCount).toBe 1
|
||||
expect(eventHandler.callCount).toBe 1
|
||||
editorView.trigger 'activation-event'
|
||||
expect(mainModule.activationEventCallCount).toBe 2
|
||||
expect(eventHandler.callCount).toBe 2
|
||||
expect(mainModule.activate.callCount).toBe 1
|
||||
waitsForPromise ->
|
||||
atom.workspaceView.open()
|
||||
|
||||
runs ->
|
||||
editorView = atom.workspaceView.getActiveView()
|
||||
eventHandler = jasmine.createSpy("activation-event")
|
||||
editorView.command 'activation-event', eventHandler
|
||||
editorView.trigger 'activation-event'
|
||||
expect(mainModule.activate.callCount).toBe 1
|
||||
expect(mainModule.activationEventCallCount).toBe 1
|
||||
expect(eventHandler.callCount).toBe 1
|
||||
editorView.trigger 'activation-event'
|
||||
expect(mainModule.activationEventCallCount).toBe 2
|
||||
expect(eventHandler.callCount).toBe 2
|
||||
expect(mainModule.activate.callCount).toBe 1
|
||||
|
||||
it "activates the package immediately when the events are empty", ->
|
||||
mainModule = require './fixtures/packages/package-with-empty-activation-events/index'
|
||||
@@ -170,28 +173,28 @@ describe "the `atom` global", ->
|
||||
element2 = $$ -> @div class: 'test-2'
|
||||
element3 = $$ -> @div class: 'test-3'
|
||||
|
||||
expect(atom.keymaps.keyBindingsForKeystrokeMatchingElement('ctrl-z', element1)).toHaveLength 0
|
||||
expect(atom.keymaps.keyBindingsForKeystrokeMatchingElement('ctrl-z', element2)).toHaveLength 0
|
||||
expect(atom.keymaps.keyBindingsForKeystrokeMatchingElement('ctrl-z', element3)).toHaveLength 0
|
||||
expect(atom.keymaps.findKeyBindings(keystrokes:'ctrl-z', target:element1[0])).toHaveLength 0
|
||||
expect(atom.keymaps.findKeyBindings(keystrokes:'ctrl-z', target:element2[0])).toHaveLength 0
|
||||
expect(atom.keymaps.findKeyBindings(keystrokes:'ctrl-z', target:element3[0])).toHaveLength 0
|
||||
|
||||
atom.packages.activatePackage("package-with-keymaps")
|
||||
|
||||
expect(atom.keymaps.keyBindingsForKeystrokeMatchingElement('ctrl-z', element1)[0].command).toBe "test-1"
|
||||
expect(atom.keymaps.keyBindingsForKeystrokeMatchingElement('ctrl-z', element2)[0].command).toBe "test-2"
|
||||
expect(atom.keymaps.keyBindingsForKeystrokeMatchingElement('ctrl-z', element3)).toHaveLength 0
|
||||
expect(atom.keymaps.findKeyBindings(keystrokes:'ctrl-z', target:element1[0])[0].command).toBe "test-1"
|
||||
expect(atom.keymaps.findKeyBindings(keystrokes:'ctrl-z', target:element2[0])[0].command).toBe "test-2"
|
||||
expect(atom.keymaps.findKeyBindings(keystrokes:'ctrl-z', target:element3[0])).toHaveLength 0
|
||||
|
||||
describe "when the metadata contains a 'keymaps' manifest", ->
|
||||
it "loads only the keymaps specified by the manifest, in the specified order", ->
|
||||
element1 = $$ -> @div class: 'test-1'
|
||||
element3 = $$ -> @div class: 'test-3'
|
||||
|
||||
expect(atom.keymaps.keyBindingsForKeystrokeMatchingElement('ctrl-z', element1)).toHaveLength 0
|
||||
expect(atom.keymaps.findKeyBindings(keystrokes:'ctrl-z', target:element1[0])).toHaveLength 0
|
||||
|
||||
atom.packages.activatePackage("package-with-keymaps-manifest")
|
||||
|
||||
expect(atom.keymaps.keyBindingsForKeystrokeMatchingElement('ctrl-z', element1)[0].command).toBe 'keymap-1'
|
||||
expect(atom.keymaps.keyBindingsForKeystrokeMatchingElement('ctrl-n', element1)[0].command).toBe 'keymap-2'
|
||||
expect(atom.keymaps.keyBindingsForKeystrokeMatchingElement('ctrl-y', element3)).toHaveLength 0
|
||||
expect(atom.keymaps.findKeyBindings(keystrokes:'ctrl-z', target:element1[0])[0].command).toBe 'keymap-1'
|
||||
expect(atom.keymaps.findKeyBindings(keystrokes:'ctrl-n', target:element1[0])[0].command).toBe 'keymap-2'
|
||||
expect(atom.keymaps.findKeyBindings(keystrokes:'ctrl-y', target:element3[0])).toHaveLength 0
|
||||
|
||||
describe "menu loading", ->
|
||||
beforeEach ->
|
||||
@@ -377,8 +380,8 @@ describe "the `atom` global", ->
|
||||
|
||||
runs ->
|
||||
atom.packages.deactivatePackage('package-with-keymaps')
|
||||
expect(atom.keymaps.keyBindingsForKeystrokeMatchingElement('ctrl-z', $$ -> @div class: 'test-1')).toHaveLength 0
|
||||
expect(atom.keymaps.keyBindingsForKeystrokeMatchingElement('ctrl-z', $$ -> @div class: 'test-2')).toHaveLength 0
|
||||
expect(atom.keymaps.findKeyBindings(keystrokes:'ctrl-z', target:$$ -> @div class: 'test-1'[0])).toHaveLength 0
|
||||
expect(atom.keymaps.findKeyBindings(keystrokes:'ctrl-z', target:$$ -> @div class: 'test-2'[0])).toHaveLength 0
|
||||
|
||||
it "removes the package's stylesheets", ->
|
||||
waitsForPromise ->
|
||||
|
||||
@@ -21,7 +21,7 @@ describe "DisplayBuffer", ->
|
||||
describe "::copy()", ->
|
||||
it "creates a new DisplayBuffer with the same initial state", ->
|
||||
marker1 = displayBuffer.markBufferRange([[1, 2], [3, 4]], id: 1)
|
||||
marker2 = displayBuffer.markBufferRange([[2, 3], [4, 5]], isReversed: true, id: 2)
|
||||
marker2 = displayBuffer.markBufferRange([[2, 3], [4, 5]], reversed: true, id: 2)
|
||||
marker3 = displayBuffer.markBufferPosition([5, 6], id: 3)
|
||||
displayBuffer.createFold(3, 5)
|
||||
|
||||
@@ -979,6 +979,7 @@ describe "DisplayBuffer", ->
|
||||
describe "::setScrollLeft", ->
|
||||
beforeEach ->
|
||||
displayBuffer.manageScrollPosition = true
|
||||
displayBuffer.setLineHeight(10)
|
||||
displayBuffer.setDefaultCharWidth(10)
|
||||
|
||||
it "disallows negative values", ->
|
||||
@@ -1001,6 +1002,7 @@ describe "DisplayBuffer", ->
|
||||
displayBuffer.manageScrollPosition = true
|
||||
displayBuffer.setLineHeight(10)
|
||||
displayBuffer.setDefaultCharWidth(10)
|
||||
displayBuffer.setHorizontalScrollbarHeight(0)
|
||||
|
||||
displayBuffer.setHeight(50)
|
||||
displayBuffer.setWidth(50)
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
{extend, flatten, toArray} = require 'underscore-plus'
|
||||
{extend, flatten, toArray, last} = require 'underscore-plus'
|
||||
ReactEditorView = require '../src/react-editor-view'
|
||||
nbsp = String.fromCharCode(160)
|
||||
|
||||
describe "EditorComponent", ->
|
||||
[editor, wrapperView, component, node, verticalScrollbarNode, horizontalScrollbarNode] = []
|
||||
[contentNode, editor, wrapperView, component, node, verticalScrollbarNode, horizontalScrollbarNode] = []
|
||||
[lineHeightInPixels, charWidth, delayAnimationFrames, nextAnimationFrame] = []
|
||||
|
||||
beforeEach ->
|
||||
@@ -22,7 +22,13 @@ describe "EditorComponent", ->
|
||||
else
|
||||
fn()
|
||||
|
||||
editor = atom.project.openSync('sample.js')
|
||||
waitsForPromise ->
|
||||
atom.project.open('sample.js').then (o) -> editor = o
|
||||
|
||||
runs ->
|
||||
contentNode = document.querySelector('#jasmine-content')
|
||||
contentNode.style.width = '1000px'
|
||||
|
||||
wrapperView = new ReactEditorView(editor)
|
||||
wrapperView.attachToDom()
|
||||
{component} = wrapperView
|
||||
@@ -35,6 +41,9 @@ describe "EditorComponent", ->
|
||||
verticalScrollbarNode = node.querySelector('.vertical-scrollbar')
|
||||
horizontalScrollbarNode = node.querySelector('.horizontal-scrollbar')
|
||||
|
||||
afterEach ->
|
||||
contentNode.style.width = ''
|
||||
|
||||
describe "line rendering", ->
|
||||
it "renders only the currently-visible lines", ->
|
||||
node.style.height = 4.5 * lineHeightInPixels + 'px'
|
||||
@@ -185,6 +194,20 @@ describe "EditorComponent", ->
|
||||
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", ->
|
||||
editor.getBuffer().setText([1..10].join('\n'))
|
||||
lineNumberNodes = toArray(node.querySelectorAll('.line-number'))
|
||||
|
||||
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]])
|
||||
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", ->
|
||||
cursor1 = editor.getCursor()
|
||||
@@ -526,6 +549,110 @@ describe "EditorComponent", ->
|
||||
|
||||
expect(editor.getScrollLeft()).toBe 100
|
||||
|
||||
it "does not obscure the last line with the horizontal scrollbar", ->
|
||||
node.style.height = 4.5 * lineHeightInPixels + 'px'
|
||||
node.style.width = 10 * charWidth + 'px'
|
||||
component.measureHeightAndWidth()
|
||||
editor.setScrollBottom(editor.getScrollHeight())
|
||||
lastLineNode = last(node.querySelectorAll('.line'))
|
||||
bottomOfLastLine = lastLineNode.getBoundingClientRect().bottom
|
||||
topOfHorizontalScrollbar = horizontalScrollbarNode.getBoundingClientRect().top
|
||||
expect(bottomOfLastLine).toBe topOfHorizontalScrollbar
|
||||
|
||||
# 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
|
||||
|
||||
it "does not obscure the last character of the longest line with the vertical scrollbar", ->
|
||||
node.style.height = 7 * lineHeightInPixels + 'px'
|
||||
node.style.width = 10 * charWidth + 'px'
|
||||
component.measureHeightAndWidth()
|
||||
|
||||
editor.setScrollLeft(Infinity)
|
||||
|
||||
lineNodes = node.querySelectorAll('.line')
|
||||
rightOfLongestLine = lineNodes[6].getBoundingClientRect().right
|
||||
leftOfVerticalScrollbar = verticalScrollbarNode.getBoundingClientRect().left
|
||||
|
||||
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'
|
||||
expect(horizontalScrollbarNode.style.display).toBe 'none'
|
||||
|
||||
node.style.height = 4.5 * lineHeightInPixels + 'px'
|
||||
node.style.width = '1000px'
|
||||
component.measureHeightAndWidth()
|
||||
|
||||
expect(verticalScrollbarNode.style.display).toBe ''
|
||||
expect(horizontalScrollbarNode.style.display).toBe 'none'
|
||||
|
||||
node.style.width = 10 * charWidth + 'px'
|
||||
component.measureHeightAndWidth()
|
||||
|
||||
expect(verticalScrollbarNode.style.display).toBe ''
|
||||
expect(horizontalScrollbarNode.style.display).toBe ''
|
||||
|
||||
node.style.height = 20 * lineHeightInPixels + 'px'
|
||||
component.measureHeightAndWidth()
|
||||
|
||||
expect(verticalScrollbarNode.style.display).toBe 'none'
|
||||
expect(horizontalScrollbarNode.style.display).toBe ''
|
||||
|
||||
it "makes the dummy scrollbar divs only as tall/wide as the actual scrollbars", ->
|
||||
node.style.height = 4 * lineHeightInPixels + 'px'
|
||||
node.style.width = 10 * charWidth + 'px'
|
||||
component.measureHeightAndWidth()
|
||||
|
||||
atom.themes.applyStylesheet "test", """
|
||||
::-webkit-scrollbar {
|
||||
width: 8px;
|
||||
height: 8px;
|
||||
}
|
||||
"""
|
||||
|
||||
scrollbarCornerNode = node.querySelector('.scrollbar-corner')
|
||||
expect(verticalScrollbarNode.offsetWidth).toBe 8
|
||||
expect(horizontalScrollbarNode.offsetHeight).toBe 8
|
||||
expect(scrollbarCornerNode.offsetWidth).toBe 8
|
||||
expect(scrollbarCornerNode.offsetHeight).toBe 8
|
||||
|
||||
it "assigns the bottom/right of the scrollbars to the width of the opposite scrollbar if it is visible", ->
|
||||
scrollbarCornerNode = node.querySelector('.scrollbar-corner')
|
||||
|
||||
expect(verticalScrollbarNode.style.bottom).toBe ''
|
||||
expect(horizontalScrollbarNode.style.right).toBe ''
|
||||
|
||||
node.style.height = 4.5 * lineHeightInPixels + 'px'
|
||||
node.style.width = '1000px'
|
||||
component.measureHeightAndWidth()
|
||||
expect(verticalScrollbarNode.style.bottom).toBe ''
|
||||
expect(horizontalScrollbarNode.style.right).toBe verticalScrollbarNode.offsetWidth + 'px'
|
||||
expect(scrollbarCornerNode.style.display).toBe 'none'
|
||||
|
||||
node.style.width = 10 * charWidth + 'px'
|
||||
component.measureHeightAndWidth()
|
||||
expect(verticalScrollbarNode.style.bottom).toBe horizontalScrollbarNode.offsetHeight + 'px'
|
||||
expect(horizontalScrollbarNode.style.right).toBe verticalScrollbarNode.offsetWidth + 'px'
|
||||
expect(scrollbarCornerNode.style.display).toBe ''
|
||||
|
||||
node.style.height = 20 * lineHeightInPixels + 'px'
|
||||
component.measureHeightAndWidth()
|
||||
expect(verticalScrollbarNode.style.bottom).toBe horizontalScrollbarNode.offsetHeight + 'px'
|
||||
expect(horizontalScrollbarNode.style.right).toBe ''
|
||||
expect(scrollbarCornerNode.style.display).toBe 'none'
|
||||
|
||||
it "accounts for the width of the gutter in the scrollWidth of the horizontal scrollbar", ->
|
||||
gutterNode = node.querySelector('.gutter')
|
||||
node.style.width = 10 * charWidth + 'px'
|
||||
component.measureHeightAndWidth()
|
||||
|
||||
expect(horizontalScrollbarNode.scrollWidth).toBe gutterNode.offsetWidth + editor.getScrollWidth()
|
||||
|
||||
describe "when a mousewheel event occurs on the editor", ->
|
||||
it "updates the horizontal or vertical scrollbar depending on which delta is greater (x or y)", ->
|
||||
node.style.height = 4.5 * lineHeightInPixels + 'px'
|
||||
|
||||
+117
-56
@@ -7,9 +7,12 @@ describe "Editor", ->
|
||||
buffer.setText(buffer.getText().replace(/[ ]{2}/g, "\t"))
|
||||
|
||||
beforeEach ->
|
||||
editor = atom.project.openSync('sample.js', autoIndent: false)
|
||||
buffer = editor.buffer
|
||||
lineLengths = buffer.getLines().map (line) -> line.length
|
||||
waitsForPromise ->
|
||||
atom.project.open('sample.js', autoIndent: false).then (o) -> editor = o
|
||||
|
||||
runs ->
|
||||
buffer = editor.buffer
|
||||
lineLengths = buffer.getLines().map (line) -> line.length
|
||||
|
||||
waitsForPromise ->
|
||||
atom.packages.activatePackage('language-javascript')
|
||||
@@ -17,7 +20,7 @@ describe "Editor", ->
|
||||
describe "when the editor is deserialized", ->
|
||||
it "restores selections and folds based on markers in the buffer", ->
|
||||
editor.setSelectedBufferRange([[1, 2], [3, 4]])
|
||||
editor.addSelectionForBufferRange([[5, 6], [7, 5]], isReversed: true)
|
||||
editor.addSelectionForBufferRange([[5, 6], [7, 5]], reversed: true)
|
||||
editor.foldBufferRow(4)
|
||||
expect(editor.isFoldedAtBufferRow(4)).toBeTruthy()
|
||||
|
||||
@@ -31,15 +34,33 @@ describe "Editor", ->
|
||||
editor2.destroy()
|
||||
|
||||
describe "when the editor is constructed with an initialLine option", ->
|
||||
it "and positions the cursor on the specified line", ->
|
||||
editor = atom.project.openSync('sample.js', initialLine: 2)
|
||||
buffer = editor.buffer
|
||||
expect(editor.getCursor().getBufferPosition().row).toEqual 2
|
||||
it "positions the cursor on the specified line", ->
|
||||
editor = null
|
||||
|
||||
waitsForPromise ->
|
||||
atom.workspace.open('sample.less', initialLine: 5).then (o) -> editor = o
|
||||
|
||||
runs ->
|
||||
buffer = editor.buffer
|
||||
expect(editor.getCursor().getBufferPosition().row).toEqual 5
|
||||
expect(editor.getCursor().getBufferPosition().column).toEqual 0
|
||||
|
||||
describe "when the editor is constructed with an initialColumn option", ->
|
||||
it "positions the cursor on the specified column", ->
|
||||
editor = null
|
||||
|
||||
waitsForPromise ->
|
||||
atom.workspace.open('sample.less', initialColumn: 8).then (o) -> editor = o
|
||||
|
||||
runs ->
|
||||
buffer = editor.buffer
|
||||
expect(editor.getCursor().getBufferPosition().row).toEqual 0
|
||||
expect(editor.getCursor().getBufferPosition().column).toEqual 8
|
||||
|
||||
describe ".copy()", ->
|
||||
it "returns a different edit session with the same initial state", ->
|
||||
editor.setSelectedBufferRange([[1, 2], [3, 4]])
|
||||
editor.addSelectionForBufferRange([[5, 6], [7, 8]], isReversed: true)
|
||||
editor.addSelectionForBufferRange([[5, 6], [7, 8]], reversed: true)
|
||||
editor.foldBufferRow(4)
|
||||
expect(editor.isFoldedAtBufferRow(4)).toBeTruthy()
|
||||
|
||||
@@ -57,21 +78,31 @@ describe "Editor", ->
|
||||
|
||||
describe "config defaults", ->
|
||||
it "uses the `editor.tabLength`, `editor.softWrap`, and `editor.softTabs` config values", ->
|
||||
editor1 = null
|
||||
editor2 = null
|
||||
atom.config.set('editor.tabLength', 4)
|
||||
atom.config.set('editor.softWrap', true)
|
||||
atom.config.set('editor.softTabs', false)
|
||||
editor1 = atom.project.openSync('a')
|
||||
expect(editor1.getTabLength()).toBe 4
|
||||
expect(editor1.getSoftWrap()).toBe true
|
||||
expect(editor1.getSoftTabs()).toBe false
|
||||
|
||||
atom.config.set('editor.tabLength', 100)
|
||||
atom.config.set('editor.softWrap', false)
|
||||
atom.config.set('editor.softTabs', true)
|
||||
editor2 = atom.project.openSync('b')
|
||||
expect(editor2.getTabLength()).toBe 100
|
||||
expect(editor2.getSoftWrap()).toBe false
|
||||
expect(editor2.getSoftTabs()).toBe true
|
||||
waitsForPromise ->
|
||||
atom.workspace.open('a').then (o) -> editor1 = o
|
||||
|
||||
runs ->
|
||||
expect(editor1.getTabLength()).toBe 4
|
||||
expect(editor1.getSoftWrap()).toBe true
|
||||
expect(editor1.getSoftTabs()).toBe false
|
||||
|
||||
atom.config.set('editor.tabLength', 100)
|
||||
atom.config.set('editor.softWrap', false)
|
||||
atom.config.set('editor.softTabs', true)
|
||||
|
||||
waitsForPromise ->
|
||||
atom.workspace.open('b').then (o) -> editor2 = o
|
||||
|
||||
runs ->
|
||||
expect(editor2.getTabLength()).toBe 100
|
||||
expect(editor2.getSoftWrap()).toBe false
|
||||
expect(editor2.getSoftTabs()).toBe true
|
||||
|
||||
describe "title", ->
|
||||
describe ".getTitle()", ->
|
||||
@@ -667,6 +698,7 @@ describe "Editor", ->
|
||||
editor.setHorizontalScrollMargin(2)
|
||||
editor.setLineHeight(10)
|
||||
editor.setDefaultCharWidth(10)
|
||||
editor.setHorizontalScrollbarHeight(0)
|
||||
editor.setHeight(5.5 * 10)
|
||||
editor.setWidth(5.5 * 10)
|
||||
|
||||
@@ -759,7 +791,7 @@ describe "Editor", ->
|
||||
expect(selection1.isReversed()).toBeFalsy()
|
||||
|
||||
it "merges selections when they intersect when moving up", ->
|
||||
editor.setSelectedBufferRanges([[[0,9], [0,13]], [[1,10], [1,20]]], isReversed: true)
|
||||
editor.setSelectedBufferRanges([[[0,9], [0,13]], [[1,10], [1,20]]], reversed: true)
|
||||
[selection1, selection2] = editor.getSelections()
|
||||
|
||||
editor.selectUp()
|
||||
@@ -770,7 +802,7 @@ describe "Editor", ->
|
||||
expect(selection1.isReversed()).toBeTruthy()
|
||||
|
||||
it "merges selections when they intersect when moving left", ->
|
||||
editor.setSelectedBufferRanges([[[0,9], [0,13]], [[0,14], [1,20]]], isReversed: true)
|
||||
editor.setSelectedBufferRanges([[[0,9], [0,13]], [[0,14], [1,20]]], reversed: true)
|
||||
[selection1, selection2] = editor.getSelections()
|
||||
|
||||
editor.selectLeft()
|
||||
@@ -1107,6 +1139,7 @@ describe "Editor", ->
|
||||
editor.setDefaultCharWidth(10)
|
||||
editor.setHeight(50)
|
||||
editor.setWidth(50)
|
||||
editor.setHorizontalScrollbarHeight(0)
|
||||
expect(editor.getScrollTop()).toBe 0
|
||||
|
||||
editor.setSelectedBufferRange([[5, 6], [6, 8]], autoscroll: true)
|
||||
@@ -1339,10 +1372,14 @@ describe "Editor", ->
|
||||
expect(selection.isEmpty()).toBeTruthy()
|
||||
|
||||
it "does not share selections between different edit sessions for the same buffer", ->
|
||||
editor2 = atom.project.openSync('sample.js')
|
||||
editor.setSelectedBufferRanges([[[1, 2], [3, 4]], [[5, 6], [7, 8]]])
|
||||
editor2.setSelectedBufferRanges([[[8, 7], [6, 5]], [[4, 3], [2, 1]]])
|
||||
expect(editor2.getSelectedBufferRanges()).not.toEqual editor.getSelectedBufferRanges()
|
||||
editor2 = null
|
||||
waitsForPromise ->
|
||||
atom.project.open('sample.js').then (o) -> editor2 = o
|
||||
|
||||
runs ->
|
||||
editor.setSelectedBufferRanges([[[1, 2], [3, 4]], [[5, 6], [7, 8]]])
|
||||
editor2.setSelectedBufferRanges([[[8, 7], [6, 5]], [[4, 3], [2, 1]]])
|
||||
expect(editor2.getSelectedBufferRanges()).not.toEqual editor.getSelectedBufferRanges()
|
||||
|
||||
describe "buffer manipulation", ->
|
||||
describe ".insertText(text)", ->
|
||||
@@ -2225,10 +2262,14 @@ describe "Editor", ->
|
||||
|
||||
it "does not explode if the current language mode has no comment regex", ->
|
||||
editor.destroy()
|
||||
editor = atom.project.openSync(null, autoIndent: false)
|
||||
editor.setSelectedBufferRange([[4, 5], [4, 5]])
|
||||
editor.toggleLineCommentsInSelection()
|
||||
expect(buffer.lineForRow(4)).toBe " while(items.length > 0) {"
|
||||
|
||||
waitsForPromise ->
|
||||
atom.workspace.open(null, autoIndent: false).then (o) -> editor = o
|
||||
|
||||
runs ->
|
||||
editor.setSelectedBufferRange([[4, 5], [4, 5]])
|
||||
editor.toggleLineCommentsInSelection()
|
||||
expect(buffer.lineForRow(4)).toBe " while(items.length > 0) {"
|
||||
|
||||
it "uncomments when the line lacks the trailing whitespace in the comment regex", ->
|
||||
editor.setCursorBufferPosition([10, 0])
|
||||
@@ -2547,14 +2588,17 @@ describe "Editor", ->
|
||||
|
||||
describe "soft-tabs detection", ->
|
||||
it "assigns soft / hard tabs based on the contents of the buffer, or uses the default if unknown", ->
|
||||
editor = atom.project.openSync('sample.js', softTabs: false)
|
||||
expect(editor.getSoftTabs()).toBeTruthy()
|
||||
waitsForPromise ->
|
||||
atom.workspace.open('sample.js', softTabs: false).then (editor) ->
|
||||
expect(editor.getSoftTabs()).toBeTruthy()
|
||||
|
||||
editor = atom.project.openSync('sample-with-tabs.coffee', softTabs: true)
|
||||
expect(editor.getSoftTabs()).toBeFalsy()
|
||||
waitsForPromise ->
|
||||
atom.workspace.open('sample-with-tabs.coffee', softTabs: true).then (editor) ->
|
||||
expect(editor.getSoftTabs()).toBeFalsy()
|
||||
|
||||
editor = atom.project.openSync(null, softTabs: false)
|
||||
expect(editor.getSoftTabs()).toBeFalsy()
|
||||
waitsForPromise ->
|
||||
atom.workspace.open(null, softTabs: false).then (editor) ->
|
||||
expect(editor.getSoftTabs()).toBeFalsy()
|
||||
|
||||
describe ".indentLevelForLine(line)", ->
|
||||
it "returns the indent level when the line has only leading whitespace", ->
|
||||
@@ -2578,16 +2622,21 @@ describe "Editor", ->
|
||||
|
||||
describe "when a better-matched grammar is added to syntax", ->
|
||||
it "switches to the better-matched grammar and re-tokenizes the buffer", ->
|
||||
editor.destroy()
|
||||
|
||||
jsGrammar = atom.syntax.selectGrammar('a.js')
|
||||
atom.syntax.removeGrammar(jsGrammar)
|
||||
|
||||
editor2 = atom.project.openSync('sample.js', autoIndent: false)
|
||||
expect(editor2.getGrammar()).toBe atom.syntax.nullGrammar
|
||||
expect(editor2.lineForScreenRow(0).tokens.length).toBe 1
|
||||
waitsForPromise ->
|
||||
atom.workspace.open('sample.js', autoIndent: false).then (o) -> editor = o
|
||||
|
||||
atom.syntax.addGrammar(jsGrammar)
|
||||
expect(editor2.getGrammar()).toBe jsGrammar
|
||||
expect(editor2.lineForScreenRow(0).tokens.length).toBeGreaterThan 1
|
||||
runs ->
|
||||
expect(editor.getGrammar()).toBe atom.syntax.nullGrammar
|
||||
expect(editor.lineForScreenRow(0).tokens.length).toBe 1
|
||||
|
||||
atom.syntax.addGrammar(jsGrammar)
|
||||
expect(editor.getGrammar()).toBe jsGrammar
|
||||
expect(editor.lineForScreenRow(0).tokens.length).toBeGreaterThan 1
|
||||
|
||||
describe "auto-indent", ->
|
||||
copyText = (text, {startColumn}={}) ->
|
||||
@@ -2874,10 +2923,15 @@ describe "Editor", ->
|
||||
expect(editor.shouldPromptToSave()).toBeFalsy()
|
||||
buffer.setText('changed')
|
||||
expect(editor.shouldPromptToSave()).toBeTruthy()
|
||||
editor2 = atom.project.openSync('sample.js', autoIndent: false)
|
||||
expect(editor.shouldPromptToSave()).toBeFalsy()
|
||||
editor2.destroy()
|
||||
expect(editor.shouldPromptToSave()).toBeTruthy()
|
||||
|
||||
editor2 = null
|
||||
waitsForPromise ->
|
||||
atom.project.open('sample.js', autoIndent: false).then (o) -> editor2 = o
|
||||
|
||||
runs ->
|
||||
expect(editor.shouldPromptToSave()).toBeFalsy()
|
||||
editor2.destroy()
|
||||
expect(editor.shouldPromptToSave()).toBeTruthy()
|
||||
|
||||
describe "when the edit session contains surrogate pair characters", ->
|
||||
it "correctly backspaces over them", ->
|
||||
@@ -2973,12 +3027,15 @@ describe "Editor", ->
|
||||
|
||||
describe "when the grammar is added", ->
|
||||
it "retokenizes existing buffers that contain tokens that match the injection selector", ->
|
||||
editor = atom.project.openSync('sample.js')
|
||||
editor.setText("// http://github.com")
|
||||
waitsForPromise ->
|
||||
atom.workspace.open('sample.js').then (o) -> editor = o
|
||||
|
||||
{tokens} = editor.lineForScreenRow(0)
|
||||
expect(tokens[1].value).toBe " http://github.com"
|
||||
expect(tokens[1].scopes).toEqual ["source.js", "comment.line.double-slash.js"]
|
||||
runs ->
|
||||
editor.setText("// http://github.com")
|
||||
|
||||
{tokens} = editor.lineForScreenRow(0)
|
||||
expect(tokens[1].value).toBe " http://github.com"
|
||||
expect(tokens[1].scopes).toEqual ["source.js", "comment.line.double-slash.js"]
|
||||
|
||||
waitsForPromise ->
|
||||
atom.packages.activatePackage('language-hyperlink')
|
||||
@@ -2990,12 +3047,15 @@ describe "Editor", ->
|
||||
|
||||
describe "when the grammar is updated", ->
|
||||
it "retokenizes existing buffers that contain tokens that match the injection selector", ->
|
||||
editor = atom.project.openSync('sample.js')
|
||||
editor.setText("// SELECT * FROM OCTOCATS")
|
||||
waitsForPromise ->
|
||||
atom.workspace.open('sample.js').then (o) -> editor = o
|
||||
|
||||
{tokens} = editor.lineForScreenRow(0)
|
||||
expect(tokens[1].value).toBe " SELECT * FROM OCTOCATS"
|
||||
expect(tokens[1].scopes).toEqual ["source.js", "comment.line.double-slash.js"]
|
||||
runs ->
|
||||
editor.setText("// SELECT * FROM OCTOCATS")
|
||||
|
||||
{tokens} = editor.lineForScreenRow(0)
|
||||
expect(tokens[1].value).toBe " SELECT * FROM OCTOCATS"
|
||||
expect(tokens[1].scopes).toEqual ["source.js", "comment.line.double-slash.js"]
|
||||
|
||||
waitsForPromise ->
|
||||
atom.packages.activatePackage('package-with-injection-selector')
|
||||
@@ -3036,6 +3096,7 @@ describe "Editor", ->
|
||||
editor.setDefaultCharWidth(10)
|
||||
editor.setHeight(50)
|
||||
editor.setWidth(50)
|
||||
editor.setHorizontalScrollbarHeight(0)
|
||||
expect(editor.getScrollTop()).toBe 0
|
||||
expect(editor.getScrollLeft()).toBe 0
|
||||
|
||||
|
||||
+174
-94
@@ -7,22 +7,30 @@ path = require 'path'
|
||||
temp = require 'temp'
|
||||
|
||||
describe "EditorView", ->
|
||||
[buffer, editorView, editor, cachedLineHeight, cachedCharWidth] = []
|
||||
[buffer, editorView, editor, cachedEditor, cachedLineHeight, cachedCharWidth, fart] = []
|
||||
|
||||
beforeEach ->
|
||||
editor = atom.project.openSync('sample.js')
|
||||
buffer = editor.buffer
|
||||
editorView = new EditorView(editor)
|
||||
editorView.lineOverdraw = 2
|
||||
editorView.isFocused = true
|
||||
editorView.enableKeymap()
|
||||
editorView.calculateHeightInLines = ->
|
||||
Math.ceil(@height() / @lineHeight)
|
||||
editorView.attachToDom = ({ heightInLines, widthInChars } = {}) ->
|
||||
heightInLines ?= @getEditor().getBuffer().getLineCount()
|
||||
@height(getLineHeight() * heightInLines)
|
||||
@width(getCharWidth() * widthInChars) if widthInChars
|
||||
$('#jasmine-content').append(this)
|
||||
waitsForPromise ->
|
||||
atom.workspace.open('sample.js').then (o) -> editor = o
|
||||
|
||||
waitsForPromise ->
|
||||
atom.workspace.open('sample.less').then (o) -> cachedEditor = o
|
||||
|
||||
runs ->
|
||||
buffer = editor.buffer
|
||||
editorView = new EditorView(editor)
|
||||
editorView.lineOverdraw = 2
|
||||
editorView.isFocused = true
|
||||
editorView.enableKeymap()
|
||||
|
||||
editorView.calculateHeightInLines = ->
|
||||
Math.ceil(@height() / @lineHeight)
|
||||
|
||||
editorView.attachToDom = ({ heightInLines, widthInChars } = {}) ->
|
||||
heightInLines ?= @getEditor().getBuffer().getLineCount()
|
||||
@height(getLineHeight() * heightInLines)
|
||||
@width(getCharWidth() * widthInChars) if widthInChars
|
||||
$('#jasmine-content').append(this)
|
||||
|
||||
waitsForPromise ->
|
||||
atom.packages.activatePackage('language-text', sync: true)
|
||||
@@ -41,7 +49,7 @@ describe "EditorView", ->
|
||||
cachedCharWidth
|
||||
|
||||
calcDimensions = ->
|
||||
editorForMeasurement = new EditorView(editor: atom.project.openSync('sample.js'))
|
||||
editorForMeasurement = new EditorView({editor: cachedEditor})
|
||||
editorForMeasurement.attachToDom()
|
||||
cachedLineHeight = editorForMeasurement.lineHeight
|
||||
cachedCharWidth = editorForMeasurement.charWidth
|
||||
@@ -105,18 +113,23 @@ describe "EditorView", ->
|
||||
|
||||
describe "when the editor's file is modified on disk", ->
|
||||
it "triggers an alert", ->
|
||||
fileChangeHandler = null
|
||||
filePath = path.join(temp.dir, 'atom-changed-file.txt')
|
||||
fs.writeFileSync(filePath, "")
|
||||
editor = atom.project.openSync(filePath)
|
||||
editorView.edit(editor)
|
||||
editor.insertText("now the buffer is modified")
|
||||
|
||||
fileChangeHandler = jasmine.createSpy('fileChange')
|
||||
editor.buffer.file.on 'contents-changed', fileChangeHandler
|
||||
waitsForPromise ->
|
||||
atom.workspace.open(filePath).then (o) -> editor = o
|
||||
|
||||
spyOn(atom, "confirm")
|
||||
runs ->
|
||||
editorView.edit(editor)
|
||||
editor.insertText("now the buffer is modified")
|
||||
|
||||
fs.writeFileSync(filePath, "a file change")
|
||||
fileChangeHandler = jasmine.createSpy('fileChange')
|
||||
editor.buffer.file.on 'contents-changed', fileChangeHandler
|
||||
|
||||
spyOn(atom, "confirm")
|
||||
|
||||
fs.writeFileSync(filePath, "a file change")
|
||||
|
||||
waitsFor "file to trigger contents-changed event", ->
|
||||
fileChangeHandler.callCount > 0
|
||||
@@ -133,8 +146,11 @@ describe "EditorView", ->
|
||||
[newEditor, newBuffer] = []
|
||||
|
||||
beforeEach ->
|
||||
newEditor = atom.project.openSync('two-hundred.txt')
|
||||
newBuffer = newEditor.buffer
|
||||
waitsForPromise ->
|
||||
atom.workspace.open('two-hundred.txt').then (o) -> newEditor = o
|
||||
|
||||
runs ->
|
||||
newBuffer = newEditor.buffer
|
||||
|
||||
it "updates the rendered lines, cursors, selections, scroll position, and event subscriptions to match the given edit session", ->
|
||||
editorView.attachToDom(heightInLines: 5, widthInChars: 30)
|
||||
@@ -170,17 +186,24 @@ describe "EditorView", ->
|
||||
expect(editorView.lineElementForScreenRow(6).text()).toMatch /^ currentgoodbye/
|
||||
|
||||
it "triggers alert if edit session's buffer goes into conflict with changes on disk", ->
|
||||
contentsConflictedHandler = null
|
||||
filePath = path.join(temp.dir, 'atom-changed-file.txt')
|
||||
fs.writeFileSync(filePath, "")
|
||||
tempEditor = atom.project.openSync(filePath)
|
||||
editorView.edit(tempEditor)
|
||||
tempEditor.insertText("a buffer change")
|
||||
tempEditor = null
|
||||
|
||||
spyOn(atom, "confirm")
|
||||
waitsForPromise ->
|
||||
atom.workspace.open(filePath).then (o) -> tempEditor = o
|
||||
|
||||
runs ->
|
||||
editorView.edit(tempEditor)
|
||||
tempEditor.insertText("a buffer change")
|
||||
|
||||
spyOn(atom, "confirm")
|
||||
|
||||
contentsConflictedHandler = jasmine.createSpy("contentsConflictedHandler")
|
||||
tempEditor.on 'contents-conflicted', contentsConflictedHandler
|
||||
fs.writeFileSync(filePath, "a file change")
|
||||
|
||||
contentsConflictedHandler = jasmine.createSpy("contentsConflictedHandler")
|
||||
tempEditor.on 'contents-conflicted', contentsConflictedHandler
|
||||
fs.writeFileSync(filePath, "a file change")
|
||||
waitsFor ->
|
||||
contentsConflictedHandler.callCount > 0
|
||||
|
||||
@@ -281,26 +304,34 @@ describe "EditorView", ->
|
||||
it "emits event when editor view view receives a new buffer", ->
|
||||
eventHandler = jasmine.createSpy('eventHandler')
|
||||
editorView.on 'editor:path-changed', eventHandler
|
||||
editorView.edit(atom.project.openSync(filePath))
|
||||
expect(eventHandler).toHaveBeenCalled()
|
||||
waitsForPromise ->
|
||||
atom.workspace.open(filePath).then (editor) ->
|
||||
editorView.edit(editor)
|
||||
|
||||
runs ->
|
||||
expect(eventHandler).toHaveBeenCalled()
|
||||
|
||||
it "stops listening to events on previously set buffers", ->
|
||||
eventHandler = jasmine.createSpy('eventHandler')
|
||||
oldBuffer = editor.getBuffer()
|
||||
newEditor = atom.project.openSync(filePath)
|
||||
editorView.on 'editor:path-changed', eventHandler
|
||||
newEditor = null
|
||||
|
||||
waitsForPromise ->
|
||||
atom.workspace.open(filePath).then (o) -> newEditor = o
|
||||
|
||||
editorView.edit(newEditor)
|
||||
expect(eventHandler).toHaveBeenCalled()
|
||||
runs ->
|
||||
editorView.on 'editor:path-changed', eventHandler
|
||||
|
||||
eventHandler.reset()
|
||||
oldBuffer.saveAs(path.join(temp.dir, 'atom-bad.txt'))
|
||||
expect(eventHandler).not.toHaveBeenCalled()
|
||||
editorView.edit(newEditor)
|
||||
expect(eventHandler).toHaveBeenCalled()
|
||||
|
||||
eventHandler.reset()
|
||||
newEditor.getBuffer().saveAs(path.join(temp.dir, 'atom-new.txt'))
|
||||
expect(eventHandler).toHaveBeenCalled()
|
||||
eventHandler.reset()
|
||||
oldBuffer.saveAs(path.join(temp.dir, 'atom-bad.txt'))
|
||||
expect(eventHandler).not.toHaveBeenCalled()
|
||||
|
||||
eventHandler.reset()
|
||||
newEditor.getBuffer().saveAs(path.join(temp.dir, 'atom-new.txt'))
|
||||
expect(eventHandler).toHaveBeenCalled()
|
||||
|
||||
it "loads the grammar for the new path", ->
|
||||
expect(editor.getGrammar().name).toBe 'JavaScript'
|
||||
@@ -478,7 +509,7 @@ describe "EditorView", ->
|
||||
|
||||
expect(editor.getSelectedBufferRange()).toEqual [[3, 10], [3, 12]]
|
||||
|
||||
describe "when clicking between a word and a non-word", ->
|
||||
describe "when double-clicking between a word and a non-word", ->
|
||||
it "selects the word", ->
|
||||
expect(editor.getCursorScreenPosition()).toEqual(row: 0, column: 0)
|
||||
editorView.renderedLines.trigger mousedownEvent(editorView: editorView, point: [1, 21], originalEvent: {detail: 1})
|
||||
@@ -501,6 +532,30 @@ describe "EditorView", ->
|
||||
editorView.renderedLines.trigger 'mouseup'
|
||||
expect(editor.getSelectedText()).toBe "{"
|
||||
|
||||
describe "when double-clicking on whitespace", ->
|
||||
it "selects all adjacent whitespace", ->
|
||||
editor.setText(" some text ")
|
||||
editor.setCursorBufferPosition([0, 2])
|
||||
editorView.renderedLines.trigger mousedownEvent(editorView: editorView, point: [0, 2], originalEvent: {detail: 1})
|
||||
editorView.renderedLines.trigger 'mouseup'
|
||||
editorView.renderedLines.trigger mousedownEvent(editorView: editorView, point: [0, 2], originalEvent: {detail: 2})
|
||||
editorView.renderedLines.trigger 'mouseup'
|
||||
expect(editor.getSelectedBufferRange()).toEqual [[0, 0], [0, 3]]
|
||||
|
||||
editor.setCursorBufferPosition([0, 8])
|
||||
editorView.renderedLines.trigger mousedownEvent(editorView: editorView, point: [0, 8], originalEvent: {detail: 1})
|
||||
editorView.renderedLines.trigger 'mouseup'
|
||||
editorView.renderedLines.trigger mousedownEvent(editorView: editorView, point: [0, 8], originalEvent: {detail: 2})
|
||||
editorView.renderedLines.trigger 'mouseup'
|
||||
expect(editor.getSelectedBufferRange()).toEqual [[0, 7], [0, 9]]
|
||||
|
||||
editor.setCursorBufferPosition([0, 14])
|
||||
editorView.renderedLines.trigger mousedownEvent(editorView: editorView, point: [0, 14], originalEvent: {detail: 1})
|
||||
editorView.renderedLines.trigger 'mouseup'
|
||||
editorView.renderedLines.trigger mousedownEvent(editorView: editorView, point: [0, 14], originalEvent: {detail: 2})
|
||||
editorView.renderedLines.trigger 'mouseup'
|
||||
expect(editor.getSelectedBufferRange()).toEqual [[0, 13], [0, 17]]
|
||||
|
||||
describe "triple/quardruple/etc-click", ->
|
||||
it "selects the line under the cursor", ->
|
||||
expect(editor.getCursorScreenPosition()).toEqual(row: 0, column: 0)
|
||||
@@ -1529,14 +1584,18 @@ describe "EditorView", ->
|
||||
|
||||
describe "when autoscrolling at the end of the document", ->
|
||||
it "renders lines properly", ->
|
||||
editorView.edit(atom.project.openSync('two-hundred.txt'))
|
||||
editorView.attachToDom(heightInLines: 5.5)
|
||||
waitsForPromise ->
|
||||
atom.workspace.open('two-hundred.txt').then (editor) ->
|
||||
editorView.edit(editor)
|
||||
|
||||
expect(editorView.renderedLines.find('.line').length).toBe 8
|
||||
runs ->
|
||||
editorView.attachToDom(heightInLines: 5.5)
|
||||
|
||||
editor.moveCursorToBottom()
|
||||
expect(editorView.renderedLines.find('.line').length).toBe 8
|
||||
|
||||
expect(editorView.renderedLines.find('.line').length).toBe 8
|
||||
editor.moveCursorToBottom()
|
||||
|
||||
expect(editorView.renderedLines.find('.line').length).toBe 8
|
||||
|
||||
describe "when line has a character that could push it to be too tall (regression)", ->
|
||||
it "does renders the line at a consistent height", ->
|
||||
@@ -1784,10 +1843,14 @@ describe "EditorView", ->
|
||||
expect(editor.bufferPositionForScreenPosition(editor.getCursorScreenPosition())).toEqual [3, 60]
|
||||
|
||||
it "does not wrap the lines of any newly assigned buffers", ->
|
||||
otherEditor = atom.project.openSync()
|
||||
otherEditor.buffer.setText([1..100].join(''))
|
||||
editorView.edit(otherEditor)
|
||||
expect(editorView.renderedLines.find('.line').length).toBe(1)
|
||||
otherEditor = null
|
||||
waitsForPromise ->
|
||||
atom.workspace.open().then (o) -> otherEditor = o
|
||||
|
||||
runs ->
|
||||
otherEditor.buffer.setText([1..100].join(''))
|
||||
editorView.edit(otherEditor)
|
||||
expect(editorView.renderedLines.find('.line').length).toBe(1)
|
||||
|
||||
it "unwraps lines when softwrap is disabled", ->
|
||||
editorView.toggleSoftWrap()
|
||||
@@ -1816,15 +1879,15 @@ describe "EditorView", ->
|
||||
expect(editor.getCursorScreenPosition()).toEqual [11, 0]
|
||||
|
||||
it "calls .setWidthInChars() when the editor view is attached because now its dimensions are available to calculate it", ->
|
||||
otherEditor = new EditorView(editor: atom.project.openSync('sample.js'))
|
||||
spyOn(otherEditor, 'setWidthInChars')
|
||||
otherEditorView = new EditorView(editor)
|
||||
spyOn(otherEditorView, 'setWidthInChars')
|
||||
|
||||
otherEditor.editor.setSoftWrap(true)
|
||||
expect(otherEditor.setWidthInChars).not.toHaveBeenCalled()
|
||||
otherEditorView.editor.setSoftWrap(true)
|
||||
expect(otherEditorView.setWidthInChars).not.toHaveBeenCalled()
|
||||
|
||||
otherEditor.simulateDomAttachment()
|
||||
expect(otherEditor.setWidthInChars).toHaveBeenCalled()
|
||||
otherEditor.remove()
|
||||
otherEditorView.simulateDomAttachment()
|
||||
expect(otherEditorView.setWidthInChars).toHaveBeenCalled()
|
||||
otherEditorView.remove()
|
||||
|
||||
describe "when the editor view's width changes", ->
|
||||
it "updates the width in characters on the edit session", ->
|
||||
@@ -1975,15 +2038,19 @@ describe "EditorView", ->
|
||||
|
||||
describe "when the switching from an edit session for a long buffer to an edit session for a short buffer", ->
|
||||
it "updates the line numbers to reflect the shorter buffer", ->
|
||||
emptyEditor = atom.project.openSync(null)
|
||||
editorView.edit(emptyEditor)
|
||||
expect(editorView.gutter.lineNumbers.find('.line-number').length).toBe 1
|
||||
emptyEditor = null
|
||||
waitsForPromise ->
|
||||
atom.workspace.open().then (o) -> emptyEditor = o
|
||||
|
||||
editorView.edit(editor)
|
||||
expect(editorView.gutter.lineNumbers.find('.line-number').length).toBeGreaterThan 1
|
||||
runs ->
|
||||
editorView.edit(emptyEditor)
|
||||
expect(editorView.gutter.lineNumbers.find('.line-number').length).toBe 1
|
||||
|
||||
editorView.edit(emptyEditor)
|
||||
expect(editorView.gutter.lineNumbers.find('.line-number').length).toBe 1
|
||||
editorView.edit(editor)
|
||||
expect(editorView.gutter.lineNumbers.find('.line-number').length).toBeGreaterThan 1
|
||||
|
||||
editorView.edit(emptyEditor)
|
||||
expect(editorView.gutter.lineNumbers.find('.line-number').length).toBe 1
|
||||
|
||||
describe "when the editor view is mini", ->
|
||||
it "hides the gutter", ->
|
||||
@@ -2203,10 +2270,13 @@ describe "EditorView", ->
|
||||
|
||||
describe "folding", ->
|
||||
beforeEach ->
|
||||
editor = atom.project.openSync('two-hundred.txt')
|
||||
buffer = editor.buffer
|
||||
editorView.edit(editor)
|
||||
editorView.attachToDom()
|
||||
waitsForPromise ->
|
||||
atom.workspace.open('two-hundred.txt').then (o) -> editor = o
|
||||
|
||||
runs ->
|
||||
buffer = editor.buffer
|
||||
editorView.edit(editor)
|
||||
editorView.attachToDom()
|
||||
|
||||
describe "when a fold-selection event is triggered", ->
|
||||
it "folds the lines covered by the selection into a single line with a fold class and marker", ->
|
||||
@@ -2260,7 +2330,7 @@ describe "EditorView", ->
|
||||
it "adds/removes the 'fold-selected' class to the fold's line element and hides the cursor if it is on the fold line", ->
|
||||
editor.createFold(2, 4)
|
||||
|
||||
editor.setSelectedBufferRange([[1, 0], [2, 0]], preserveFolds: true, isReversed: true)
|
||||
editor.setSelectedBufferRange([[1, 0], [2, 0]], preserveFolds: true, reversed: true)
|
||||
expect(editorView.lineElementForScreenRow(2)).toMatchSelector('.fold.fold-selected')
|
||||
|
||||
editor.setSelectedBufferRange([[1, 0], [1, 1]], preserveFolds: true)
|
||||
@@ -2341,8 +2411,11 @@ describe "EditorView", ->
|
||||
beforeEach ->
|
||||
filePath = atom.project.resolve('git/working-dir/file.txt')
|
||||
originalPathText = fs.readFileSync(filePath, 'utf8')
|
||||
editor = atom.project.openSync(filePath)
|
||||
editorView.edit(editor)
|
||||
waitsForPromise ->
|
||||
atom.workspace.open(filePath).then (o) -> editor = o
|
||||
|
||||
runs ->
|
||||
editorView.edit(editor)
|
||||
|
||||
afterEach ->
|
||||
fs.writeFileSync(filePath, originalPathText)
|
||||
@@ -2816,7 +2889,7 @@ describe "EditorView", ->
|
||||
|
||||
describe "when the escape key is pressed on the editor view", ->
|
||||
it "clears multiple selections if there are any, and otherwise allows other bindings to be handled", ->
|
||||
atom.keymaps.bindKeys 'name', '.editor', {'escape': 'test-event'}
|
||||
atom.keymaps.add 'name', '.editor': {'escape': 'test-event'}
|
||||
testEventHandler = jasmine.createSpy("testEventHandler")
|
||||
|
||||
editorView.on 'test-event', testEventHandler
|
||||
@@ -2833,22 +2906,26 @@ describe "EditorView", ->
|
||||
describe "when the editor view is attached but invisible", ->
|
||||
describe "when the editor view's text is changed", ->
|
||||
it "redraws the editor view when it is next shown", ->
|
||||
displayUpdatedHandler = null
|
||||
atom.workspaceView = new WorkspaceView
|
||||
atom.workspaceView.openSync('sample.js')
|
||||
atom.workspaceView.attachToDom()
|
||||
editorView = atom.workspaceView.getActiveView()
|
||||
waitsForPromise ->
|
||||
atom.workspaceView.open('sample.txt').then (o) -> editor = o
|
||||
|
||||
view = $$ -> @div id: 'view', tabindex: -1, 'View'
|
||||
editorView.getPane().activateItem(view)
|
||||
expect(editorView.isVisible()).toBeFalsy()
|
||||
runs ->
|
||||
atom.workspaceView.attachToDom()
|
||||
editorView = atom.workspaceView.getActiveView()
|
||||
|
||||
editor.setText('hidden changes')
|
||||
editor.setCursorBufferPosition([0,4])
|
||||
view = $$ -> @div id: 'view', tabindex: -1, 'View'
|
||||
editorView.getPane().activateItem(view)
|
||||
expect(editorView.isVisible()).toBeFalsy()
|
||||
|
||||
displayUpdatedHandler = jasmine.createSpy("displayUpdatedHandler")
|
||||
editorView.on 'editor:display-updated', displayUpdatedHandler
|
||||
editorView.getPane().activateItem(editorView.getModel())
|
||||
expect(editorView.isVisible()).toBeTruthy()
|
||||
editor.setText('hidden changes')
|
||||
editor.setCursorBufferPosition([0,4])
|
||||
|
||||
displayUpdatedHandler = jasmine.createSpy("displayUpdatedHandler")
|
||||
editorView.on 'editor:display-updated', displayUpdatedHandler
|
||||
editorView.getPane().activateItem(editorView.getModel())
|
||||
expect(editorView.isVisible()).toBeTruthy()
|
||||
|
||||
waitsFor ->
|
||||
displayUpdatedHandler.callCount is 1
|
||||
@@ -2888,14 +2965,17 @@ describe "EditorView", ->
|
||||
describe "when the editor view is removed", ->
|
||||
it "fires a editor:will-be-removed event", ->
|
||||
atom.workspaceView = new WorkspaceView
|
||||
atom.workspaceView.openSync('sample.js')
|
||||
atom.workspaceView.attachToDom()
|
||||
editorView = atom.workspaceView.getActiveView()
|
||||
waitsForPromise ->
|
||||
atom.workspace.open('sample.js')
|
||||
|
||||
willBeRemovedHandler = jasmine.createSpy('willBeRemovedHandler')
|
||||
editorView.on 'editor:will-be-removed', willBeRemovedHandler
|
||||
editorView.getPane().destroyActiveItem()
|
||||
expect(willBeRemovedHandler).toHaveBeenCalled()
|
||||
runs ->
|
||||
atom.workspaceView.attachToDom()
|
||||
editorView = atom.workspaceView.getActiveView()
|
||||
|
||||
willBeRemovedHandler = jasmine.createSpy('willBeRemovedHandler')
|
||||
editorView.on 'editor:will-be-removed', willBeRemovedHandler
|
||||
editorView.getPane().destroyActiveItem()
|
||||
expect(willBeRemovedHandler).toHaveBeenCalled()
|
||||
|
||||
describe "when setInvisibles is toggled (regression)", ->
|
||||
it "renders inserted newlines properly", ->
|
||||
|
||||
+11
-5
@@ -229,8 +229,11 @@ describe "Git", ->
|
||||
[originalContent, editor] = []
|
||||
|
||||
beforeEach ->
|
||||
editor = atom.project.openSync('sample.js')
|
||||
originalContent = editor.getText()
|
||||
waitsForPromise ->
|
||||
atom.workspace.open('sample.js').then (o) -> editor = o
|
||||
|
||||
runs ->
|
||||
originalContent = editor.getText()
|
||||
|
||||
afterEach ->
|
||||
fs.writeFileSync(editor.getPath(), originalContent)
|
||||
@@ -274,9 +277,12 @@ describe "Git", ->
|
||||
project2?.destroy()
|
||||
|
||||
it "subscribes to all the serialized buffers in the project", ->
|
||||
atom.project.openSync('sample.js')
|
||||
project2 = atom.project.testSerialization()
|
||||
buffer = project2.getBuffers()[0]
|
||||
waitsForPromise ->
|
||||
atom.workspace.open('sample.js')
|
||||
|
||||
runs ->
|
||||
project2 = atom.project.testSerialization()
|
||||
buffer = project2.getBuffers()[0]
|
||||
|
||||
waitsFor ->
|
||||
buffer.loaded
|
||||
|
||||
@@ -6,8 +6,10 @@ describe "LanguageMode", ->
|
||||
|
||||
describe "javascript", ->
|
||||
beforeEach ->
|
||||
editor = atom.project.openSync('sample.js', autoIndent: false)
|
||||
{buffer, languageMode} = editor
|
||||
waitsForPromise ->
|
||||
atom.workspace.open('sample.js', autoIndent: false).then (o) ->
|
||||
editor = o
|
||||
{buffer, languageMode} = editor
|
||||
|
||||
waitsForPromise ->
|
||||
atom.packages.activatePackage('language-javascript')
|
||||
@@ -112,8 +114,10 @@ describe "LanguageMode", ->
|
||||
|
||||
describe "coffeescript", ->
|
||||
beforeEach ->
|
||||
editor = atom.project.openSync('coffee.coffee', autoIndent: false)
|
||||
{buffer, languageMode} = editor
|
||||
waitsForPromise ->
|
||||
atom.workspace.open('coffee.coffee', autoIndent: false).then (o) ->
|
||||
editor = o
|
||||
{buffer, languageMode} = editor
|
||||
|
||||
waitsForPromise ->
|
||||
atom.packages.activatePackage('language-coffee-script')
|
||||
@@ -161,8 +165,10 @@ describe "LanguageMode", ->
|
||||
|
||||
describe "css", ->
|
||||
beforeEach ->
|
||||
editor = atom.project.openSync('css.css', autoIndent: false)
|
||||
{buffer, languageMode} = editor
|
||||
waitsForPromise ->
|
||||
atom.workspace.open('css.css', autoIndent: false).then (o) ->
|
||||
editor = o
|
||||
{buffer, languageMode} = editor
|
||||
|
||||
waitsForPromise ->
|
||||
atom.packages.activatePackage('language-css')
|
||||
@@ -178,13 +184,13 @@ describe "LanguageMode", ->
|
||||
languageMode.toggleLineCommentsForBufferRows(2, 2)
|
||||
expect(buffer.lineForRow(0)).toBe "/*body {"
|
||||
expect(buffer.lineForRow(1)).toBe " font-size: 1234px;*/"
|
||||
expect(buffer.lineForRow(2)).toBe "/* width: 110%;*/"
|
||||
expect(buffer.lineForRow(2)).toBe " /*width: 110%;*/"
|
||||
expect(buffer.lineForRow(3)).toBe " font-weight: bold !important;"
|
||||
|
||||
languageMode.toggleLineCommentsForBufferRows(0, 1)
|
||||
expect(buffer.lineForRow(0)).toBe "body {"
|
||||
expect(buffer.lineForRow(1)).toBe " font-size: 1234px;"
|
||||
expect(buffer.lineForRow(2)).toBe "/* width: 110%;*/"
|
||||
expect(buffer.lineForRow(2)).toBe " /*width: 110%;*/"
|
||||
expect(buffer.lineForRow(3)).toBe " font-weight: bold !important;"
|
||||
|
||||
it "uncomments lines with leading whitespace", ->
|
||||
@@ -204,8 +210,10 @@ describe "LanguageMode", ->
|
||||
|
||||
describe "less", ->
|
||||
beforeEach ->
|
||||
editor = atom.project.openSync('sample.less', autoIndent: false)
|
||||
{buffer, languageMode} = editor
|
||||
waitsForPromise ->
|
||||
atom.workspace.open('sample.less', autoIndent: false).then (o) ->
|
||||
editor = o
|
||||
{buffer, languageMode} = editor
|
||||
|
||||
waitsForPromise ->
|
||||
atom.packages.activatePackage('language-less')
|
||||
@@ -220,9 +228,11 @@ describe "LanguageMode", ->
|
||||
|
||||
describe "xml", ->
|
||||
beforeEach ->
|
||||
editor = atom.project.openSync('sample.xml', autoIndent: false)
|
||||
editor.setText("<!-- test -->")
|
||||
{buffer, languageMode} = editor
|
||||
waitsForPromise ->
|
||||
atom.workspace.open('sample.xml', autoIndent: false).then (o) ->
|
||||
editor = o
|
||||
editor.setText("<!-- test -->")
|
||||
{buffer, languageMode} = editor
|
||||
|
||||
waitsForPromise ->
|
||||
atom.packages.activatePackage('language-xml')
|
||||
@@ -234,8 +244,10 @@ describe "LanguageMode", ->
|
||||
|
||||
describe "folding", ->
|
||||
beforeEach ->
|
||||
editor = atom.project.openSync('sample.js', autoIndent: false)
|
||||
{buffer, languageMode} = editor
|
||||
waitsForPromise ->
|
||||
atom.workspace.open('sample.js', autoIndent: false).then (o) ->
|
||||
editor = o
|
||||
{buffer, languageMode} = editor
|
||||
|
||||
waitsForPromise ->
|
||||
atom.packages.activatePackage('language-javascript')
|
||||
@@ -319,8 +331,10 @@ describe "LanguageMode", ->
|
||||
|
||||
describe "folding with comments", ->
|
||||
beforeEach ->
|
||||
editor = atom.project.openSync('sample-with-comments.js', autoIndent: false)
|
||||
{buffer, languageMode} = editor
|
||||
waitsForPromise ->
|
||||
atom.workspace.open('sample-with-comments.js', autoIndent: false).then (o) ->
|
||||
editor = o
|
||||
{buffer, languageMode} = editor
|
||||
|
||||
waitsForPromise ->
|
||||
atom.packages.activatePackage('language-javascript')
|
||||
@@ -385,7 +399,10 @@ describe "LanguageMode", ->
|
||||
|
||||
describe "css", ->
|
||||
beforeEach ->
|
||||
editor = atom.project.openSync('css.css', autoIndent: true)
|
||||
waitsForPromise ->
|
||||
atom.workspace.open('css.css', autoIndent: true).then (o) ->
|
||||
editor = o
|
||||
{buffer, languageMode} = editor
|
||||
|
||||
waitsForPromise ->
|
||||
atom.packages.activatePackage('language-source')
|
||||
|
||||
@@ -21,11 +21,16 @@ describe "PaneView", ->
|
||||
container = new PaneContainerView
|
||||
view1 = new TestView(id: 'view-1', text: 'View 1')
|
||||
view2 = new TestView(id: 'view-2', text: 'View 2')
|
||||
editor1 = atom.project.openSync('sample.js')
|
||||
editor2 = atom.project.openSync('sample.txt')
|
||||
pane = container.getRoot()
|
||||
paneModel = pane.model
|
||||
paneModel.addItems([view1, editor1, view2, editor2])
|
||||
waitsForPromise ->
|
||||
atom.workspace.open('sample.js').then (o) -> editor1 = o
|
||||
|
||||
waitsForPromise ->
|
||||
atom.workspace.open('sample.txt').then (o) -> editor2 = o
|
||||
|
||||
runs ->
|
||||
pane = container.getRoot()
|
||||
paneModel = pane.model
|
||||
paneModel.addItems([view1, editor1, view2, editor2])
|
||||
|
||||
afterEach ->
|
||||
atom.deserializers.remove(TestView)
|
||||
@@ -159,14 +164,20 @@ describe "PaneView", ->
|
||||
|
||||
describe "when an unmodifed buffer's path is deleted", ->
|
||||
it "removes the pane item", ->
|
||||
editor = null
|
||||
jasmine.unspy(window, 'setTimeout')
|
||||
filePath = temp.openSync('atom').path
|
||||
editor = atom.project.openSync(filePath)
|
||||
pane.activateItem(editor)
|
||||
expect(pane.items).toHaveLength(5)
|
||||
|
||||
fs.removeSync(filePath)
|
||||
waitsFor -> pane.items.length == 4
|
||||
waitsForPromise ->
|
||||
atom.workspace.open(filePath).then (o) -> editor = o
|
||||
|
||||
runs ->
|
||||
pane.activateItem(editor)
|
||||
expect(pane.items).toHaveLength(5)
|
||||
fs.removeSync(filePath)
|
||||
|
||||
waitsFor ->
|
||||
pane.items.length == 4
|
||||
|
||||
describe "when a pane is destroyed", ->
|
||||
[pane2, pane2Model] = []
|
||||
|
||||
+67
-75
@@ -18,62 +18,39 @@ describe "Project", ->
|
||||
deserializedProject?.destroy()
|
||||
|
||||
it "does not include unretained buffers in the serialized state", ->
|
||||
atom.project.bufferForPathSync('a')
|
||||
expect(atom.project.getBuffers().length).toBe 1
|
||||
waitsForPromise ->
|
||||
atom.project.bufferForPath('a')
|
||||
|
||||
deserializedProject = atom.project.testSerialization()
|
||||
expect(deserializedProject.getBuffers().length).toBe 0
|
||||
runs ->
|
||||
expect(atom.project.getBuffers().length).toBe 1
|
||||
deserializedProject = atom.project.testSerialization()
|
||||
expect(deserializedProject.getBuffers().length).toBe 0
|
||||
|
||||
it "listens for destroyed events on deserialized buffers and removes them when they are destroyed", ->
|
||||
atom.project.openSync('a')
|
||||
expect(atom.project.getBuffers().length).toBe 1
|
||||
deserializedProject = atom.project.testSerialization()
|
||||
waitsForPromise ->
|
||||
atom.project.open('a')
|
||||
|
||||
expect(deserializedProject.getBuffers().length).toBe 1
|
||||
deserializedProject.getBuffers()[0].destroy()
|
||||
expect(deserializedProject.getBuffers().length).toBe 0
|
||||
runs ->
|
||||
expect(atom.project.getBuffers().length).toBe 1
|
||||
deserializedProject = atom.project.testSerialization()
|
||||
|
||||
expect(deserializedProject.getBuffers().length).toBe 1
|
||||
deserializedProject.getBuffers()[0].destroy()
|
||||
expect(deserializedProject.getBuffers().length).toBe 0
|
||||
|
||||
describe "when an editor is saved and the project has no path", ->
|
||||
it "sets the project's path to the saved file's parent directory", ->
|
||||
tempFile = temp.openSync().path
|
||||
atom.project.setPath(undefined)
|
||||
expect(atom.project.getPath()).toBeUndefined()
|
||||
editor = atom.project.openSync()
|
||||
editor.saveAs(tempFile)
|
||||
expect(atom.project.getPath()).toBe path.dirname(tempFile)
|
||||
editor = null
|
||||
|
||||
describe ".openSync(path)", ->
|
||||
[absolutePath, newBufferHandler] = []
|
||||
beforeEach ->
|
||||
absolutePath = require.resolve('./fixtures/dir/a')
|
||||
newBufferHandler = jasmine.createSpy('newBufferHandler')
|
||||
atom.project.on 'buffer-created', newBufferHandler
|
||||
waitsForPromise ->
|
||||
atom.project.open().then (o) -> editor = o
|
||||
|
||||
describe "when given an absolute path that hasn't been opened previously", ->
|
||||
it "returns a new edit session for the given path and emits 'buffer-created'", ->
|
||||
editor = atom.project.openSync(absolutePath)
|
||||
expect(editor.buffer.getPath()).toBe absolutePath
|
||||
expect(newBufferHandler).toHaveBeenCalledWith editor.buffer
|
||||
|
||||
describe "when given a relative path that hasn't been opened previously", ->
|
||||
it "returns a new edit session for the given path (relative to the project root) and emits 'buffer-created'", ->
|
||||
editor = atom.project.openSync('a')
|
||||
expect(editor.buffer.getPath()).toBe absolutePath
|
||||
expect(newBufferHandler).toHaveBeenCalledWith editor.buffer
|
||||
|
||||
describe "when passed the path to a buffer that has already been opened", ->
|
||||
it "returns a new edit session containing previously opened buffer", ->
|
||||
editor = atom.project.openSync(absolutePath)
|
||||
newBufferHandler.reset()
|
||||
expect(atom.project.openSync(absolutePath).buffer).toBe editor.buffer
|
||||
expect(atom.project.openSync('a').buffer).toBe editor.buffer
|
||||
expect(newBufferHandler).not.toHaveBeenCalled()
|
||||
|
||||
describe "when not passed a path", ->
|
||||
it "returns a new edit session and emits 'buffer-created'", ->
|
||||
editor = atom.project.openSync()
|
||||
expect(editor.buffer.getPath()).toBeUndefined()
|
||||
expect(newBufferHandler).toHaveBeenCalledWith(editor.buffer)
|
||||
runs ->
|
||||
editor.saveAs(tempFile)
|
||||
expect(atom.project.getPath()).toBe path.dirname(tempFile)
|
||||
|
||||
describe ".open(path)", ->
|
||||
[absolutePath, newBufferHandler] = []
|
||||
@@ -106,14 +83,21 @@ describe "Project", ->
|
||||
describe "when passed the path to a buffer that is currently opened", ->
|
||||
it "returns a new edit session containing currently opened buffer", ->
|
||||
editor = null
|
||||
|
||||
waitsForPromise ->
|
||||
atom.project.open(absolutePath).then (o) -> editor = o
|
||||
|
||||
runs ->
|
||||
newBufferHandler.reset()
|
||||
expect(atom.project.openSync(absolutePath).buffer).toBe editor.buffer
|
||||
expect(atom.project.openSync('a').buffer).toBe editor.buffer
|
||||
expect(newBufferHandler).not.toHaveBeenCalled()
|
||||
|
||||
waitsForPromise ->
|
||||
atom.project.open(absolutePath).then ({buffer}) ->
|
||||
expect(buffer).toBe editor.buffer
|
||||
|
||||
waitsForPromise ->
|
||||
atom.project.open('a').then ({buffer}) ->
|
||||
expect(buffer).toBe editor.buffer
|
||||
expect(newBufferHandler).not.toHaveBeenCalled()
|
||||
|
||||
describe "when not passed a path", ->
|
||||
it "returns a new edit session and emits 'buffer-created'", ->
|
||||
@@ -137,20 +121,6 @@ describe "Project", ->
|
||||
runs ->
|
||||
expect(totalBytes).toBe fs.statSync(filePath).size
|
||||
|
||||
describe ".bufferForPathSync(path)", ->
|
||||
describe "when opening a previously opened path", ->
|
||||
it "does not create a new buffer", ->
|
||||
buffer = atom.project.bufferForPathSync("a").retain()
|
||||
expect(atom.project.bufferForPathSync("a")).toBe buffer
|
||||
|
||||
alternativeBuffer = atom.project.bufferForPathSync("b").retain().release()
|
||||
expect(alternativeBuffer).not.toBe buffer
|
||||
buffer.release()
|
||||
|
||||
it "creates a new buffer if the previous buffer was destroyed", ->
|
||||
buffer = atom.project.bufferForPathSync("a").retain().release()
|
||||
expect(atom.project.bufferForPathSync("a").retain().release()).not.toBe buffer
|
||||
|
||||
describe ".bufferForPath(path)", ->
|
||||
[buffer] = []
|
||||
beforeEach ->
|
||||
@@ -240,10 +210,15 @@ describe "Project", ->
|
||||
|
||||
describe "when a buffer is already open", ->
|
||||
it "replaces properly and saves when not modified", ->
|
||||
editor = atom.project.openSync('sample.js')
|
||||
expect(editor.isModified()).toBeFalsy()
|
||||
|
||||
editor = null
|
||||
results = []
|
||||
|
||||
waitsForPromise ->
|
||||
atom.project.open('sample.js').then (o) -> editor = o
|
||||
|
||||
runs ->
|
||||
expect(editor.isModified()).toBeFalsy()
|
||||
|
||||
waitsForPromise ->
|
||||
atom.project.replace /items/gi, 'items', [filePath], (result) ->
|
||||
results.push(result)
|
||||
@@ -256,10 +231,12 @@ describe "Project", ->
|
||||
expect(editor.isModified()).toBeFalsy()
|
||||
|
||||
it "does not replace when the path is not specified", ->
|
||||
editor = atom.project.openSync('sample.js')
|
||||
editor = atom.project.openSync('sample-with-comments.js')
|
||||
|
||||
editor = null
|
||||
results = []
|
||||
|
||||
waitsForPromise ->
|
||||
atom.project.open('sample-with-comments.js').then (o) -> editor = o
|
||||
|
||||
waitsForPromise ->
|
||||
atom.project.replace /items/gi, 'items', [commentFilePath], (result) ->
|
||||
results.push(result)
|
||||
@@ -269,11 +246,16 @@ describe "Project", ->
|
||||
expect(results[0].filePath).toBe commentFilePath
|
||||
|
||||
it "does NOT save when modified", ->
|
||||
editor = atom.project.openSync('sample.js')
|
||||
editor.buffer.setTextInRange([[0,0],[0,0]], 'omg')
|
||||
expect(editor.isModified()).toBeTruthy()
|
||||
|
||||
editor = null
|
||||
results = []
|
||||
|
||||
waitsForPromise ->
|
||||
atom.project.open('sample.js').then (o) -> editor = o
|
||||
|
||||
runs ->
|
||||
editor.buffer.setTextInRange([[0,0],[0,0]], 'omg')
|
||||
expect(editor.isModified()).toBeTruthy()
|
||||
|
||||
waitsForPromise ->
|
||||
atom.project.replace /items/gi, 'okthen', [filePath], (result) ->
|
||||
results.push(result)
|
||||
@@ -437,9 +419,14 @@ describe "Project", ->
|
||||
expect(resultHandler).not.toHaveBeenCalled()
|
||||
|
||||
it "scans buffer contents if the buffer is modified", ->
|
||||
editor = atom.project.openSync("a")
|
||||
editor.setText("Elephant")
|
||||
editor = null
|
||||
results = []
|
||||
|
||||
waitsForPromise ->
|
||||
atom.project.open('a').then (o) ->
|
||||
editor = o
|
||||
editor.setText("Elephant")
|
||||
|
||||
waitsForPromise ->
|
||||
atom.project.scan /a|Elephant/, (result) -> results.push result
|
||||
|
||||
@@ -450,9 +437,14 @@ describe "Project", ->
|
||||
expect(resultForA.matches[0].matchText).toBe 'Elephant'
|
||||
|
||||
it "ignores buffers outside the project", ->
|
||||
editor = atom.project.openSync(temp.openSync().path)
|
||||
editor.setText("Elephant")
|
||||
editor = null
|
||||
results = []
|
||||
|
||||
waitsForPromise ->
|
||||
atom.project.open(temp.openSync().path).then (o) ->
|
||||
editor = o
|
||||
editor.setText("Elephant")
|
||||
|
||||
waitsForPromise ->
|
||||
atom.project.scan /Elephant/, (result) -> results.push result
|
||||
|
||||
|
||||
@@ -58,7 +58,7 @@ describe "Selection", ->
|
||||
|
||||
describe "when only the selection's tail is moved (regression)", ->
|
||||
it "emits the 'screen-range-changed' event", ->
|
||||
selection.setBufferRange([[2, 0], [2, 10]], isReversed: true)
|
||||
selection.setBufferRange([[2, 0], [2, 10]], reversed: true)
|
||||
changeScreenRangeHandler = jasmine.createSpy('changeScreenRangeHandler')
|
||||
selection.on 'screen-range-changed', changeScreenRangeHandler
|
||||
|
||||
|
||||
@@ -6,6 +6,7 @@ require '../vendor/jasmine-jquery'
|
||||
path = require 'path'
|
||||
_ = require 'underscore-plus'
|
||||
fs = require 'fs-plus'
|
||||
Grim = require 'grim'
|
||||
KeymapManager = require '../src/keymap-extensions'
|
||||
{$, WorkspaceView, Workspace} = require 'atom'
|
||||
Config = require '../src/config'
|
||||
@@ -37,6 +38,7 @@ jasmine.getEnv().defaultTimeoutInterval = 5000
|
||||
specPackageName = null
|
||||
specPackagePath = null
|
||||
specProjectPath = null
|
||||
isCoreSpec = false
|
||||
|
||||
{specDirectory, resourcePath} = atom.getLoadSettings()
|
||||
|
||||
@@ -46,7 +48,10 @@ if specDirectory
|
||||
specPackageName = JSON.parse(fs.readFileSync(path.join(specPackagePath, 'package.json')))?.name
|
||||
specProjectPath = path.join(specDirectory, 'fixtures')
|
||||
|
||||
isCoreSpec = specDirectory == fs.realpathSync(__dirname)
|
||||
|
||||
beforeEach ->
|
||||
Grim.clearDeprecations() if isCoreSpec
|
||||
$.fx.off = true
|
||||
projectPath = specProjectPath ? path.join(@specDirectory, 'fixtures')
|
||||
atom.project = new Project(path: projectPath)
|
||||
@@ -124,6 +129,7 @@ afterEach ->
|
||||
jasmine.unspy(atom, 'saveSync')
|
||||
ensureNoPathSubscriptions()
|
||||
atom.syntax.off()
|
||||
ensureNoDeprecatedFunctionsCalled() if isCoreSpec
|
||||
waits(0) # yield to ui thread to make screen update more frequently
|
||||
|
||||
ensureNoPathSubscriptions = ->
|
||||
@@ -132,6 +138,27 @@ ensureNoPathSubscriptions = ->
|
||||
if watchedPaths.length > 0
|
||||
throw new Error("Leaking subscriptions for paths: " + watchedPaths.join(", "))
|
||||
|
||||
ensureNoDeprecatedFunctionsCalled = ->
|
||||
deprecations = Grim.getDeprecations()
|
||||
if deprecations.length > 0
|
||||
originalPrepareStackTrace = Error.prepareStackTrace
|
||||
Error.prepareStackTrace = (error, stack) ->
|
||||
output = []
|
||||
for deprecation in deprecations
|
||||
output.push "#{deprecation.originName} is deprecated. #{deprecation.message}"
|
||||
output.push _.multiplyString("-", output[output.length - 1].length)
|
||||
for stack in deprecation.getStacks()
|
||||
for {functionName, location} in stack
|
||||
output.push "#{functionName} -- #{location}"
|
||||
output.push ""
|
||||
output.join("\n")
|
||||
|
||||
error = new Error("Deprecated function(s) #{deprecations.map(({originName}) -> originName).join ', '}) were called.")
|
||||
error.stack
|
||||
Error.prepareStackTrace = originalPrepareStackTrace
|
||||
|
||||
throw error
|
||||
|
||||
emitObject = jasmine.StringPrettyPrinter.prototype.emitObject
|
||||
jasmine.StringPrettyPrinter.prototype.emitObject = (obj) ->
|
||||
if obj.inspect
|
||||
@@ -289,7 +316,11 @@ $.fn.resultOfTrigger = (type) ->
|
||||
event.result
|
||||
|
||||
$.fn.enableKeymap = ->
|
||||
@on 'keydown', (e) => atom.keymaps.handleKeyEvent(e)
|
||||
@on 'keydown', (e) ->
|
||||
originalEvent = e.originalEvent ? e
|
||||
Object.defineProperty(originalEvent, 'target', get: -> e.target) unless originalEvent.target?
|
||||
atom.keymaps.handleKeyboardEvent(originalEvent)
|
||||
not e.originalEvent.defaultPrevented
|
||||
|
||||
$.fn.attachToDom = ->
|
||||
@appendTo($('#jasmine-content'))
|
||||
|
||||
@@ -131,15 +131,21 @@ describe "ThemeManager", ->
|
||||
|
||||
describe "requireStylesheet(path)", ->
|
||||
it "synchronously loads css at the given path and installs a style tag for it in the head", ->
|
||||
themeManager.on 'stylesheets-changed', stylesheetsChangedHandler = jasmine.createSpy("stylesheetsChangedHandler")
|
||||
themeManager.on 'stylesheet-added', stylesheetAddedHandler = jasmine.createSpy("stylesheetAddedHandler")
|
||||
cssPath = atom.project.resolve('css.css')
|
||||
lengthBefore = $('head style').length
|
||||
|
||||
themeManager.requireStylesheet(cssPath)
|
||||
expect($('head style').length).toBe lengthBefore + 1
|
||||
|
||||
expect(stylesheetAddedHandler).toHaveBeenCalled()
|
||||
expect(stylesheetsChangedHandler).toHaveBeenCalled()
|
||||
|
||||
element = $('head style[id*="css.css"]')
|
||||
expect(element.attr('id')).toBe themeManager.stringToId(cssPath)
|
||||
expect(element.text()).toBe fs.readFileSync(cssPath, 'utf8')
|
||||
expect(element[0].sheet).toBe stylesheetAddedHandler.argsForCall[0][0]
|
||||
|
||||
# doesn't append twice
|
||||
themeManager.requireStylesheet(cssPath)
|
||||
@@ -187,9 +193,18 @@ describe "ThemeManager", ->
|
||||
themeManager.requireStylesheet(cssPath)
|
||||
expect($(document.body).css('font-weight')).toBe("bold")
|
||||
|
||||
themeManager.on 'stylesheet-removed', stylesheetRemovedHandler = jasmine.createSpy("stylesheetRemovedHandler")
|
||||
themeManager.on 'stylesheets-changed', stylesheetsChangedHandler = jasmine.createSpy("stylesheetsChangedHandler")
|
||||
|
||||
themeManager.removeStylesheet(cssPath)
|
||||
|
||||
expect($(document.body).css('font-weight')).not.toBe("bold")
|
||||
|
||||
expect(stylesheetRemovedHandler).toHaveBeenCalled()
|
||||
stylesheet = stylesheetRemovedHandler.argsForCall[0][0]
|
||||
expect(stylesheet instanceof CSSStyleSheet).toBe true
|
||||
expect(stylesheet.cssRules[0].selectorText).toBe 'body'
|
||||
|
||||
expect(stylesheetsChangedHandler).toHaveBeenCalled()
|
||||
|
||||
describe "base stylesheet loading", ->
|
||||
@@ -219,20 +234,21 @@ describe "ThemeManager", ->
|
||||
|
||||
describe "when the user stylesheet changes", ->
|
||||
it "reloads it", ->
|
||||
[stylesheetRemovedHandler, stylesheetAddedHandler, stylesheetsChangedHandler] = []
|
||||
userStylesheetPath = path.join(temp.mkdirSync("atom"), 'styles.less')
|
||||
fs.writeFileSync(userStylesheetPath, 'body {border-style: dotted !important;}')
|
||||
|
||||
spyOn(themeManager, 'getUserStylesheetPath').andReturn userStylesheetPath
|
||||
themeManager.on 'stylesheets-changed', stylesheetsChangedHandler = jasmine.createSpy("stylesheetsChangedHandler")
|
||||
|
||||
waitsForPromise ->
|
||||
themeManager.activateThemes()
|
||||
|
||||
runs ->
|
||||
expect($(document.body).css('border-style')).toBe 'dotted'
|
||||
expect(stylesheetsChangedHandler).toHaveBeenCalled()
|
||||
stylesheetsChangedHandler.reset()
|
||||
themeManager.on 'stylesheets-changed', stylesheetsChangedHandler = jasmine.createSpy("stylesheetsChangedHandler")
|
||||
themeManager.on 'stylesheet-removed', stylesheetRemovedHandler = jasmine.createSpy("stylesheetRemovedHandler")
|
||||
themeManager.on 'stylesheet-added', stylesheetAddedHandler = jasmine.createSpy("stylesheetAddedHandler")
|
||||
spyOn(themeManager, 'loadUserStylesheet').andCallThrough()
|
||||
|
||||
expect($(document.body).css('border-style')).toBe 'dotted'
|
||||
fs.writeFileSync(userStylesheetPath, 'body {border-style: dashed}')
|
||||
|
||||
waitsFor ->
|
||||
@@ -240,7 +256,16 @@ describe "ThemeManager", ->
|
||||
|
||||
runs ->
|
||||
expect($(document.body).css('border-style')).toBe 'dashed'
|
||||
|
||||
expect(stylesheetRemovedHandler).toHaveBeenCalled()
|
||||
expect(stylesheetRemovedHandler.argsForCall[0][0].cssRules[0].style.border).toBe 'dotted'
|
||||
|
||||
expect(stylesheetAddedHandler).toHaveBeenCalled()
|
||||
expect(stylesheetAddedHandler.argsForCall[0][0].cssRules[0].style.border).toBe 'dashed'
|
||||
|
||||
expect(stylesheetsChangedHandler).toHaveBeenCalled()
|
||||
|
||||
stylesheetRemovedHandler.reset()
|
||||
stylesheetsChangedHandler.reset()
|
||||
fs.removeSync(userStylesheetPath)
|
||||
|
||||
@@ -248,6 +273,8 @@ describe "ThemeManager", ->
|
||||
themeManager.loadUserStylesheet.callCount is 2
|
||||
|
||||
runs ->
|
||||
expect(stylesheetRemovedHandler).toHaveBeenCalled()
|
||||
expect(stylesheetRemovedHandler.argsForCall[0][0].cssRules[0].style.border).toBe 'dashed'
|
||||
expect($(document.body).css('border-style')).toBe 'none'
|
||||
expect(stylesheetsChangedHandler).toHaveBeenCalled()
|
||||
|
||||
|
||||
@@ -6,7 +6,7 @@ describe "TokenizedLine", ->
|
||||
|
||||
describe "::getScopeTree()", ->
|
||||
it "returns a tree whose inner nodes are scopes and whose leaf nodes are tokens in those scopes", ->
|
||||
editor = atom.project.openSync('coffee.coffee')
|
||||
[tokens, tokenIndex] = []
|
||||
|
||||
ensureValidScopeTree = (scopeTree, scopes=[]) ->
|
||||
if scopeTree.children?
|
||||
@@ -16,7 +16,11 @@ describe "TokenizedLine", ->
|
||||
expect(scopeTree).toBe tokens[tokenIndex++]
|
||||
expect(scopes).toEqual scopeTree.scopes
|
||||
|
||||
tokenIndex = 0
|
||||
tokens = editor.lineForScreenRow(1).tokens
|
||||
scopeTree = editor.lineForScreenRow(1).getScopeTree()
|
||||
ensureValidScopeTree(scopeTree)
|
||||
waitsForPromise ->
|
||||
atom.project.open('coffee.coffee').then (o) -> editor = o
|
||||
|
||||
runs ->
|
||||
tokenIndex = 0
|
||||
tokens = editor.lineForScreenRow(1).tokens
|
||||
scopeTree = editor.lineForScreenRow(1).getScopeTree()
|
||||
ensureValidScopeTree(scopeTree)
|
||||
|
||||
+37
-20
@@ -64,27 +64,41 @@ describe "Window", ->
|
||||
|
||||
describe "when pane items are are modified", ->
|
||||
it "prompts user to save and and calls workspaceView.confirmClose", ->
|
||||
editor = null
|
||||
spyOn(atom.workspaceView, 'confirmClose').andCallThrough()
|
||||
spyOn(atom, "confirm").andReturn(2)
|
||||
editor = atom.workspaceView.openSync("sample.js")
|
||||
editor.insertText("I look different, I feel different.")
|
||||
$(window).trigger(beforeUnloadEvent)
|
||||
expect(atom.workspaceView.confirmClose).toHaveBeenCalled()
|
||||
expect(atom.confirm).toHaveBeenCalled()
|
||||
|
||||
waitsForPromise ->
|
||||
atom.workspace.open("sample.js").then (o) -> editor = o
|
||||
|
||||
runs ->
|
||||
editor.insertText("I look different, I feel different.")
|
||||
$(window).trigger(beforeUnloadEvent)
|
||||
expect(atom.workspaceView.confirmClose).toHaveBeenCalled()
|
||||
expect(atom.confirm).toHaveBeenCalled()
|
||||
|
||||
it "prompts user to save and handler returns true if don't save", ->
|
||||
editor = null
|
||||
spyOn(atom, "confirm").andReturn(2)
|
||||
editor = atom.workspaceView.openSync("sample.js")
|
||||
editor.insertText("I look different, I feel different.")
|
||||
$(window).trigger(beforeUnloadEvent)
|
||||
expect(atom.confirm).toHaveBeenCalled()
|
||||
|
||||
waitsForPromise ->
|
||||
atom.workspace.open("sample.js").then (o) -> editor = o
|
||||
|
||||
runs ->
|
||||
editor.insertText("I look different, I feel different.")
|
||||
$(window).trigger(beforeUnloadEvent)
|
||||
expect(atom.confirm).toHaveBeenCalled()
|
||||
|
||||
it "prompts user to save and handler returns false if dialog is canceled", ->
|
||||
editor = null
|
||||
spyOn(atom, "confirm").andReturn(1)
|
||||
editor = atom.workspaceView.openSync("sample.js")
|
||||
editor.insertText("I look different, I feel different.")
|
||||
$(window).trigger(beforeUnloadEvent)
|
||||
expect(atom.confirm).toHaveBeenCalled()
|
||||
waitsForPromise ->
|
||||
atom.workspace.open("sample.js").then (o) -> editor = o
|
||||
|
||||
runs ->
|
||||
editor.insertText("I look different, I feel different.")
|
||||
$(window).trigger(beforeUnloadEvent)
|
||||
expect(atom.confirm).toHaveBeenCalled()
|
||||
|
||||
describe ".unloadEditorWindow()", ->
|
||||
it "saves the serialized state of the window so it can be deserialized after reload", ->
|
||||
@@ -100,15 +114,18 @@ describe "Window", ->
|
||||
expect(atom.saveSync).toHaveBeenCalled()
|
||||
|
||||
it "unsubscribes from all buffers", ->
|
||||
atom.workspaceView.openSync('sample.js')
|
||||
buffer = atom.workspaceView.getActivePaneItem().buffer
|
||||
pane = atom.workspaceView.getActivePaneView()
|
||||
pane.splitRight(pane.copyActiveItem())
|
||||
expect(atom.workspaceView.find('.editor').length).toBe 2
|
||||
waitsForPromise ->
|
||||
atom.workspace.open("sample.js")
|
||||
|
||||
atom.unloadEditorWindow()
|
||||
runs ->
|
||||
buffer = atom.workspace.getActivePaneItem().buffer
|
||||
pane = atom.workspaceView.getActivePaneView()
|
||||
pane.splitRight(pane.copyActiveItem())
|
||||
expect(atom.workspaceView.find('.editor').length).toBe 2
|
||||
|
||||
expect(buffer.getSubscriptionCount()).toBe 0
|
||||
atom.unloadEditorWindow()
|
||||
|
||||
expect(buffer.getSubscriptionCount()).toBe 0
|
||||
|
||||
describe "drag and drop", ->
|
||||
buildDragEvent = (type, files) ->
|
||||
|
||||
+109
-80
@@ -37,12 +37,17 @@ describe "Workspace", ->
|
||||
describe "when called with a uri", ->
|
||||
describe "when the active pane already has an editor for the given uri", ->
|
||||
it "activates the existing editor on the active pane", ->
|
||||
editor1 = workspace.openSync('a')
|
||||
editor2 = workspace.openSync('b')
|
||||
|
||||
editor = null
|
||||
editor1 = null
|
||||
editor2 = null
|
||||
|
||||
waitsForPromise ->
|
||||
workspace.open('a').then (o) -> editor = o
|
||||
workspace.open('a').then (o) ->
|
||||
editor1 = o
|
||||
workspace.open('b').then (o) ->
|
||||
editor2 = o
|
||||
workspace.open('a').then (o) ->
|
||||
editor = o
|
||||
|
||||
runs ->
|
||||
expect(editor).toBe editor1
|
||||
@@ -64,11 +69,21 @@ describe "Workspace", ->
|
||||
describe "when the 'searchAllPanes' option is true", ->
|
||||
describe "when an editor for the given uri is already open on an inactive pane", ->
|
||||
it "activates the existing editor on the inactive pane, then activates that pane", ->
|
||||
editor1 = workspace.openSync('a')
|
||||
pane1 = workspace.activePane
|
||||
pane2 = workspace.activePane.splitRight()
|
||||
editor2 = workspace.openSync('b')
|
||||
expect(workspace.activePaneItem).toBe editor2
|
||||
editor1 = null
|
||||
editor2 = null
|
||||
pane1 = workspace.getActivePane()
|
||||
pane2 = workspace.getActivePane().splitRight()
|
||||
|
||||
waitsForPromise ->
|
||||
pane1.activate()
|
||||
workspace.open('a').then (o) -> editor1 = o
|
||||
|
||||
waitsForPromise ->
|
||||
pane2.activate()
|
||||
workspace.open('b').then (o) -> editor2 = o
|
||||
|
||||
runs ->
|
||||
expect(workspace.activePaneItem).toBe editor2
|
||||
|
||||
waitsForPromise ->
|
||||
workspace.open('a', searchAllPanes: true)
|
||||
@@ -112,6 +127,22 @@ describe "Workspace", ->
|
||||
expect(pane1.items).toEqual [editor]
|
||||
expect(pane2.items).toEqual []
|
||||
|
||||
describe "when a pane axis is the leftmost sibling of the current pane", ->
|
||||
it "opens the new item in the current pane", ->
|
||||
editor = null
|
||||
pane1 = workspace.activePane
|
||||
pane2 = pane1.splitLeft()
|
||||
pane3 = pane2.splitDown()
|
||||
pane1.activate()
|
||||
expect(workspace.activePane).toBe pane1
|
||||
|
||||
waitsForPromise ->
|
||||
workspace.open('a', split: 'left').then (o) -> editor = o
|
||||
|
||||
runs ->
|
||||
expect(workspace.activePane).toBe pane1
|
||||
expect(pane1.items).toEqual [editor]
|
||||
|
||||
describe "when the 'split' option is 'right'", ->
|
||||
it "opens the editor in the rightmost pane of the current pane axis", ->
|
||||
editor = null
|
||||
@@ -136,6 +167,26 @@ describe "Workspace", ->
|
||||
expect(pane1.items).toEqual []
|
||||
expect(pane2.items).toEqual [editor]
|
||||
|
||||
describe "when a pane axis is the rightmost sibling of the current pane", ->
|
||||
it "opens the new item in a new pane split to the right of the current pane", ->
|
||||
editor = null
|
||||
pane1 = workspace.activePane
|
||||
pane2 = pane1.splitRight()
|
||||
pane3 = pane2.splitDown()
|
||||
pane1.activate()
|
||||
expect(workspace.activePane).toBe pane1
|
||||
pane4 = null
|
||||
|
||||
waitsForPromise ->
|
||||
workspace.open('a', split: 'right').then (o) -> editor = o
|
||||
|
||||
runs ->
|
||||
pane4 = workspace.getPanes().filter((p) -> p != pane1)[0]
|
||||
expect(workspace.activePane).toBe pane4
|
||||
expect(pane4.items).toEqual [editor]
|
||||
expect(workspace.paneContainer.root.children[0]).toBe pane1
|
||||
expect(workspace.paneContainer.root.children[1]).toBe pane4
|
||||
|
||||
describe "when passed a path that matches a custom opener", ->
|
||||
it "returns the resource returned by the custom opener", ->
|
||||
fooOpener = (pathToOpen, options) -> { foo: pathToOpen, options } if pathToOpen?.match(/\.foo/)
|
||||
@@ -164,80 +215,55 @@ describe "Workspace", ->
|
||||
runs ->
|
||||
expect(newEditorHandler).toHaveBeenCalledWith editor
|
||||
|
||||
describe "::openSync(uri, options)", ->
|
||||
[activePane, initialItemCount] = []
|
||||
|
||||
beforeEach ->
|
||||
activePane = workspace.activePane
|
||||
spyOn(activePane, 'activate')
|
||||
initialItemCount = activePane.items.length
|
||||
|
||||
describe "when called without a uri", ->
|
||||
it "adds and activates an empty editor on the active pane", ->
|
||||
editor = workspace.openSync()
|
||||
expect(activePane.items.length).toBe initialItemCount + 1
|
||||
expect(activePane.activeItem).toBe editor
|
||||
expect(editor.getPath()).toBeUndefined()
|
||||
expect(activePane.activate).toHaveBeenCalled()
|
||||
|
||||
describe "when called with a uri", ->
|
||||
describe "when the active pane already has an editor for the given uri", ->
|
||||
it "activates the existing editor on the active pane", ->
|
||||
editor1 = workspace.openSync('a')
|
||||
editor2 = workspace.openSync('b')
|
||||
expect(activePane.activeItem).toBe editor2
|
||||
expect(activePane.items.length).toBe 2
|
||||
|
||||
editor = workspace.openSync(editor1.getPath())
|
||||
expect(editor).toBe editor1
|
||||
expect(activePane.activeItem).toBe editor
|
||||
expect(activePane.activate).toHaveBeenCalled()
|
||||
expect(activePane.items.length).toBe 2
|
||||
|
||||
describe "when the active pane does not have an editor for the given uri", ->
|
||||
it "adds and activates a new editor for the given path on the active pane", ->
|
||||
editor = workspace.openSync('a')
|
||||
expect(activePane.items.length).toBe 1
|
||||
expect(activePane.activeItem).toBe editor
|
||||
expect(activePane.activate).toHaveBeenCalled()
|
||||
|
||||
describe "when the 'activatePane' option is false", ->
|
||||
it "does not activate the active pane", ->
|
||||
workspace.openSync('b', activatePane: false)
|
||||
expect(activePane.activate).not.toHaveBeenCalled()
|
||||
|
||||
describe "::reopenItemSync()", ->
|
||||
describe "::reopenItem()", ->
|
||||
it "opens the uri associated with the last closed pane that isn't currently open", ->
|
||||
pane = workspace.activePane
|
||||
workspace.openSync('a')
|
||||
workspace.openSync('b')
|
||||
workspace.openSync('file1')
|
||||
workspace.openSync()
|
||||
waitsForPromise ->
|
||||
workspace.open('a').then ->
|
||||
workspace.open('b').then ->
|
||||
workspace.open('file1').then ->
|
||||
workspace.open()
|
||||
|
||||
# does not reopen items with no uri
|
||||
expect(workspace.activePaneItem.getUri()).toBeUndefined()
|
||||
pane.destroyActiveItem()
|
||||
workspace.reopenItemSync()
|
||||
expect(workspace.activePaneItem.getUri()).not.toBeUndefined()
|
||||
runs ->
|
||||
# does not reopen items with no uri
|
||||
expect(workspace.activePaneItem.getUri()).toBeUndefined()
|
||||
pane.destroyActiveItem()
|
||||
|
||||
# destroy all items
|
||||
expect(workspace.activePaneItem.getUri()).toBe atom.project.resolve('file1')
|
||||
pane.destroyActiveItem()
|
||||
expect(workspace.activePaneItem.getUri()).toBe atom.project.resolve('b')
|
||||
pane.destroyActiveItem()
|
||||
expect(workspace.activePaneItem.getUri()).toBe atom.project.resolve('a')
|
||||
pane.destroyActiveItem()
|
||||
waitsForPromise ->
|
||||
workspace.reopenItem()
|
||||
|
||||
# reopens items with uris
|
||||
expect(workspace.activePaneItem).toBeUndefined()
|
||||
workspace.reopenItemSync()
|
||||
expect(workspace.activePaneItem.getUri()).toBe atom.project.resolve('a')
|
||||
runs ->
|
||||
expect(workspace.activePaneItem.getUri()).not.toBeUndefined()
|
||||
|
||||
# destroy all items
|
||||
expect(workspace.activePaneItem.getUri()).toBe atom.project.resolve('file1')
|
||||
pane.destroyActiveItem()
|
||||
expect(workspace.activePaneItem.getUri()).toBe atom.project.resolve('b')
|
||||
pane.destroyActiveItem()
|
||||
expect(workspace.activePaneItem.getUri()).toBe atom.project.resolve('a')
|
||||
pane.destroyActiveItem()
|
||||
|
||||
# reopens items with uris
|
||||
expect(workspace.activePaneItem).toBeUndefined()
|
||||
|
||||
waitsForPromise ->
|
||||
workspace.reopenItem()
|
||||
|
||||
runs ->
|
||||
expect(workspace.activePaneItem.getUri()).toBe atom.project.resolve('a')
|
||||
|
||||
# does not reopen items that are already open
|
||||
workspace.openSync('b')
|
||||
expect(workspace.activePaneItem.getUri()).toBe atom.project.resolve('b')
|
||||
workspace.reopenItemSync()
|
||||
expect(workspace.activePaneItem.getUri()).toBe atom.project.resolve('file1')
|
||||
waitsForPromise ->
|
||||
workspace.open('b')
|
||||
|
||||
runs ->
|
||||
expect(workspace.activePaneItem.getUri()).toBe atom.project.resolve('b')
|
||||
|
||||
waitsForPromise ->
|
||||
workspace.reopenItem()
|
||||
|
||||
runs ->
|
||||
expect(workspace.activePaneItem.getUri()).toBe atom.project.resolve('file1')
|
||||
|
||||
describe "::increase/decreaseFontSize()", ->
|
||||
it "increases/decreases the font size without going below 1", ->
|
||||
@@ -272,11 +298,14 @@ describe "Workspace", ->
|
||||
|
||||
describe "when an editor is copied", ->
|
||||
it "emits an 'editor-created' event", ->
|
||||
editor = null
|
||||
handler = jasmine.createSpy('editorCreatedHandler')
|
||||
workspace.on 'editor-created', handler
|
||||
|
||||
editor1 = workspace.openSync("a")
|
||||
expect(handler.callCount).toBe 1
|
||||
waitsForPromise ->
|
||||
workspace.open("a").then (o) -> editor = o
|
||||
|
||||
editor2 = editor1.copy()
|
||||
expect(handler.callCount).toBe 2
|
||||
runs ->
|
||||
expect(handler.callCount).toBe 1
|
||||
editorCopy = editor.copy()
|
||||
expect(handler.callCount).toBe 2
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
Q = require 'q'
|
||||
path = require 'path'
|
||||
temp = require 'temp'
|
||||
EditorView = require '../src/editor-view'
|
||||
PaneView = require '../src/pane-view'
|
||||
Workspace = require '../src/workspace'
|
||||
|
||||
@@ -14,9 +15,12 @@ describe "WorkspaceView", ->
|
||||
atom.workspace = new Workspace
|
||||
atom.workspaceView = new WorkspaceView(atom.workspace)
|
||||
atom.workspaceView.enableKeymap()
|
||||
atom.workspaceView.openSync(pathToOpen)
|
||||
atom.workspaceView.focus()
|
||||
|
||||
waitsForPromise ->
|
||||
atom.workspace.open(pathToOpen)
|
||||
|
||||
|
||||
describe "@deserialize()", ->
|
||||
viewState = null
|
||||
|
||||
@@ -32,17 +36,21 @@ describe "WorkspaceView", ->
|
||||
describe "when the serialized WorkspaceView has an unsaved buffer", ->
|
||||
it "constructs the view with the same panes", ->
|
||||
atom.workspaceView.attachToDom()
|
||||
atom.workspaceView.openSync()
|
||||
editorView1 = atom.workspaceView.getActiveView()
|
||||
buffer = editorView1.getEditor().getBuffer()
|
||||
editorView1.splitRight()
|
||||
expect(atom.workspaceView.getActivePaneView()).toBe atom.workspaceView.getPaneViews()[1]
|
||||
|
||||
simulateReload()
|
||||
waitsForPromise ->
|
||||
atom.workspace.open()
|
||||
|
||||
expect(atom.workspaceView.getEditorViews().length).toBe 2
|
||||
expect(atom.workspaceView.getActivePaneView()).toBe atom.workspaceView.getPaneViews()[1]
|
||||
expect(atom.workspaceView.title).toBe "untitled - #{atom.project.getPath()}"
|
||||
runs ->
|
||||
editorView1 = atom.workspaceView.getActiveView()
|
||||
buffer = editorView1.getEditor().getBuffer()
|
||||
editorView1.splitRight()
|
||||
expect(atom.workspaceView.getActivePaneView()).toBe atom.workspaceView.getPaneViews()[1]
|
||||
|
||||
simulateReload()
|
||||
|
||||
expect(atom.workspaceView.getEditorViews().length).toBe 2
|
||||
expect(atom.workspaceView.getActivePaneView()).toBe atom.workspaceView.getPaneViews()[1]
|
||||
expect(atom.workspaceView.title).toBe "untitled - #{atom.project.getPath()}"
|
||||
|
||||
describe "when there are open editors", ->
|
||||
it "constructs the view with the same panes", ->
|
||||
@@ -50,42 +58,56 @@ describe "WorkspaceView", ->
|
||||
pane1 = atom.workspaceView.getActivePaneView()
|
||||
pane2 = pane1.splitRight()
|
||||
pane3 = pane2.splitRight()
|
||||
pane4 = pane2.splitDown()
|
||||
pane2.activateItem(atom.project.openSync('b'))
|
||||
pane3.activateItem(atom.project.openSync('../sample.js'))
|
||||
pane3.activeItem.setCursorScreenPosition([2, 4])
|
||||
pane4.activateItem(atom.project.openSync('../sample.txt'))
|
||||
pane4.activeItem.setCursorScreenPosition([0, 2])
|
||||
pane2.focus()
|
||||
pane4 = null
|
||||
|
||||
simulateReload()
|
||||
waitsForPromise ->
|
||||
atom.workspace.open('b').then (editor) ->
|
||||
pane2.activateItem(editor)
|
||||
|
||||
expect(atom.workspaceView.getEditorViews().length).toBe 4
|
||||
editorView1 = atom.workspaceView.panes.find('.pane-row > .pane .editor:eq(0)').view()
|
||||
editorView3 = atom.workspaceView.panes.find('.pane-row > .pane .editor:eq(1)').view()
|
||||
editorView2 = atom.workspaceView.panes.find('.pane-row > .pane-column > .pane .editor:eq(0)').view()
|
||||
editorView4 = atom.workspaceView.panes.find('.pane-row > .pane-column > .pane .editor:eq(1)').view()
|
||||
waitsForPromise ->
|
||||
atom.workspace.open('../sample.js').then (editor) ->
|
||||
pane3.activateItem(editor)
|
||||
|
||||
expect(editorView1.getEditor().getPath()).toBe atom.project.resolve('a')
|
||||
expect(editorView2.getEditor().getPath()).toBe atom.project.resolve('b')
|
||||
expect(editorView3.getEditor().getPath()).toBe atom.project.resolve('../sample.js')
|
||||
expect(editorView3.getEditor().getCursorScreenPosition()).toEqual [2, 4]
|
||||
expect(editorView4.getEditor().getPath()).toBe atom.project.resolve('../sample.txt')
|
||||
expect(editorView4.getEditor().getCursorScreenPosition()).toEqual [0, 2]
|
||||
runs ->
|
||||
pane3.activeItem.setCursorScreenPosition([2, 4])
|
||||
pane4 = pane2.splitDown()
|
||||
|
||||
# ensure adjust pane dimensions is called
|
||||
expect(editorView1.width()).toBeGreaterThan 0
|
||||
expect(editorView2.width()).toBeGreaterThan 0
|
||||
expect(editorView3.width()).toBeGreaterThan 0
|
||||
expect(editorView4.width()).toBeGreaterThan 0
|
||||
waitsForPromise ->
|
||||
atom.workspace.open('../sample.txt').then (editor) ->
|
||||
pane4.activateItem(editor)
|
||||
|
||||
# ensure correct editorView is focused again
|
||||
expect(editorView2.isFocused).toBeTruthy()
|
||||
expect(editorView1.isFocused).toBeFalsy()
|
||||
expect(editorView3.isFocused).toBeFalsy()
|
||||
expect(editorView4.isFocused).toBeFalsy()
|
||||
runs ->
|
||||
pane4.activeItem.setCursorScreenPosition([0, 2])
|
||||
pane2.focus()
|
||||
|
||||
expect(atom.workspaceView.title).toBe "#{path.basename(editorView2.getEditor().getPath())} - #{atom.project.getPath()}"
|
||||
simulateReload()
|
||||
|
||||
expect(atom.workspaceView.getEditorViews().length).toBe 4
|
||||
editorView1 = atom.workspaceView.panes.find('.pane-row > .pane .editor:eq(0)').view()
|
||||
editorView3 = atom.workspaceView.panes.find('.pane-row > .pane .editor:eq(1)').view()
|
||||
editorView2 = atom.workspaceView.panes.find('.pane-row > .pane-column > .pane .editor:eq(0)').view()
|
||||
editorView4 = atom.workspaceView.panes.find('.pane-row > .pane-column > .pane .editor:eq(1)').view()
|
||||
|
||||
expect(editorView1.getEditor().getPath()).toBe atom.project.resolve('a')
|
||||
expect(editorView2.getEditor().getPath()).toBe atom.project.resolve('b')
|
||||
expect(editorView3.getEditor().getPath()).toBe atom.project.resolve('../sample.js')
|
||||
expect(editorView3.getEditor().getCursorScreenPosition()).toEqual [2, 4]
|
||||
expect(editorView4.getEditor().getPath()).toBe atom.project.resolve('../sample.txt')
|
||||
expect(editorView4.getEditor().getCursorScreenPosition()).toEqual [0, 2]
|
||||
|
||||
# ensure adjust pane dimensions is called
|
||||
expect(editorView1.width()).toBeGreaterThan 0
|
||||
expect(editorView2.width()).toBeGreaterThan 0
|
||||
expect(editorView3.width()).toBeGreaterThan 0
|
||||
expect(editorView4.width()).toBeGreaterThan 0
|
||||
|
||||
# ensure correct editorView is focused again
|
||||
expect(editorView2).toHaveFocus()
|
||||
expect(editorView1).not.toHaveFocus()
|
||||
expect(editorView3).not.toHaveFocus()
|
||||
expect(editorView4).not.toHaveFocus()
|
||||
|
||||
expect(atom.workspaceView.title).toBe "#{path.basename(editorView2.getEditor().getPath())} - #{atom.project.getPath()}"
|
||||
|
||||
describe "where there are no open editors", ->
|
||||
it "constructs the view with no open editors", ->
|
||||
@@ -101,9 +123,9 @@ describe "WorkspaceView", ->
|
||||
it "hands off focus to the active pane", ->
|
||||
activePane = atom.workspaceView.getActivePaneView()
|
||||
$('body').focus()
|
||||
expect(activePane.hasFocus()).toBe false
|
||||
expect(activePane).not.toHaveFocus()
|
||||
atom.workspaceView.focus()
|
||||
expect(activePane.hasFocus()).toBe true
|
||||
expect(activePane).toHaveFocus()
|
||||
|
||||
describe "keymap wiring", ->
|
||||
commandHandler = null
|
||||
@@ -111,7 +133,7 @@ describe "WorkspaceView", ->
|
||||
commandHandler = jasmine.createSpy('commandHandler')
|
||||
atom.workspaceView.on('foo-command', commandHandler)
|
||||
|
||||
atom.keymaps.bindKeys('name', '*', 'x': 'foo-command')
|
||||
atom.keymaps.add('name', '*': {'x': 'foo-command'})
|
||||
|
||||
describe "when a keydown event is triggered in the WorkspaceView", ->
|
||||
it "triggers matching keybindings for that event", ->
|
||||
@@ -128,7 +150,8 @@ describe "WorkspaceView", ->
|
||||
|
||||
describe "when the project has a path", ->
|
||||
beforeEach ->
|
||||
atom.workspaceView.openSync('b')
|
||||
waitsForPromise ->
|
||||
atom.workspace.open('b')
|
||||
|
||||
describe "when there is an active pane item", ->
|
||||
it "sets the title to the pane item's title plus the project path", ->
|
||||
@@ -143,7 +166,7 @@ describe "WorkspaceView", ->
|
||||
|
||||
describe "when the active pane's item changes", ->
|
||||
it "updates the title to the new item's title plus the project path", ->
|
||||
atom.workspaceView.getActivePaneView().showNextItem()
|
||||
atom.workspaceView.getActivePaneView().activateNextItem()
|
||||
item = atom.workspace.getActivePaneItem()
|
||||
expect(atom.workspaceView.title).toBe "#{item.getTitle()} - #{atom.project.getPath()}"
|
||||
|
||||
@@ -158,7 +181,7 @@ describe "WorkspaceView", ->
|
||||
pane = atom.workspaceView.getActivePaneView()
|
||||
pane.splitRight()
|
||||
initialTitle = atom.workspaceView.title
|
||||
pane.showNextItem()
|
||||
pane.activateNextItem()
|
||||
expect(atom.workspaceView.title).toBe initialTitle
|
||||
|
||||
describe "when the root view is deserialized", ->
|
||||
@@ -222,6 +245,14 @@ describe "WorkspaceView", ->
|
||||
expect(count).toBe 1
|
||||
expect(callbackEditor).toBe atom.workspaceView.getActiveView()
|
||||
|
||||
it "does not invoke the callback for mini editors", ->
|
||||
editorViewCreatedHandler = jasmine.createSpy('editorViewCreatedHandler')
|
||||
atom.workspaceView.eachEditorView(editorViewCreatedHandler)
|
||||
editorViewCreatedHandler.reset()
|
||||
miniEditor = new EditorView(mini: true)
|
||||
atom.workspaceView.append(miniEditor)
|
||||
expect(editorViewCreatedHandler).not.toHaveBeenCalled()
|
||||
|
||||
it "returns a subscription that can be disabled", ->
|
||||
count = 0
|
||||
callback = (editor) -> count++
|
||||
@@ -237,10 +268,22 @@ describe "WorkspaceView", ->
|
||||
describe "core:close", ->
|
||||
it "closes the active pane item until all that remains is a single empty pane", ->
|
||||
atom.config.set('core.destroyEmptyPanes', true)
|
||||
atom.project.openSync('../sample.txt')
|
||||
expect(atom.workspaceView.getActivePaneView().getItems()).toHaveLength 1
|
||||
|
||||
paneView1 = atom.workspaceView.getActivePaneView()
|
||||
editorView = atom.workspaceView.getActiveView()
|
||||
editorView.splitRight()
|
||||
paneView2 = atom.workspaceView.getActivePaneView()
|
||||
|
||||
expect(paneView1).not.toBe paneView2
|
||||
expect(atom.workspaceView.getPaneViews()).toHaveLength 2
|
||||
atom.workspaceView.trigger('core:close')
|
||||
|
||||
expect(atom.workspaceView.getActivePaneView().getItems()).toHaveLength 1
|
||||
expect(atom.workspaceView.getPaneViews()).toHaveLength 1
|
||||
atom.workspaceView.trigger('core:close')
|
||||
|
||||
expect(atom.workspaceView.getActivePaneView().getItems()).toHaveLength 0
|
||||
expect(atom.workspaceView.getPaneViews()).toHaveLength 1
|
||||
|
||||
describe "the scrollbar visibility class", ->
|
||||
it "has a class based on the style of the scrollbar", ->
|
||||
|
||||
+14
-14
@@ -148,7 +148,7 @@ class Atom extends Model
|
||||
ThemeManager = require './theme-manager'
|
||||
ContextMenuManager = require './context-menu-manager'
|
||||
MenuManager = require './menu-manager'
|
||||
{devMode, resourcePath} = @getLoadSettings()
|
||||
{devMode, safeMode, resourcePath} = @getLoadSettings()
|
||||
configDirPath = @getConfigDirPath()
|
||||
|
||||
# Add 'src/exports' to module search path.
|
||||
@@ -163,7 +163,7 @@ class Atom extends Model
|
||||
@config = new Config({configDirPath, resourcePath})
|
||||
@keymaps = new KeymapManager({configDirPath, resourcePath})
|
||||
@keymap = @keymaps # Deprecated
|
||||
@packages = new PackageManager({devMode, configDirPath, resourcePath})
|
||||
@packages = new PackageManager({devMode, configDirPath, resourcePath, safeMode})
|
||||
@themes = new ThemeManager({packageManager: @packages, configDirPath, resourcePath})
|
||||
@contextMenu = new ContextMenuManager(devMode)
|
||||
@menu = new MenuManager({resourcePath})
|
||||
@@ -340,7 +340,7 @@ class Atom extends Model
|
||||
# options - An {Object} with the following keys:
|
||||
# :pathsToOpen - An {Array} of {String} paths to open.
|
||||
open: (options) ->
|
||||
ipc.sendChannel('open', options)
|
||||
ipc.send('open', options)
|
||||
|
||||
# Public: Open a confirm dialog.
|
||||
#
|
||||
@@ -394,50 +394,50 @@ class Atom extends Model
|
||||
|
||||
# Public: Open the dev tools for the current window.
|
||||
openDevTools: ->
|
||||
ipc.sendChannel('call-window-method', 'openDevTools')
|
||||
ipc.send('call-window-method', 'openDevTools')
|
||||
|
||||
# Public: Toggle the visibility of the dev tools for the current window.
|
||||
toggleDevTools: ->
|
||||
ipc.sendChannel('call-window-method', 'toggleDevTools')
|
||||
ipc.send('call-window-method', 'toggleDevTools')
|
||||
|
||||
# Public: Execute code in dev tools.
|
||||
executeJavaScriptInDevTools: (code) ->
|
||||
ipc.sendChannel('call-window-method', 'executeJavaScriptInDevTools', code)
|
||||
ipc.send('call-window-method', 'executeJavaScriptInDevTools', code)
|
||||
|
||||
# Public: Reload the current window.
|
||||
reload: ->
|
||||
ipc.sendChannel('call-window-method', 'restart')
|
||||
ipc.send('call-window-method', 'restart')
|
||||
|
||||
# Public: Focus the current window.
|
||||
focus: ->
|
||||
ipc.sendChannel('call-window-method', 'focus')
|
||||
ipc.send('call-window-method', 'focus')
|
||||
$(window).focus()
|
||||
|
||||
# Public: Show the current window.
|
||||
show: ->
|
||||
ipc.sendChannel('call-window-method', 'show')
|
||||
ipc.send('call-window-method', 'show')
|
||||
|
||||
# Public: Hide the current window.
|
||||
hide: ->
|
||||
ipc.sendChannel('call-window-method', 'hide')
|
||||
ipc.send('call-window-method', 'hide')
|
||||
|
||||
# Public: Set the size of current window.
|
||||
#
|
||||
# width - The {Number} of pixels.
|
||||
# height - The {Number} of pixels.
|
||||
setSize: (width, height) ->
|
||||
ipc.sendChannel('call-window-method', 'setSize', width, height)
|
||||
ipc.send('call-window-method', 'setSize', width, height)
|
||||
|
||||
# Public: Set the position of current window.
|
||||
#
|
||||
# x - The {Number} of pixels.
|
||||
# y - The {Number} of pixels.
|
||||
setPosition: (x, y) ->
|
||||
ipc.sendChannel('call-window-method', 'setPosition', x, y)
|
||||
ipc.send('call-window-method', 'setPosition', x, y)
|
||||
|
||||
# Public: Move current window to the center of the screen.
|
||||
center: ->
|
||||
ipc.sendChannel('call-window-method', 'center')
|
||||
ipc.send('call-window-method', 'center')
|
||||
|
||||
# Schedule the window to be shown and focused on the next tick.
|
||||
#
|
||||
@@ -472,7 +472,7 @@ class Atom extends Model
|
||||
|
||||
# Public: Set the full screen state of the current window.
|
||||
setFullScreen: (fullScreen=false) ->
|
||||
ipc.sendChannel('call-window-method', 'setFullScreen', fullScreen)
|
||||
ipc.send('call-window-method', 'setFullScreen', fullScreen)
|
||||
|
||||
# Public: Is the current window in full screen mode?
|
||||
isFullScreen: ->
|
||||
|
||||
@@ -59,7 +59,7 @@ class AtomApplication
|
||||
exit: (status) -> app.exit(status)
|
||||
|
||||
constructor: (options) ->
|
||||
{@resourcePath, @version, @devMode} = options
|
||||
{@resourcePath, @version, @devMode, @safeMode} = options
|
||||
global.atomApplication = this
|
||||
|
||||
@pidsToOpenWindows = {}
|
||||
@@ -77,15 +77,15 @@ class AtomApplication
|
||||
@openWithOptions(options)
|
||||
|
||||
# Opens a new window based on the options provided.
|
||||
openWithOptions: ({pathsToOpen, urlsToOpen, test, pidToKillWhenClosed, devMode, newWindow, specDirectory, logFile}) ->
|
||||
openWithOptions: ({pathsToOpen, urlsToOpen, test, pidToKillWhenClosed, devMode, safeMode, newWindow, specDirectory, logFile}) ->
|
||||
if test
|
||||
@runSpecs({exitWhenDone: true, @resourcePath, specDirectory, logFile})
|
||||
else if pathsToOpen.length > 0
|
||||
@openPaths({pathsToOpen, pidToKillWhenClosed, newWindow, devMode})
|
||||
@openPaths({pathsToOpen, pidToKillWhenClosed, newWindow, devMode, safeMode})
|
||||
else if urlsToOpen.length > 0
|
||||
@openUrl({urlToOpen, devMode}) for urlToOpen in urlsToOpen
|
||||
@openUrl({urlToOpen, devMode, safeMode}) for urlToOpen in urlsToOpen
|
||||
else
|
||||
@openPath({pidToKillWhenClosed, newWindow, devMode}) # Always open a editor window if this is the first instance of Atom.
|
||||
@openPath({pidToKillWhenClosed, newWindow, devMode, safeMode}) # Always open a editor window if this is the first instance of Atom.
|
||||
|
||||
# Public: Removes the {AtomWindow} from the global window list.
|
||||
removeWindow: (window) ->
|
||||
@@ -140,6 +140,7 @@ class AtomApplication
|
||||
@on 'application:open-file', -> @promptForPath(type: 'file')
|
||||
@on 'application:open-folder', -> @promptForPath(type: 'folder')
|
||||
@on 'application:open-dev', -> @promptForPath(devMode: true)
|
||||
@on 'application:open-safe', -> @promptForPath(safeMode: true)
|
||||
@on 'application:inspect', ({x,y, atomWindow}) ->
|
||||
atomWindow ?= @focusedWindow()
|
||||
atomWindow?.browserWindow.inspectElement(x, y)
|
||||
@@ -166,6 +167,7 @@ class AtomApplication
|
||||
@openPathOnEvent('application:open-your-keymap', 'atom://.atom/keymap')
|
||||
@openPathOnEvent('application:open-your-snippets', 'atom://.atom/snippets')
|
||||
@openPathOnEvent('application:open-your-stylesheet', 'atom://.atom/stylesheet')
|
||||
@openPathOnEvent('application:open-license', path.join(@resourcePath, 'LICENSE.md'))
|
||||
|
||||
app.on 'window-all-closed', ->
|
||||
app.quit() if process.platform in ['win32', 'linux']
|
||||
@@ -184,14 +186,14 @@ class AtomApplication
|
||||
|
||||
app.on 'open-url', (event, urlToOpen) =>
|
||||
event.preventDefault()
|
||||
@openUrl({urlToOpen, @devMode})
|
||||
@openUrl({urlToOpen, @devMode, @safeMode})
|
||||
|
||||
app.on 'activate-with-no-open-windows', (event) =>
|
||||
event.preventDefault()
|
||||
@emit('application:new-window')
|
||||
|
||||
# A request from the associated render process to open a new render process.
|
||||
ipc.on 'open', (processId, routingId, options) =>
|
||||
ipc.on 'open', (event, options) =>
|
||||
if options?
|
||||
if options.pathsToOpen?.length > 0
|
||||
@openPaths(options)
|
||||
@@ -200,21 +202,21 @@ class AtomApplication
|
||||
else
|
||||
@promptForPath()
|
||||
|
||||
ipc.on 'update-application-menu', (processId, routingId, template, keystrokesByCommand) =>
|
||||
ipc.on 'update-application-menu', (event, template, keystrokesByCommand) =>
|
||||
@applicationMenu.update(template, keystrokesByCommand)
|
||||
|
||||
ipc.on 'run-package-specs', (processId, routingId, specDirectory) =>
|
||||
ipc.on 'run-package-specs', (event, specDirectory) =>
|
||||
@runSpecs({resourcePath: global.devResourcePath, specDirectory: specDirectory, exitWhenDone: false})
|
||||
|
||||
ipc.on 'command', (processId, routingId, command) =>
|
||||
ipc.on 'command', (event, command) =>
|
||||
@emit(command)
|
||||
|
||||
ipc.on 'window-command', (processId, routingId, command, args...) ->
|
||||
win = BrowserWindow.fromProcessIdAndRoutingId(processId, routingId)
|
||||
ipc.on 'window-command', (event, command, args...) ->
|
||||
win = BrowserWindow.fromWebContents(event.sender)
|
||||
win.emit(command, args...)
|
||||
|
||||
ipc.on 'call-window-method', (processId, routingId, method, args...) ->
|
||||
win = BrowserWindow.fromProcessIdAndRoutingId(processId, routingId)
|
||||
ipc.on 'call-window-method', (event, method, args...) ->
|
||||
win = BrowserWindow.fromWebContents(event.sender)
|
||||
win[method](args...)
|
||||
|
||||
# Public: Executes the given command.
|
||||
@@ -288,8 +290,10 @@ class AtomApplication
|
||||
# :pidToKillWhenClosed - The integer of the pid to kill
|
||||
# :newWindow - Boolean of whether this should be opened in a new window.
|
||||
# :devMode - Boolean to control the opened window's dev mode.
|
||||
openPaths: ({pathsToOpen, pidToKillWhenClosed, newWindow, devMode}) ->
|
||||
@openPath({pathToOpen, pidToKillWhenClosed, newWindow, devMode}) for pathToOpen in pathsToOpen ? []
|
||||
# :safeMode - Boolean to control the opened window's safe mode.
|
||||
openPaths: ({pathsToOpen, pidToKillWhenClosed, newWindow, devMode, safeMode}) ->
|
||||
for pathToOpen in pathsToOpen ? []
|
||||
@openPath({pathToOpen, pidToKillWhenClosed, newWindow, devMode, safeMode})
|
||||
|
||||
# Public: Opens a single path, in an existing window if possible.
|
||||
#
|
||||
@@ -298,13 +302,16 @@ class AtomApplication
|
||||
# :pidToKillWhenClosed - The integer of the pid to kill
|
||||
# :newWindow - Boolean of whether this should be opened in a new window.
|
||||
# :devMode - Boolean to control the opened window's dev mode.
|
||||
# :safeMode - Boolean to control the opened window's safe mode.
|
||||
# :windowDimensions - Object with height and width keys.
|
||||
openPath: ({pathToOpen, pidToKillWhenClosed, newWindow, devMode, windowDimensions}={}) ->
|
||||
openPath: ({pathToOpen, pidToKillWhenClosed, newWindow, devMode, safeMode, windowDimensions}={}) ->
|
||||
if pathToOpen
|
||||
[basename, initialLine] = path.basename(pathToOpen).split(':')
|
||||
if initialLine
|
||||
pathToOpen = "#{path.dirname(pathToOpen)}/#{basename}"
|
||||
initialLine -= 1 # Convert line numbers to a base of 0
|
||||
[basename, initialLine, initialColumn] = path.basename(pathToOpen).split(':')
|
||||
pathToOpen = path.join(path.dirname(pathToOpen), basename) if initialLine
|
||||
|
||||
# Convert line numbers to a base of 0
|
||||
initialLine -= 1 if initialLine
|
||||
initialColumn -= 1 if initialColumn
|
||||
|
||||
unless devMode
|
||||
existingWindow = @windowForPath(pathToOpen) unless pidToKillWhenClosed or newWindow
|
||||
@@ -320,12 +327,12 @@ class AtomApplication
|
||||
|
||||
bootstrapScript ?= require.resolve('../window-bootstrap')
|
||||
resourcePath ?= @resourcePath
|
||||
openedWindow = new AtomWindow({pathToOpen, initialLine, bootstrapScript, resourcePath, devMode, windowDimensions})
|
||||
openedWindow = new AtomWindow({pathToOpen, initialLine, initialColumn, bootstrapScript, resourcePath, devMode, safeMode, windowDimensions})
|
||||
|
||||
if pidToKillWhenClosed?
|
||||
@pidsToOpenWindows[pidToKillWhenClosed] = openedWindow
|
||||
|
||||
openedWindow.browserWindow.on 'destroyed', =>
|
||||
openedWindow.browserWindow.on 'closed', =>
|
||||
@killProcessForWindow(openedWindow)
|
||||
|
||||
# Kill all processes associated with opened windows.
|
||||
@@ -355,7 +362,8 @@ class AtomApplication
|
||||
# options -
|
||||
# :urlToOpen - The atom:// url to open.
|
||||
# :devMode - Boolean to control the opened window's dev mode.
|
||||
openUrl: ({urlToOpen, devMode}) ->
|
||||
# :safeMode - Boolean to control the opened window's safe mode.
|
||||
openUrl: ({urlToOpen, devMode, safeMode}) ->
|
||||
unless @packages?
|
||||
PackageManager = require '../package-manager'
|
||||
fs = require 'fs-plus'
|
||||
@@ -371,7 +379,7 @@ class AtomApplication
|
||||
packagePath = @packages.resolvePackagePath(packageName)
|
||||
bootstrapScript = path.resolve(packagePath, pack.urlMain)
|
||||
windowDimensions = @focusedWindow()?.getDimensions()
|
||||
new AtomWindow({bootstrapScript, @resourcePath, devMode, urlToOpen, windowDimensions})
|
||||
new AtomWindow({bootstrapScript, @resourcePath, devMode, safeMode, urlToOpen, windowDimensions})
|
||||
else
|
||||
console.log "Package '#{pack.name}' does not have a url main: #{urlToOpen}"
|
||||
else
|
||||
@@ -414,8 +422,10 @@ class AtomApplication
|
||||
# :type - A String which specifies the type of the dialog, could be 'file',
|
||||
# 'folder' or 'all'. The 'all' is only available on OS X.
|
||||
# :devMode - A Boolean which controls whether any newly opened windows
|
||||
# should be in dev mode or not.
|
||||
promptForPath: ({type, devMode}={}) ->
|
||||
# should be in dev mode or not.
|
||||
# :safeMode - A Boolean which controls whether any newly opened windows
|
||||
# should be in safe mode or not.
|
||||
promptForPath: ({type, devMode, safeMode}={}) ->
|
||||
type ?= 'all'
|
||||
properties =
|
||||
switch type
|
||||
@@ -424,4 +434,4 @@ class AtomApplication
|
||||
when 'all' then ['openFile', 'openDirectory']
|
||||
else throw new Error("#{type} is an invalid type for promptForPath")
|
||||
dialog.showOpenDialog title: 'Open', properties: properties.concat(['multiSelections', 'createDirectory']), (pathsToOpen) =>
|
||||
@openPaths({pathsToOpen, devMode})
|
||||
@openPaths({pathsToOpen, devMode, safeMode})
|
||||
|
||||
@@ -2,7 +2,6 @@ BrowserWindow = require 'browser-window'
|
||||
ContextMenu = require './context-menu'
|
||||
app = require 'app'
|
||||
dialog = require 'dialog'
|
||||
ipc = require 'ipc'
|
||||
path = require 'path'
|
||||
fs = require 'fs'
|
||||
url = require 'url'
|
||||
@@ -21,7 +20,7 @@ class AtomWindow
|
||||
isSpec: null
|
||||
|
||||
constructor: (settings={}) ->
|
||||
{@resourcePath, pathToOpen, initialLine, @isSpec, @exitWhenDone} = settings
|
||||
{@resourcePath, pathToOpen, initialLine, initialColumn, @isSpec, @exitWhenDone} = settings
|
||||
global.atomApplication.addWindow(this)
|
||||
|
||||
@browserWindow = new BrowserWindow show: false, title: 'Atom', icon: @constructor.iconPath
|
||||
@@ -48,7 +47,7 @@ class AtomWindow
|
||||
@browserWindow.loadUrl @getUrl(loadSettings)
|
||||
@browserWindow.focusOnWebView() if @isSpec
|
||||
|
||||
@openPath(pathToOpen, initialLine)
|
||||
@openPath(pathToOpen, initialLine, initialColumn)
|
||||
|
||||
getUrl: (loadSettingsObj) ->
|
||||
# Ignore the windowState when passing loadSettings via URL, since it could
|
||||
@@ -81,7 +80,7 @@ class AtomWindow
|
||||
false
|
||||
|
||||
handleEvents: ->
|
||||
@browserWindow.on 'destroyed', =>
|
||||
@browserWindow.on 'closed', =>
|
||||
global.atomApplication.removeWindow(this)
|
||||
|
||||
@browserWindow.on 'unresponsive', =>
|
||||
@@ -94,7 +93,7 @@ class AtomWindow
|
||||
detail: 'The editor is not responding. Would you like to force close it or just keep waiting?'
|
||||
@browserWindow.destroy() if chosen is 0
|
||||
|
||||
@browserWindow.on 'crashed', =>
|
||||
@browserWindow.webContents.on 'crashed', =>
|
||||
global.atomApplication.exit(100) if @exitWhenDone
|
||||
|
||||
chosen = dialog.showMessageBox @browserWindow,
|
||||
@@ -114,12 +113,12 @@ class AtomWindow
|
||||
@browserWindow.on 'blur', =>
|
||||
@browserWindow.focusOnWebView()
|
||||
|
||||
openPath: (pathToOpen, initialLine) ->
|
||||
openPath: (pathToOpen, initialLine, initialColumn) ->
|
||||
if @loaded
|
||||
@focus()
|
||||
@sendCommand('window:open-path', {pathToOpen, initialLine})
|
||||
@sendCommand('window:open-path', {pathToOpen, initialLine, initialColumn})
|
||||
else
|
||||
@browserWindow.once 'window:loaded', => @openPath(pathToOpen, initialLine)
|
||||
@browserWindow.once 'window:loaded', => @openPath(pathToOpen, initialLine, initialColumn)
|
||||
|
||||
sendCommand: (command, args...) ->
|
||||
if @isSpecWindow()
|
||||
@@ -136,7 +135,7 @@ class AtomWindow
|
||||
|
||||
sendCommandToBrowserWindow: (command, args...) ->
|
||||
action = if args[0]?.contextCommand then 'context-command' else 'command'
|
||||
ipc.sendChannel @browserWindow.getProcessId(), @browserWindow.getRoutingId(), action, command, args...
|
||||
@browserWindow.webContents.send action, command, args...
|
||||
|
||||
getDimensions: ->
|
||||
[x, y] = @browserWindow.getPosition()
|
||||
|
||||
@@ -73,6 +73,7 @@ parseCommandLine = ->
|
||||
options.alias('l', 'log-file').string('l').describe('l', 'Log all output to file.')
|
||||
options.alias('n', 'new-window').boolean('n').describe('n', 'Open a new window.')
|
||||
options.alias('s', 'spec-directory').string('s').describe('s', 'Set the spec directory (default: Atom\'s spec directory).')
|
||||
options.boolean('safe').describe('safe', 'Do not load packages from ~/.atom/packages or ~/.atom/dev/packages.')
|
||||
options.alias('t', 'test').boolean('t').describe('t', 'Run the specified specs and exit with error code on failures.')
|
||||
options.alias('v', 'version').boolean('v').describe('v', 'Print the version.')
|
||||
options.alias('w', 'wait').boolean('w').describe('w', 'Wait for window to be closed before returning.')
|
||||
@@ -88,6 +89,7 @@ parseCommandLine = ->
|
||||
|
||||
executedFrom = args['executed-from']
|
||||
devMode = args['dev']
|
||||
safeMode = args['safe']
|
||||
pathsToOpen = args._
|
||||
pathsToOpen = [executedFrom] if executedFrom and pathsToOpen.length is 0
|
||||
test = args['test']
|
||||
@@ -107,6 +109,6 @@ parseCommandLine = ->
|
||||
catch
|
||||
resourcePath = path.dirname(path.dirname(__dirname))
|
||||
|
||||
{resourcePath, pathsToOpen, executedFrom, test, version, pidToKillWhenClosed, devMode, newWindow, specDirectory, logFile}
|
||||
{resourcePath, pathsToOpen, executedFrom, test, version, pidToKillWhenClosed, devMode, safeMode, newWindow, specDirectory, logFile}
|
||||
|
||||
start()
|
||||
|
||||
+3
-3
@@ -138,13 +138,13 @@ class Cursor extends Model
|
||||
|
||||
# Public: Identifies if the cursor is surrounded by whitespace.
|
||||
#
|
||||
# "Surrounded" here means that all characters before and after the cursor is
|
||||
# whitespace.
|
||||
# "Surrounded" here means that the character directly before and after the
|
||||
# cursor are both whitespace.
|
||||
#
|
||||
# Returns a {Boolean}.
|
||||
isSurroundedByWhitespace: ->
|
||||
{row, column} = @getBufferPosition()
|
||||
range = [[row, Math.min(0, column - 1)], [row, Math.max(0, column + 1)]]
|
||||
range = [[row, column - 1], [row, column + 1]]
|
||||
/^\s+$/.test @editor.getTextInBufferRange(range)
|
||||
|
||||
# Public: Returns whether the cursor is currently between a word and non-word
|
||||
|
||||
@@ -32,6 +32,8 @@ class DisplayBuffer extends Model
|
||||
|
||||
verticalScrollMargin: 2
|
||||
horizontalScrollMargin: 6
|
||||
horizontalScrollbarHeight: 15
|
||||
verticalScrollbarWidth: 15
|
||||
|
||||
constructor: ({tabLength, @editorWidthInChars, @tokenizedBuffer, buffer}={}) ->
|
||||
super
|
||||
@@ -111,32 +113,83 @@ class DisplayBuffer extends Model
|
||||
getHorizontalScrollMargin: -> @horizontalScrollMargin
|
||||
setHorizontalScrollMargin: (@horizontalScrollMargin) -> @horizontalScrollMargin
|
||||
|
||||
getHeight: -> @height ? @getScrollHeight()
|
||||
getHorizontalScrollbarHeight: -> @horizontalScrollbarHeight
|
||||
setHorizontalScrollbarHeight: (@horizontalScrollbarHeight) -> @horizontalScrollbarHeight
|
||||
|
||||
getVerticalScrollbarWidth: -> @verticalScrollbarWidth
|
||||
setVerticalScrollbarWidth: (@verticalScrollbarWidth) -> @verticalScrollbarWidth
|
||||
|
||||
getHeight: ->
|
||||
if @height?
|
||||
@height
|
||||
else
|
||||
if @horizontallyScrollable()
|
||||
@getScrollHeight() + @getHorizontalScrollbarHeight()
|
||||
else
|
||||
@getScrollHeight()
|
||||
|
||||
setHeight: (@height) -> @height
|
||||
|
||||
getWidth: -> @width ? @getScrollWidth()
|
||||
getClientHeight: (reentrant) ->
|
||||
if @horizontallyScrollable(reentrant)
|
||||
@getHeight() - @getHorizontalScrollbarHeight()
|
||||
else
|
||||
@getHeight()
|
||||
|
||||
getClientWidth: (reentrant) ->
|
||||
if @verticallyScrollable(reentrant)
|
||||
@getWidth() - @getVerticalScrollbarWidth()
|
||||
else
|
||||
@getWidth()
|
||||
|
||||
horizontallyScrollable: (reentrant) ->
|
||||
return false unless @width?
|
||||
return false if @getSoftWrap()
|
||||
if reentrant
|
||||
@getScrollWidth() > @getWidth()
|
||||
else
|
||||
@getScrollWidth() > @getClientWidth(true)
|
||||
|
||||
verticallyScrollable: (reentrant) ->
|
||||
return false unless @height?
|
||||
if reentrant
|
||||
@getScrollHeight() > @getHeight()
|
||||
else
|
||||
@getScrollHeight() > @getClientHeight(true)
|
||||
|
||||
getWidth: ->
|
||||
if @width?
|
||||
@width
|
||||
else
|
||||
if @verticallyScrollable()
|
||||
@getScrollWidth() + @getVerticalScrollbarWidth()
|
||||
else
|
||||
@getScrollWidth()
|
||||
|
||||
setWidth: (newWidth) ->
|
||||
oldWidth = @width
|
||||
@width = newWidth
|
||||
@updateWrappedScreenLines() if newWidth isnt oldWidth and @softWrap
|
||||
@setScrollTop(@getScrollTop()) # Ensure scrollTop is still valid in case horizontal scrollbar disappeared
|
||||
@width
|
||||
|
||||
getScrollTop: -> @scrollTop
|
||||
setScrollTop: (scrollTop) ->
|
||||
if @manageScrollPosition
|
||||
@scrollTop = Math.max(0, Math.min(@getScrollHeight() - @getHeight(), scrollTop))
|
||||
@scrollTop = Math.max(0, Math.min(@getScrollHeight() - @getClientHeight(), scrollTop))
|
||||
else
|
||||
@scrollTop = scrollTop
|
||||
|
||||
getScrollBottom: -> @scrollTop + @height
|
||||
setScrollBottom: (scrollBottom) ->
|
||||
@setScrollTop(scrollBottom - @height)
|
||||
@setScrollTop(scrollBottom - @getClientHeight())
|
||||
@getScrollBottom()
|
||||
|
||||
getScrollLeft: -> @scrollLeft
|
||||
setScrollLeft: (scrollLeft) ->
|
||||
if @manageScrollPosition
|
||||
@scrollLeft = Math.max(0, Math.min(@getScrollWidth() - @getWidth(), scrollLeft))
|
||||
@scrollLeft = Math.max(0, Math.min(@getScrollWidth() - @getClientWidth(), scrollLeft))
|
||||
@scrollLeft
|
||||
else
|
||||
@scrollLeft = scrollLeft
|
||||
|
||||
@@ -151,6 +204,8 @@ class DisplayBuffer extends Model
|
||||
getDefaultCharWidth: -> @defaultCharWidth
|
||||
setDefaultCharWidth: (@defaultCharWidth) -> @defaultCharWidth
|
||||
|
||||
getCursorWidth: -> 1
|
||||
|
||||
getScopedCharWidth: (scopeNames, char) ->
|
||||
@getScopedCharWidths(scopeNames)[char]
|
||||
|
||||
@@ -178,13 +233,13 @@ class DisplayBuffer extends Model
|
||||
@getLineCount() * @getLineHeight()
|
||||
|
||||
getScrollWidth: ->
|
||||
@getMaxLineLength() * @getDefaultCharWidth()
|
||||
(@getMaxLineLength() * @getDefaultCharWidth()) + @getCursorWidth()
|
||||
|
||||
getVisibleRowRange: ->
|
||||
unless @getLineHeight() > 0
|
||||
throw new Error("You must assign a non-zero lineHeight before calling ::getVisibleRowRange()")
|
||||
|
||||
heightInLines = Math.ceil(@getHeight() / @getLineHeight()) + 1
|
||||
heightInLines = Math.ceil(@getClientHeight() / @getLineHeight()) + 1
|
||||
startRow = Math.floor(@getScrollTop() / @getLineHeight())
|
||||
endRow = Math.min(@getLineCount(), Math.ceil(startRow + heightInLines))
|
||||
[startRow, endRow]
|
||||
|
||||
@@ -5,6 +5,7 @@ React = require 'react'
|
||||
GutterComponent = require './gutter-component'
|
||||
EditorScrollViewComponent = require './editor-scroll-view-component'
|
||||
ScrollbarComponent = require './scrollbar-component'
|
||||
ScrollbarCornerComponent = require './scrollbar-corner-component'
|
||||
SubscriberMixin = require './subscriber-mixin'
|
||||
|
||||
module.exports =
|
||||
@@ -20,10 +21,15 @@ EditorComponent = React.createClass
|
||||
cursorsMoved: false
|
||||
preservedRowRange: null
|
||||
scrollingVertically: false
|
||||
gutterWidth: 0
|
||||
refreshingScrollbars: false
|
||||
measuringScrollbars: true
|
||||
|
||||
render: ->
|
||||
{focused, fontSize, lineHeight, fontFamily, showIndentGuide} = @state
|
||||
{editor, cursorBlinkPeriod, cursorBlinkResumeDelay} = @props
|
||||
maxLineNumberDigits = editor.getScreenLineCount().toString().length
|
||||
|
||||
if @isMounted()
|
||||
renderedRowRange = @getRenderedRowRange()
|
||||
scrollHeight = editor.getScrollHeight()
|
||||
@@ -31,15 +37,20 @@ EditorComponent = React.createClass
|
||||
scrollTop = editor.getScrollTop()
|
||||
scrollLeft = editor.getScrollLeft()
|
||||
lineHeightInPixels = editor.getLineHeight()
|
||||
horizontalScrollbarHeight = editor.getHorizontalScrollbarHeight()
|
||||
verticalScrollbarWidth = editor.getVerticalScrollbarWidth()
|
||||
verticallyScrollable = editor.verticallyScrollable()
|
||||
horizontallyScrollable = editor.horizontallyScrollable()
|
||||
|
||||
className = 'editor editor-colors react'
|
||||
className += ' is-focused' if focused
|
||||
|
||||
div className: className, style: {fontSize, lineHeight, fontFamily}, tabIndex: -1,
|
||||
GutterComponent {
|
||||
editor, renderedRowRange, scrollTop, scrollHeight,
|
||||
lineHeight: lineHeightInPixels, @pendingChanges
|
||||
}
|
||||
# GutterComponent {
|
||||
# editor, renderedRowRange, maxLineNumberDigits, scrollTop, scrollHeight,
|
||||
# lineHeight: lineHeightInPixels, fontSize, fontFamily, @pendingChanges,
|
||||
# onWidthChanged: @onGutterWidthChanged
|
||||
# }
|
||||
|
||||
EditorScrollViewComponent {
|
||||
ref: 'scrollView', editor, fontSize, fontFamily, showIndentGuide
|
||||
@@ -55,6 +66,10 @@ EditorComponent = React.createClass
|
||||
onScroll: @onVerticalScroll
|
||||
scrollTop: scrollTop
|
||||
scrollHeight: scrollHeight
|
||||
visible: verticallyScrollable and not @refreshingScrollbars and not @measuringScrollbars
|
||||
scrollableInOppositeDirection: horizontallyScrollable
|
||||
verticalScrollbarWidth: verticalScrollbarWidth
|
||||
horizontalScrollbarHeight: horizontalScrollbarHeight
|
||||
|
||||
ScrollbarComponent
|
||||
ref: 'horizontalScrollbar'
|
||||
@@ -62,7 +77,19 @@ EditorComponent = React.createClass
|
||||
orientation: 'horizontal'
|
||||
onScroll: @onHorizontalScroll
|
||||
scrollLeft: scrollLeft
|
||||
scrollWidth: scrollWidth
|
||||
scrollWidth: scrollWidth + @gutterWidth
|
||||
visible: horizontallyScrollable and not @refreshingScrollbars and not @measuringScrollbars
|
||||
scrollableInOppositeDirection: verticallyScrollable
|
||||
verticalScrollbarWidth: verticalScrollbarWidth
|
||||
horizontalScrollbarHeight: horizontalScrollbarHeight
|
||||
|
||||
# Also used to measure the height/width of scrollbars after the initial render
|
||||
ScrollbarCornerComponent
|
||||
ref: 'scrollbarCorner'
|
||||
visible: not @refreshingScrollbars and (@measuringScrollbars or horizontallyScrollable and verticallyScrollable)
|
||||
measuringScrollbars: @measuringScrollbars
|
||||
height: horizontalScrollbarHeight
|
||||
width: verticalScrollbarWidth
|
||||
|
||||
getRenderedRowRange: ->
|
||||
renderedRowRange = @props.editor.getVisibleRowRange()
|
||||
@@ -86,6 +113,8 @@ EditorComponent = React.createClass
|
||||
@observeEditor()
|
||||
@listenForDOMEvents()
|
||||
@listenForCommands()
|
||||
@measureScrollbars()
|
||||
@subscribe atom.themes, 'stylesheet-added stylsheet-removed', @onStylesheetsChanged
|
||||
@props.editor.setVisible(true)
|
||||
@requestUpdate()
|
||||
|
||||
@@ -99,6 +128,8 @@ EditorComponent = React.createClass
|
||||
componentDidUpdate: ->
|
||||
@pendingChanges.length = 0
|
||||
@cursorsMoved = false
|
||||
@refreshingScrollbars = false
|
||||
@measureScrollbars() if @measuringScrollbars
|
||||
@props.parentView.trigger 'editor:display-updated'
|
||||
|
||||
observeEditor: ->
|
||||
@@ -230,6 +261,16 @@ EditorComponent = React.createClass
|
||||
@subscribe atom.config.observe 'editor.fontSize', @setFontSize
|
||||
@subscribe atom.config.observe 'editor.showIndentGuide', @setShowIndentGuide
|
||||
|
||||
measureScrollbars: ->
|
||||
@measuringScrollbars = false
|
||||
|
||||
{editor} = @props
|
||||
scrollbarCornerNode = @refs.scrollbarCorner.getDOMNode()
|
||||
width = (scrollbarCornerNode.offsetWidth - scrollbarCornerNode.clientWidth) or 15
|
||||
height = (scrollbarCornerNode.offsetHeight - scrollbarCornerNode.clientHeight) or 15
|
||||
editor.setVerticalScrollbarWidth(width)
|
||||
editor.setHorizontalScrollbarHeight(height)
|
||||
|
||||
setFontSize: (fontSize) ->
|
||||
@setState({fontSize})
|
||||
|
||||
@@ -285,6 +326,35 @@ EditorComponent = React.createClass
|
||||
|
||||
event.preventDefault()
|
||||
|
||||
onStylesheetsChanged: (stylesheet) ->
|
||||
# Only update when the scrollbar is changed
|
||||
return unless @containsScrollbarSelector(stylesheet)
|
||||
|
||||
# Believe it or not, proper handling of changes to scrollbar styles requires
|
||||
# three DOM updates.
|
||||
|
||||
# Scrollbar style changes won't apply to scrollbars that are already
|
||||
# visible, so first we need to hide scrollbars so we can redisplay them and
|
||||
# force Chromium to apply updates.
|
||||
@refreshingScrollbars = true
|
||||
@requestUpdate()
|
||||
|
||||
# Next, we display only the scrollbar corner so we can measure the new
|
||||
# scrollbar dimensions. The ::measuringScrollbars property will be set back
|
||||
# to false after the scrollbars are measured.
|
||||
@measuringScrollbars = true
|
||||
@requestUpdate()
|
||||
|
||||
# Finally, we restore the scrollbars based on the newly-measured dimensions
|
||||
# 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
|
||||
@@ -312,10 +382,10 @@ EditorComponent = React.createClass
|
||||
@requestUpdate() if editor.selectionIntersectsVisibleRowRange(selection)
|
||||
|
||||
onScrollTopChanged: ->
|
||||
@preservedRowRange = @getRenderedRowRange()
|
||||
# @preservedRowRange = @getRenderedRowRange()
|
||||
@scrollingVertically = true
|
||||
@clearPreservedRowRangeAfterDelay ?= debounce(@clearPreservedRowRange, 200)
|
||||
@clearPreservedRowRangeAfterDelay()
|
||||
# @clearPreservedRowRangeAfterDelay ?= debounce(@clearPreservedRowRange, 200)
|
||||
# @clearPreservedRowRangeAfterDelay()
|
||||
@requestUpdate()
|
||||
|
||||
onSelectionRemoved: (selection) ->
|
||||
@@ -325,6 +395,9 @@ EditorComponent = React.createClass
|
||||
onCursorsMoved: ->
|
||||
@cursorsMoved = true
|
||||
|
||||
onGutterWidthChanged: (@gutterWidth) ->
|
||||
@requestUpdate()
|
||||
|
||||
requestUpdate: ->
|
||||
if @batchingUpdates
|
||||
@updateRequested = true
|
||||
|
||||
@@ -182,17 +182,19 @@ EditorScrollViewComponent = React.createClass
|
||||
measureHeightAndWidth: ->
|
||||
return unless @isMounted()
|
||||
|
||||
node = @getDOMNode()
|
||||
computedStyle = getComputedStyle(node)
|
||||
{editor} = @props
|
||||
node = @getDOMNode()
|
||||
editorNode = node.parentNode
|
||||
{position} = getComputedStyle(editorNode)
|
||||
{width, height} = editorNode.style
|
||||
|
||||
unless computedStyle.height is '0px'
|
||||
clientHeight = node.clientHeight
|
||||
if position is 'absolute' or height
|
||||
clientHeight = node.clientHeight
|
||||
editor.setHeight(clientHeight) if clientHeight > 0
|
||||
|
||||
unless computedStyle.width is '0px'
|
||||
if position is 'absolute' or width
|
||||
clientWidth = node.clientWidth
|
||||
editor.setWidth(clientWidth) if clientHeight > 0
|
||||
editor.setWidth(clientWidth) if clientWidth > 0
|
||||
|
||||
focus: ->
|
||||
@refs.input.focus()
|
||||
|
||||
@@ -472,7 +472,7 @@ class EditorView extends View
|
||||
$(document).off 'mouseup', finalizeSelections
|
||||
|
||||
unless @editor.isDestroyed()
|
||||
@editor.mergeIntersectingSelections(isReversed: @editor.getLastSelection().isReversed())
|
||||
@editor.mergeIntersectingSelections(reversed: @editor.getLastSelection().isReversed())
|
||||
@editor.finalizeSelections()
|
||||
@syncCursorAnimations()
|
||||
|
||||
@@ -1482,10 +1482,12 @@ class EditorView extends View
|
||||
html = @buildEmptyLineHtml(showIndentGuide, eolInvisibles, htmlEolInvisibles, indentation, editor, mini)
|
||||
line.push(html) if html
|
||||
else
|
||||
firstTrailingWhitespacePosition = text.search(/\s*$/)
|
||||
lineIsWhitespaceOnly = firstTrailingWhitespacePosition is 0
|
||||
position = 0
|
||||
for token in tokens
|
||||
@updateScopeStack(line, scopeStack, token.scopes)
|
||||
hasIndentGuide = not mini and showIndentGuide
|
||||
hasIndentGuide = not mini and showIndentGuide and token.hasLeadingWhitespace or (token.hasTrailingWhitespace and lineIsWhitespaceOnly)
|
||||
line.push(token.getValueAsHtml({invisibles, hasIndentGuide}))
|
||||
position += token.value.length
|
||||
|
||||
|
||||
+25
-15
@@ -152,7 +152,7 @@ class Editor extends Model
|
||||
@delegatesProperties '$lineHeight', '$defaultCharWidth', '$height', '$width',
|
||||
'$scrollTop', '$scrollLeft', 'manageScrollPosition', toProperty: 'displayBuffer'
|
||||
|
||||
constructor: ({@softTabs, initialLine, tabLength, softWrap, @displayBuffer, buffer, registerEditor, suppressCursorCreation}) ->
|
||||
constructor: ({@softTabs, initialLine, initialColumn, tabLength, softWrap, @displayBuffer, buffer, registerEditor, suppressCursorCreation}) ->
|
||||
super
|
||||
|
||||
@cursors = []
|
||||
@@ -170,11 +170,9 @@ class Editor extends Model
|
||||
@subscribeToDisplayBuffer()
|
||||
|
||||
if @getCursors().length is 0 and not suppressCursorCreation
|
||||
if initialLine
|
||||
position = [initialLine, 0]
|
||||
else
|
||||
position = [0, 0]
|
||||
@addCursorAtBufferPosition(position)
|
||||
initialLine = Math.max(parseInt(initialLine) or 0, 0)
|
||||
initialColumn = Math.max(parseInt(initialColumn) or 0, 0)
|
||||
@addCursorAtBufferPosition([initialLine, initialColumn])
|
||||
|
||||
@languageMode = new LanguageMode(this)
|
||||
|
||||
@@ -410,13 +408,13 @@ class Editor extends Model
|
||||
saveAs: (filePath) -> @buffer.saveAs(filePath)
|
||||
|
||||
checkoutHead: ->
|
||||
if path = @getPath()
|
||||
atom.project.getRepo()?.checkoutHead(path)
|
||||
if filePath = @getPath()
|
||||
atom.project.getRepo()?.checkoutHead(filePath)
|
||||
|
||||
# Copies the current file path to the native clipboard.
|
||||
copyPathToClipboard: ->
|
||||
path = @getPath()
|
||||
atom.clipboard.write(path) if path?
|
||||
if filePath = @getPath()
|
||||
atom.clipboard.write(filePath)
|
||||
|
||||
# Public: Returns the {String} path of this editor's text buffer.
|
||||
getPath: -> @buffer.getPath()
|
||||
@@ -466,7 +464,7 @@ class Editor extends Model
|
||||
# options - An options hash with an `includeNewline` key.
|
||||
#
|
||||
# Returns a {Range}.
|
||||
bufferRangeForBufferRow: (row, options) -> @buffer.rangeForRow(row, options)
|
||||
bufferRangeForBufferRow: (row, {includeNewline}={}) -> @buffer.rangeForRow(row, includeNewline)
|
||||
|
||||
# Public: Returns a {String} representing the contents of the line at the
|
||||
# given buffer row.
|
||||
@@ -895,7 +893,7 @@ class Editor extends Model
|
||||
endRow = row
|
||||
|
||||
insertPosition = Point.fromObject([startRow - insertDelta])
|
||||
endPosition = Point.min([endRow + 1], @buffer.getEofPosition())
|
||||
endPosition = Point.min([endRow + 1], @buffer.getEndPosition())
|
||||
lines = @buffer.getTextInRange([[startRow], endPosition])
|
||||
if endPosition.row is lastRow and endPosition.column > 0 and not @buffer.lineEndingForRow(endPosition.row)
|
||||
lines = "#{lines}\n"
|
||||
@@ -954,7 +952,7 @@ class Editor extends Model
|
||||
lines = @buffer.getTextInRange([[startRow], endPosition])
|
||||
@buffer.deleteRows(startRow, endRow)
|
||||
|
||||
insertPosition = Point.min([startRow + insertDelta], @buffer.getEofPosition())
|
||||
insertPosition = Point.min([startRow + insertDelta], @buffer.getEndPosition())
|
||||
if insertPosition.row is @buffer.getLastRow() and insertPosition.column > 0
|
||||
lines = "\n#{lines}"
|
||||
|
||||
@@ -1483,7 +1481,7 @@ class Editor extends Model
|
||||
selectToScreenPosition: (position) ->
|
||||
lastSelection = @getLastSelection()
|
||||
lastSelection.selectToScreenPosition(position)
|
||||
@mergeIntersectingSelections(isReversed: lastSelection.isReversed())
|
||||
@mergeIntersectingSelections(reversed: lastSelection.isReversed())
|
||||
|
||||
# Public: Move the cursor of each selection one character rightward while
|
||||
# preserving the selection's tail position.
|
||||
@@ -1710,7 +1708,7 @@ class Editor extends Model
|
||||
# Calls the given function with each selection, then merges selections in the
|
||||
# reversed orientation
|
||||
expandSelectionsBackward: (fn) ->
|
||||
@mergeIntersectingSelections isReversed: true, =>
|
||||
@mergeIntersectingSelections reversed: true, =>
|
||||
fn(selection) for selection in @getSelections()
|
||||
|
||||
finalizeSelections: ->
|
||||
@@ -1840,6 +1838,8 @@ class Editor extends Model
|
||||
setHeight: (height) -> @displayBuffer.setHeight(height)
|
||||
getHeight: -> @displayBuffer.getHeight()
|
||||
|
||||
getClientHeight: -> @displayBuffer.getClientHeight()
|
||||
|
||||
setWidth: (width) -> @displayBuffer.setWidth(width)
|
||||
getWidth: -> @displayBuffer.getWidth()
|
||||
|
||||
@@ -1878,6 +1878,16 @@ class Editor extends Model
|
||||
|
||||
scrollToBufferPosition: (bufferPosition) -> @displayBuffer.scrollToBufferPosition(bufferPosition)
|
||||
|
||||
horizontallyScrollable: -> @displayBuffer.horizontallyScrollable()
|
||||
|
||||
verticallyScrollable: -> @displayBuffer.verticallyScrollable()
|
||||
|
||||
getHorizontalScrollbarHeight: -> @displayBuffer.getHorizontalScrollbarHeight()
|
||||
setHorizontalScrollbarHeight: (height) -> @displayBuffer.setHorizontalScrollbarHeight(height)
|
||||
|
||||
getVerticalScrollbarWidth: -> @displayBuffer.getVerticalScrollbarWidth()
|
||||
setVerticalScrollbarWidth: (width) -> @displayBuffer.setVerticalScrollbarWidth(width)
|
||||
|
||||
# Deprecated: Call {::joinLines} instead.
|
||||
joinLine: ->
|
||||
deprecate("Use Editor::joinLines() instead")
|
||||
|
||||
+6
-3
@@ -135,6 +135,7 @@ class Git
|
||||
relativePath = @relativize(path)
|
||||
currentPathStatus = @statuses[relativePath] ? 0
|
||||
pathStatus = repo.getStatus(repo.relativize(path)) ? 0
|
||||
pathStatus = 0 if repo.isStatusIgnored(pathStatus)
|
||||
if pathStatus > 0
|
||||
@statuses[relativePath] = pathStatus
|
||||
else
|
||||
@@ -344,8 +345,10 @@ class Git
|
||||
# Refreshes the current git status in an outside process and asynchronously
|
||||
# updates the relevant properties.
|
||||
refreshStatus: ->
|
||||
handlerPath = require.resolve('./repository-status-handler')
|
||||
@statusTask = Task.once handlerPath, @getPath(), ({statuses, upstream, branch, submodules}) =>
|
||||
@handlerPath ?= require.resolve('./repository-status-handler')
|
||||
|
||||
@statusTask?.terminate()
|
||||
@statusTask = Task.once @handlerPath, @getPath(), ({statuses, upstream, branch, submodules}) =>
|
||||
statusesUnchanged = _.isEqual(statuses, @statuses) and
|
||||
_.isEqual(upstream, @upstream) and
|
||||
_.isEqual(branch, @branch) and
|
||||
@@ -357,6 +360,6 @@ class Git
|
||||
@submodules = submodules
|
||||
|
||||
for submodulePath, submoduleRepo of @getRepo().submodules
|
||||
submoduleRepo.upstream = submodules[submodulePath].upstream
|
||||
submoduleRepo.upstream = submodules[submodulePath]?.upstream ? {ahead: 0, behind: 0}
|
||||
|
||||
@emit 'statuses-changed' unless statusesUnchanged
|
||||
|
||||
@@ -8,18 +8,19 @@ GutterComponent = React.createClass
|
||||
displayName: 'GutterComponent'
|
||||
mixins: [SubscriberMixin]
|
||||
|
||||
lastMeasuredWidth: null
|
||||
|
||||
render: ->
|
||||
div className: 'gutter',
|
||||
@renderLineNumbers() if @isMounted()
|
||||
|
||||
renderLineNumbers: ->
|
||||
{editor, renderedRowRange, scrollTop, scrollHeight} = @props
|
||||
{editor, renderedRowRange, maxLineNumberDigits, scrollTop, scrollHeight} = @props
|
||||
[startRow, endRow] = renderedRowRange
|
||||
charWidth = editor.getDefaultCharWidth()
|
||||
lineHeight = editor.getLineHeight()
|
||||
maxDigits = editor.getLastBufferRow().toString().length
|
||||
style =
|
||||
width: charWidth * (maxDigits + 1.5)
|
||||
width: charWidth * (maxLineNumberDigits + 1.5)
|
||||
height: scrollHeight
|
||||
WebkitTransform: "translate3d(0, #{-scrollTop}px, 0)"
|
||||
|
||||
@@ -33,30 +34,33 @@ GutterComponent = React.createClass
|
||||
lastBufferRow = bufferRow
|
||||
lineNumber = (bufferRow + 1).toString()
|
||||
|
||||
key = tokenizedLines[i]?.id
|
||||
key = tokenizedLines[i].id
|
||||
screenRow = startRow + i
|
||||
lineNumbers.push(LineNumberComponent({key, lineNumber, maxDigits, bufferRow, screenRow, lineHeight}))
|
||||
lineNumbers.push(LineNumberComponent({key, lineNumber, maxLineNumberDigits, bufferRow, screenRow, lineHeight}))
|
||||
lastBufferRow = bufferRow
|
||||
|
||||
div className: 'line-numbers', style: style,
|
||||
lineNumbers
|
||||
|
||||
componentWillUnmount: ->
|
||||
@unsubscribe()
|
||||
|
||||
# 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) ->
|
||||
{renderedRowRange, pendingChanges, scrollTop} = @props
|
||||
|
||||
return true unless isEqualForProperties(newProps, @props, 'renderedRowRange', 'scrollTop', 'lineHeight')
|
||||
return true unless isEqualForProperties(newProps, @props, 'renderedRowRange', 'scrollTop', 'lineHeight', 'fontSize')
|
||||
|
||||
{renderedRowRange, pendingChanges} = newProps
|
||||
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 @lastMeasuredWidth? and isEqualForProperties(oldProps, @props, 'maxLineNumberDigits', 'fontSize', 'fontFamily')
|
||||
width = @getDOMNode().offsetWidth
|
||||
if width isnt @lastMeasuredWidth
|
||||
@lastMeasuredWidth = width
|
||||
@props.onWidthChanged(width)
|
||||
|
||||
LineNumberComponent = React.createClass
|
||||
displayName: 'LineNumberComponent'
|
||||
|
||||
@@ -70,9 +74,9 @@ LineNumberComponent = React.createClass
|
||||
dangerouslySetInnerHTML: {__html: @buildInnerHTML()}
|
||||
|
||||
buildInnerHTML: ->
|
||||
{lineNumber, maxDigits} = @props
|
||||
if lineNumber.length < maxDigits
|
||||
padding = multiplyString(' ', maxDigits - lineNumber.length)
|
||||
{lineNumber, maxLineNumberDigits} = @props
|
||||
if lineNumber.length < maxLineNumberDigits
|
||||
padding = multiplyString(' ', maxLineNumberDigits - lineNumber.length)
|
||||
padding + lineNumber + @iconDivHTML
|
||||
else
|
||||
lineNumber + @iconDivHTML
|
||||
@@ -80,4 +84,4 @@ LineNumberComponent = React.createClass
|
||||
iconDivHTML: '<div class="icon-right"></div>'
|
||||
|
||||
shouldComponentUpdate: (newProps) ->
|
||||
not isEqualForProperties(newProps, @props, 'lineHeight', 'screenRow')
|
||||
not isEqualForProperties(newProps, @props, 'lineHeight', 'screenRow', 'maxLineNumberDigits')
|
||||
|
||||
@@ -60,7 +60,8 @@ class LanguageMode
|
||||
buffer.setTextInRange([[end, endColumn], [end, endLength]], "")
|
||||
else
|
||||
buffer.transact ->
|
||||
buffer.insert([start, 0], commentStartString)
|
||||
indentLength = buffer.lineForRow(start).match(/^\s*/)?[0].length ? 0
|
||||
buffer.insert([start, indentLength], commentStartString)
|
||||
buffer.insert([end, buffer.lineLengthForRow(end)], commentEndString)
|
||||
else
|
||||
if shouldUncomment and start isnt end
|
||||
|
||||
@@ -1,7 +1,8 @@
|
||||
React = require 'react'
|
||||
{div, span} = require 'reactionary'
|
||||
{debounce, isEqual, isEqualForProperties, multiplyString} = require 'underscore-plus'
|
||||
{debounce, isEqual, isEqualForProperties, multiplyString, toArray} = require 'underscore-plus'
|
||||
{$$} = require 'space-pen'
|
||||
EditorView = require './editor-view'
|
||||
|
||||
DummyLineNode = $$(-> @div className: 'line', style: 'position: absolute; visibility: hidden;', => @span 'x')[0]
|
||||
AcceptFilter = {acceptNode: -> NodeFilter.FILTER_ACCEPT}
|
||||
@@ -11,15 +12,7 @@ LinesComponent = React.createClass
|
||||
displayName: 'LinesComponent'
|
||||
|
||||
render: ->
|
||||
if @isMounted()
|
||||
{editor, renderedRowRange, lineHeight, showIndentGuide} = @props
|
||||
[startRow, endRow] = renderedRowRange
|
||||
|
||||
lines =
|
||||
for tokenizedLine, i in editor.linesForScreenRows(startRow, endRow - 1)
|
||||
LineComponent({key: tokenizedLine.id, tokenizedLine, showIndentGuide, lineHeight, screenRow: startRow + i})
|
||||
|
||||
div {className: 'lines'}, lines
|
||||
div className: 'lines'
|
||||
|
||||
componentWillMount: ->
|
||||
@measuredLines = new WeakSet
|
||||
@@ -37,9 +30,14 @@ LinesComponent = React.createClass
|
||||
false
|
||||
|
||||
componentDidUpdate: (prevProps) ->
|
||||
if not prevProps.renderedRowRange? or prevProps.lineHeight isnt @props.lineHeight
|
||||
@renderLines()
|
||||
else
|
||||
@updateRenderedLines(prevProps.renderedRowRange)
|
||||
|
||||
@measureLineHeightAndCharWidth() unless isEqualForProperties(prevProps, @props, 'fontSize', 'fontFamily', 'lineHeight')
|
||||
@clearScopedCharWidths() unless isEqualForProperties(prevProps, @props, 'fontSize', 'fontFamily')
|
||||
@measureCharactersInNewLines() unless @props.scrollingVertically
|
||||
# @clearScopedCharWidths() unless isEqualForProperties(prevProps, @props, 'fontSize', 'fontFamily')
|
||||
# @measureCharactersInNewLines() unless @props.scrollingVertically
|
||||
|
||||
measureLineHeightAndCharWidth: ->
|
||||
node = @getDOMNode()
|
||||
@@ -52,6 +50,75 @@ LinesComponent = React.createClass
|
||||
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()
|
||||
@@ -97,44 +164,3 @@ LinesComponent = React.createClass
|
||||
clearScopedCharWidths: ->
|
||||
@measuredLines.clear()
|
||||
@props.editor.clearScopedCharWidths()
|
||||
|
||||
|
||||
LineComponent = React.createClass
|
||||
displayName: 'LineComponent'
|
||||
|
||||
render: ->
|
||||
{screenRow, lineHeight} = @props
|
||||
|
||||
style =
|
||||
top: screenRow * lineHeight
|
||||
position: 'absolute'
|
||||
|
||||
div className: 'line', style: style, 'data-screen-row': screenRow, dangerouslySetInnerHTML: {__html: @buildInnerHTML()}
|
||||
|
||||
buildInnerHTML: ->
|
||||
if @props.tokenizedLine.text.length is 0
|
||||
@buildEmptyLineHTML()
|
||||
else
|
||||
@buildScopeTreeHTML(@props.tokenizedLine.getScopeTree())
|
||||
|
||||
buildEmptyLineHTML: ->
|
||||
{showIndentGuide, tokenizedLine} = @props
|
||||
{indentLevel, tabLength} = tokenizedLine
|
||||
|
||||
if showIndentGuide and indentLevel > 0
|
||||
indentSpan = "<span class='indent-guide'>#{multiplyString(' ', tabLength)}</span>"
|
||||
multiplyString(indentSpan, indentLevel + 1)
|
||||
else
|
||||
" "
|
||||
|
||||
buildScopeTreeHTML: (scopeTree) ->
|
||||
if scopeTree.children?
|
||||
html = "<span class='#{scopeTree.scope.replace(/\./g, ' ')}'>"
|
||||
html += @buildScopeTreeHTML(child) for child in scopeTree.children
|
||||
html += "</span>"
|
||||
html
|
||||
else
|
||||
"<span>#{scopeTree.getValueAsHtml({hasIndentGuide: @props.showIndentGuide})}</span>"
|
||||
|
||||
shouldComponentUpdate: (newProps) ->
|
||||
not isEqualForProperties(newProps, @props, 'showIndentGuide', 'lineHeight', 'screenRow')
|
||||
|
||||
@@ -112,7 +112,7 @@ class MenuManager
|
||||
|
||||
sendToBrowserProcess: (template, keystrokesByCommand) ->
|
||||
keystrokesByCommand = @filterMultipleKeystroke(keystrokesByCommand)
|
||||
ipc.sendChannel 'update-application-menu', template, keystrokesByCommand
|
||||
ipc.send 'update-application-menu', template, keystrokesByCommand
|
||||
|
||||
normalizeLabel: (label) ->
|
||||
return undefined unless label?
|
||||
|
||||
@@ -27,10 +27,12 @@ module.exports =
|
||||
class PackageManager
|
||||
Emitter.includeInto(this)
|
||||
|
||||
constructor: ({configDirPath, devMode, @resourcePath}) ->
|
||||
@packageDirPaths = [path.join(configDirPath, "packages")]
|
||||
if devMode
|
||||
@packageDirPaths.unshift(path.join(configDirPath, "dev", "packages"))
|
||||
constructor: ({configDirPath, devMode, safeMode, @resourcePath}) ->
|
||||
@packageDirPaths = []
|
||||
unless safeMode
|
||||
if devMode
|
||||
@packageDirPaths.push(path.join(configDirPath, "dev", "packages"))
|
||||
@packageDirPaths.push(path.join(configDirPath, "packages"))
|
||||
|
||||
@loadedPackages = {}
|
||||
@activePackages = {}
|
||||
|
||||
@@ -103,7 +103,7 @@ class PaneView extends View
|
||||
|
||||
# Deprecated: Use ::activateNextItem
|
||||
showNextItem: ->
|
||||
deprecate("Use PaneView::destroyItem instead")
|
||||
deprecate("Use PaneView::activateNextItem instead")
|
||||
@activateNextItem()
|
||||
|
||||
# Deprecated: Use ::activatePreviousItem
|
||||
|
||||
+13
-5
@@ -339,18 +339,26 @@ class Pane extends Model
|
||||
newPane.activate()
|
||||
newPane
|
||||
|
||||
# If the parent is a horizontal axis, returns its first child;
|
||||
# otherwise this pane.
|
||||
# If the parent is a horizontal axis, returns its first child if it is a pane;
|
||||
# otherwise returns this pane.
|
||||
findLeftmostSibling: ->
|
||||
if @parent.orientation is 'horizontal'
|
||||
@parent.children[0]
|
||||
[leftmostSibling] = @parent.children
|
||||
if leftmostSibling instanceof PaneAxis
|
||||
this
|
||||
else
|
||||
leftmostSibling
|
||||
else
|
||||
this
|
||||
|
||||
# If the parent is a horizontal axis, returns its last child;
|
||||
# If the parent is a horizontal axis, returns its last child if it is a pane;
|
||||
# otherwise returns a new pane created by splitting this pane rightward.
|
||||
findOrCreateRightmostSibling: ->
|
||||
if @parent.orientation is 'horizontal'
|
||||
last(@parent.children)
|
||||
rightmostSibling = last(@parent.children)
|
||||
if rightmostSibling instanceof PaneAxis
|
||||
@splitRight()
|
||||
else
|
||||
rightmostSibling
|
||||
else
|
||||
@splitRight()
|
||||
|
||||
@@ -165,9 +165,8 @@ class Project extends Model
|
||||
bufferForId: (id) ->
|
||||
_.find @buffers, (buffer) -> buffer.id is id
|
||||
|
||||
# DEPRECATED
|
||||
# Still needed when deserializing a tokenized buffer
|
||||
buildBufferSync: (absoluteFilePath) ->
|
||||
deprecate("Use Project::buildBuffer instead")
|
||||
buffer = new TextBuffer({filePath: absoluteFilePath})
|
||||
@addBuffer(buffer)
|
||||
buffer.loadSync()
|
||||
|
||||
@@ -1,13 +1,24 @@
|
||||
React = require 'react'
|
||||
{div} = require 'reactionary'
|
||||
{isEqualForProperties} = require 'underscore-plus'
|
||||
{extend, isEqualForProperties} = require 'underscore-plus'
|
||||
|
||||
module.exports =
|
||||
ScrollbarComponent = React.createClass
|
||||
render: ->
|
||||
{orientation, className, scrollHeight, scrollWidth} = @props
|
||||
{orientation, className, scrollHeight, scrollWidth, visible} = @props
|
||||
{scrollableInOppositeDirection, horizontalScrollbarHeight, verticalScrollbarWidth} = @props
|
||||
|
||||
div {className, @onScroll},
|
||||
style = {}
|
||||
style.display = 'none' unless visible
|
||||
switch orientation
|
||||
when 'vertical'
|
||||
style.width = verticalScrollbarWidth
|
||||
style.bottom = horizontalScrollbarHeight if scrollableInOppositeDirection
|
||||
when 'horizontal'
|
||||
style.height = horizontalScrollbarHeight
|
||||
style.right = verticalScrollbarWidth if scrollableInOppositeDirection
|
||||
|
||||
div {className, style, @onScroll},
|
||||
switch orientation
|
||||
when 'vertical'
|
||||
div className: 'scrollbar-content', style: {height: scrollHeight}
|
||||
@@ -21,11 +32,13 @@ ScrollbarComponent = React.createClass
|
||||
throw new Error("Must specify an orientation property of 'vertical' or 'horizontal'")
|
||||
|
||||
shouldComponentUpdate: (newProps) ->
|
||||
return true if newProps.visible isnt @props.visible
|
||||
|
||||
switch @props.orientation
|
||||
when 'vertical'
|
||||
not isEqualForProperties(newProps, @props, 'scrollHeight', 'scrollTop')
|
||||
not isEqualForProperties(newProps, @props, 'scrollHeight', 'scrollTop', 'scrollableInOppositeDirection')
|
||||
when 'horizontal'
|
||||
not isEqualForProperties(newProps, @props, 'scrollWidth', 'scrollLeft')
|
||||
not isEqualForProperties(newProps, @props, 'scrollWidth', 'scrollLeft', 'scrollableInOppositeDirection')
|
||||
|
||||
componentDidUpdate: ->
|
||||
{orientation, scrollTop, scrollLeft} = @props
|
||||
|
||||
@@ -0,0 +1,18 @@
|
||||
React = require 'react'
|
||||
{div} = require 'reactionary'
|
||||
|
||||
module.exports =
|
||||
ScrollbarComponent = React.createClass
|
||||
render: ->
|
||||
{visible, measuringScrollbars, width, height} = @props
|
||||
|
||||
if measuringScrollbars
|
||||
height = 25
|
||||
width = 25
|
||||
|
||||
display = 'none' unless visible
|
||||
|
||||
div className: 'scrollbar-corner', style: {display, width, height},
|
||||
div style:
|
||||
height: height + 1
|
||||
width: width + 1
|
||||
@@ -150,7 +150,7 @@ class Selection extends Model
|
||||
@modifySelection =>
|
||||
if @initialScreenRange
|
||||
if position.isLessThan(@initialScreenRange.start)
|
||||
@marker.setScreenRange([position, @initialScreenRange.end], isReversed: true)
|
||||
@marker.setScreenRange([position, @initialScreenRange.end], reversed: true)
|
||||
else
|
||||
@marker.setScreenRange([@initialScreenRange.start, position])
|
||||
else
|
||||
@@ -298,7 +298,7 @@ class Selection extends Model
|
||||
|
||||
newBufferRange = @editor.buffer.setTextInRange(oldBufferRange, text, pick(options, 'undo'))
|
||||
if options.select
|
||||
@setBufferRange(newBufferRange, isReversed: wasReversed)
|
||||
@setBufferRange(newBufferRange, reversed: wasReversed)
|
||||
else
|
||||
@cursor.setBufferPosition(newBufferRange.end, skipAtomicTokens: true) if wasReversed
|
||||
|
||||
|
||||
@@ -158,10 +158,10 @@ class ThemeManager
|
||||
# load path.
|
||||
#
|
||||
# Returns the absolute path to the required stylesheet.
|
||||
requireStylesheet: (stylesheetPath, ttype = 'bundled', htmlElement) ->
|
||||
requireStylesheet: (stylesheetPath, type = 'bundled', htmlElement) ->
|
||||
if fullPath = @resolveStylesheet(stylesheetPath)
|
||||
content = @loadStylesheet(fullPath)
|
||||
@applyStylesheet(fullPath, content, ttype = 'bundled', htmlElement)
|
||||
@applyStylesheet(fullPath, content, type = 'bundled', htmlElement)
|
||||
else
|
||||
throw new Error("Could not find a file at path '#{stylesheetPath}'")
|
||||
|
||||
@@ -192,16 +192,24 @@ class ThemeManager
|
||||
|
||||
removeStylesheet: (stylesheetPath) ->
|
||||
fullPath = @resolveStylesheet(stylesheetPath) ? stylesheetPath
|
||||
@stylesheetElementForId(@stringToId(fullPath)).remove()
|
||||
@emit 'stylesheets-changed'
|
||||
element = @stylesheetElementForId(@stringToId(fullPath))
|
||||
if element.length > 0
|
||||
stylesheet = element[0].sheet
|
||||
element.remove()
|
||||
@emit 'stylesheet-removed', stylesheet
|
||||
@emit 'stylesheets-changed'
|
||||
|
||||
applyStylesheet: (path, text, ttype = 'bundled', htmlElement=$('html')) ->
|
||||
applyStylesheet: (path, text, type = 'bundled', htmlElement=$('html')) ->
|
||||
styleElement = @stylesheetElementForId(@stringToId(path), htmlElement)
|
||||
if styleElement.length
|
||||
@emit 'stylesheet-removed', styleElement[0].sheet
|
||||
styleElement.text(text)
|
||||
else
|
||||
if htmlElement.find("head style.#{ttype}").length
|
||||
htmlElement.find("head style.#{ttype}:last").after "<style class='#{ttype}' id='#{@stringToId(path)}'>#{text}</style>"
|
||||
styleElement = $("<style class='#{type}' id='#{@stringToId(path)}'>#{text}</style>")
|
||||
if htmlElement.find("head style.#{type}").length
|
||||
htmlElement.find("head style.#{type}:last").after(styleElement)
|
||||
else
|
||||
htmlElement.find("head").append "<style class='#{ttype}' id='#{@stringToId(path)}'>#{text}</style>"
|
||||
htmlElement.find("head").append(styleElement)
|
||||
|
||||
@emit 'stylesheet-added', styleElement[0].sheet
|
||||
@emit 'stylesheets-changed'
|
||||
|
||||
@@ -318,7 +318,7 @@ class TokenizedBuffer extends Model
|
||||
position
|
||||
|
||||
findClosingBracket: (startBufferPosition) ->
|
||||
range = [startBufferPosition, @buffer.getEofPosition()]
|
||||
range = [startBufferPosition, @buffer.getEndPosition()]
|
||||
position = null
|
||||
depth = 0
|
||||
@iterateTokensInBufferRange range, (token, startPosition, { stop }) ->
|
||||
|
||||
@@ -27,9 +27,9 @@ class WindowEventHandler
|
||||
|
||||
@subscribe $(window), 'blur', -> $("body").addClass('is-blurred')
|
||||
|
||||
@subscribe $(window), 'window:open-path', (event, {pathToOpen, initialLine}) ->
|
||||
@subscribe $(window), 'window:open-path', (event, {pathToOpen, initialLine, initialColumn}) ->
|
||||
unless fs.isDirectorySync(pathToOpen)
|
||||
atom.workspaceView?.open(pathToOpen, {initialLine})
|
||||
atom.workspace?.open(pathToOpen, {initialLine, initialColumn})
|
||||
|
||||
@subscribe $(window), 'beforeunload', =>
|
||||
confirmed = atom.workspaceView?.confirmClose()
|
||||
|
||||
+34
-31
@@ -57,7 +57,7 @@ class WorkspaceView extends View
|
||||
Delegator.includeInto(this)
|
||||
|
||||
@delegatesProperty 'fullScreen', 'destroyedItemUris', toProperty: 'model'
|
||||
@delegatesMethods 'open', 'openSync', 'reopenItemSync',
|
||||
@delegatesMethods 'open', 'openSync',
|
||||
'saveActivePaneItem', 'saveActivePaneItemAs', 'saveAll', 'destroyActivePaneItem',
|
||||
'destroyActivePane', 'increaseFontSize', 'decreaseFontSize', toProperty: 'model'
|
||||
|
||||
@@ -106,33 +106,34 @@ class WorkspaceView extends View
|
||||
@on 'pane-container:active-pane-item-changed', => @updateTitle()
|
||||
@on 'pane:active-item-title-changed', '.active.pane', => @updateTitle()
|
||||
|
||||
@command 'application:about', -> ipc.sendChannel('command', 'application:about')
|
||||
@command 'application:run-all-specs', -> ipc.sendChannel('command', 'application:run-all-specs')
|
||||
@command 'application:run-benchmarks', -> ipc.sendChannel('command', 'application:run-benchmarks')
|
||||
@command 'application:show-settings', -> ipc.sendChannel('command', 'application:show-settings')
|
||||
@command 'application:quit', -> ipc.sendChannel('command', 'application:quit')
|
||||
@command 'application:hide', -> ipc.sendChannel('command', 'application:hide')
|
||||
@command 'application:hide-other-applications', -> ipc.sendChannel('command', 'application:hide-other-applications')
|
||||
@command 'application:unhide-all-applications', -> ipc.sendChannel('command', 'application:unhide-all-applications')
|
||||
@command 'application:new-window', -> ipc.sendChannel('command', 'application:new-window')
|
||||
@command 'application:new-file', -> ipc.sendChannel('command', 'application:new-file')
|
||||
@command 'application:open', -> ipc.sendChannel('command', 'application:open')
|
||||
@command 'application:open-file', -> ipc.sendChannel('command', 'application:open-file')
|
||||
@command 'application:open-folder', -> ipc.sendChannel('command', 'application:open-folder')
|
||||
@command 'application:open-dev', -> ipc.sendChannel('command', 'application:open-dev')
|
||||
@command 'application:minimize', -> ipc.sendChannel('command', 'application:minimize')
|
||||
@command 'application:zoom', -> ipc.sendChannel('command', 'application:zoom')
|
||||
@command 'application:bring-all-windows-to-front', -> ipc.sendChannel('command', 'application:bring-all-windows-to-front')
|
||||
@command 'application:open-your-config', -> ipc.sendChannel('command', 'application:open-your-config')
|
||||
@command 'application:open-your-init-script', -> ipc.sendChannel('command', 'application:open-your-init-script')
|
||||
@command 'application:open-your-keymap', -> ipc.sendChannel('command', 'application:open-your-keymap')
|
||||
@command 'application:open-your-snippets', -> ipc.sendChannel('command', 'application:open-your-snippets')
|
||||
@command 'application:open-your-stylesheet', -> ipc.sendChannel('command', 'application:open-your-stylesheet')
|
||||
@command 'application:about', -> ipc.send('command', 'application:about')
|
||||
@command 'application:run-all-specs', -> ipc.send('command', 'application:run-all-specs')
|
||||
@command 'application:run-benchmarks', -> ipc.send('command', 'application:run-benchmarks')
|
||||
@command 'application:show-settings', -> ipc.send('command', 'application:show-settings')
|
||||
@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: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')
|
||||
@command 'application:open', -> ipc.send('command', 'application:open')
|
||||
@command 'application:open-file', -> ipc.send('command', 'application:open-file')
|
||||
@command 'application:open-folder', -> ipc.send('command', 'application:open-folder')
|
||||
@command 'application:open-dev', -> ipc.send('command', 'application:open-dev')
|
||||
@command 'application:open-safe', -> ipc.send('command', 'application:open-safe')
|
||||
@command 'application:minimize', -> ipc.send('command', 'application:minimize')
|
||||
@command 'application:zoom', -> ipc.send('command', 'application:zoom')
|
||||
@command 'application:bring-all-windows-to-front', -> ipc.send('command', 'application:bring-all-windows-to-front')
|
||||
@command 'application:open-your-config', -> ipc.send('command', 'application:open-your-config')
|
||||
@command 'application:open-your-init-script', -> ipc.send('command', 'application:open-your-init-script')
|
||||
@command 'application:open-your-keymap', -> ipc.send('command', 'application:open-your-keymap')
|
||||
@command 'application:open-your-snippets', -> ipc.send('command', 'application:open-your-snippets')
|
||||
@command 'application:open-your-stylesheet', -> ipc.send('command', 'application:open-your-stylesheet')
|
||||
@command 'application:open-license', => @model.openLicense()
|
||||
|
||||
@command 'window:install-shell-commands', => @installShellCommands()
|
||||
|
||||
@command 'window:run-package-specs', => ipc.sendChannel('run-package-specs', path.join(atom.project.getPath(), 'spec'))
|
||||
@command 'window:run-package-specs', -> ipc.send('run-package-specs', path.join(atom.project.getPath(), 'spec'))
|
||||
@command 'window:increase-font-size', => @increaseFontSize()
|
||||
@command 'window:decrease-font-size', => @decreaseFontSize()
|
||||
@command 'window:reset-font-size', => @model.resetFontSize()
|
||||
@@ -147,10 +148,10 @@ class WorkspaceView extends View
|
||||
@command 'window:toggle-invisibles', -> atom.config.toggle("editor.showInvisibles")
|
||||
@command 'window:log-deprecation-warnings', -> logDeprecationWarnings()
|
||||
|
||||
@command 'window:toggle-auto-indent', =>
|
||||
@command 'window:toggle-auto-indent', ->
|
||||
atom.config.toggle("editor.autoIndent")
|
||||
|
||||
@command 'pane:reopen-closed-item', => @reopenItemSync()
|
||||
@command 'pane:reopen-closed-item', => @getModel().reopenItem()
|
||||
|
||||
@command 'core:close', => if @getModel().getActivePaneItem()? then @destroyActivePaneItem() else @destroyActivePane()
|
||||
@command 'core:save', => @saveActivePaneItem()
|
||||
@@ -170,11 +171,11 @@ class WorkspaceView extends View
|
||||
detailedMessage: error.message
|
||||
|
||||
resourcePath = atom.getLoadSettings().resourcePath
|
||||
CommandInstaller.installAtomCommand resourcePath, true, (error) =>
|
||||
CommandInstaller.installAtomCommand resourcePath, true, (error) ->
|
||||
if error?
|
||||
showErrorDialog(error)
|
||||
else
|
||||
CommandInstaller.installApmCommand resourcePath, true, (error) =>
|
||||
CommandInstaller.installApmCommand resourcePath, true, (error) ->
|
||||
if error?
|
||||
showErrorDialog(error)
|
||||
else
|
||||
@@ -320,15 +321,17 @@ class WorkspaceView extends View
|
||||
@panes.getPaneViews()
|
||||
|
||||
# Public: Register a function to be called for every current and future
|
||||
# editor view in the workspace.
|
||||
# editor view in the workspace (only includes {EditorView}s that are pane
|
||||
# items).
|
||||
#
|
||||
# callback - A {Function} with an {EditorView} as its only argument.
|
||||
#
|
||||
# Returns a subscription object with an `.off` method that you can call to
|
||||
# unregister the callback.
|
||||
eachEditorView: (callback) ->
|
||||
callback(editor) for editor in @getEditorViews()
|
||||
attachedCallback = (e, editor) -> callback(editor)
|
||||
callback(editorView) for editorView in @getEditorViews()
|
||||
attachedCallback = (e, editorView) ->
|
||||
callback(editorView) unless editorView.mini
|
||||
@on('editor:attached', attachedCallback)
|
||||
off: => @off('editor:attached', attachedCallback)
|
||||
|
||||
|
||||
+18
-4
@@ -84,6 +84,8 @@ class Workspace extends Model
|
||||
# options - An optional options {Object}
|
||||
# :initialLine - A {Number} indicating which row to move the cursor to
|
||||
# initially. Defaults to `0`.
|
||||
# :initialColumn - A {Number} indicating which column to move the cursor to
|
||||
# initially. Defaults to `0`.
|
||||
# :split - Either 'left' or 'right'. If 'left', the item will be opened in
|
||||
# leftmost pane of the current active pane's row. If 'right', the
|
||||
# item will be opened in the rightmost pane of the current active
|
||||
@@ -114,7 +116,7 @@ class Workspace extends Model
|
||||
|
||||
# Public: Open Atom's license in the active pane.
|
||||
openLicense: ->
|
||||
@open(join(atom.getLoadSettings().resourcePath, 'LICENSE'))
|
||||
@open(join(atom.getLoadSettings().resourcePath, 'LICENSE.md'))
|
||||
|
||||
# Synchronously open the given URI in the active pane. **Only use this method
|
||||
# in specs. Calling this in production code will block the UI thread and
|
||||
@@ -124,12 +126,14 @@ class Workspace extends Model
|
||||
# options - An optional options {Object}
|
||||
# :initialLine - A {Number} indicating which row to move the cursor to
|
||||
# initially. Defaults to `0`.
|
||||
# :initialColumn - A {Number} indicating which column to move the cursor to
|
||||
# initially. Defaults to `0`.
|
||||
# :activatePane - A {Boolean} indicating whether to call {Pane::activate} on
|
||||
# the containing pane. Defaults to `true`.
|
||||
openSync: (uri='', options={}) ->
|
||||
deprecate("Don't use the `changeFocus` option") if options.changeFocus?
|
||||
|
||||
{initialLine} = options
|
||||
{initialLine, initialColumn} = options
|
||||
# TODO: Remove deprecated changeFocus option
|
||||
activatePane = options.activatePane ? options.changeFocus ? true
|
||||
uri = atom.project.resolve(uri)
|
||||
@@ -137,7 +141,7 @@ class Workspace extends Model
|
||||
item = @activePane.itemForUri(uri)
|
||||
if uri
|
||||
item ?= opener(uri, options) for opener in @getOpeners() when !item
|
||||
item ?= atom.project.openSync(uri, {initialLine})
|
||||
item ?= atom.project.openSync(uri, {initialLine, initialColumn})
|
||||
|
||||
@activePane.activateItem(item)
|
||||
@itemOpened(item)
|
||||
@@ -165,9 +169,19 @@ class Workspace extends Model
|
||||
.catch (error) ->
|
||||
console.error(error.stack ? error)
|
||||
|
||||
# Public: Reopen the last-closed item's URI if it hasn't already been
|
||||
# Public: Asynchronously reopens the last-closed item's URI if it hasn't already been
|
||||
# reopened.
|
||||
#
|
||||
# Returns a promise that is resolved when the item is opened
|
||||
reopenItem: ->
|
||||
if uri = @destroyedItemUris.pop()
|
||||
@open(uri)
|
||||
else
|
||||
Q()
|
||||
|
||||
# Deprecated
|
||||
reopenItemSync: ->
|
||||
deprecate("Use Workspace::reopenItem instead")
|
||||
if uri = @destroyedItemUris.pop()
|
||||
@openSync(uri)
|
||||
|
||||
|
||||
@@ -14,6 +14,10 @@
|
||||
|
||||
.lines {
|
||||
z-index: -1;
|
||||
|
||||
.line {
|
||||
position: absolute;
|
||||
}
|
||||
}
|
||||
|
||||
.horizontal-scrollbar {
|
||||
@@ -32,6 +36,17 @@
|
||||
}
|
||||
}
|
||||
|
||||
.vertical-scrollbar {
|
||||
overflow-x: hidden;
|
||||
}
|
||||
|
||||
.scrollbar-corner {
|
||||
position: absolute;
|
||||
overflow: auto;
|
||||
bottom: 0;
|
||||
right: 0;
|
||||
}
|
||||
|
||||
.scroll-view {
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
externo
-1
Submodule vendor/apm deleted from d349e45263
Referência em uma Nova Issue
Bloquear um usuário