Comparar commits

..

1 Commits

Autor SHA1 Mensagem Data
Ivan Zuzak 0a0e848e7b Show devtools console for all console errors 2014-06-23 12:58:26 +02:00
60 arquivos alterados com 814 adições e 1765 exclusões
-2
Ver Arquivo
@@ -13,5 +13,3 @@ debug.log
docs/output
docs/includes
spec/fixtures/evil-files/
resources/linux/Atom.desktop
resources/linux/debian/control
-1
Ver Arquivo
@@ -11,7 +11,6 @@ pairs:
bo: Ben Ogle; benogle
jr: Jason Rudolph; jasonrudolph
jl: Jessica Lord; jlord
dh: Daniel Hengeveld; danielh
email:
domain: github.com
#global: true
+1 -1
Ver Arquivo
@@ -6,6 +6,6 @@
"url": "https://github.com/atom/atom.git"
},
"dependencies": {
"atom-package-manager": "0.70.0"
"atom-package-manager": "0.69.0"
}
}
+4 -10
Ver Arquivo
@@ -39,25 +39,21 @@ module.exports = (grunt) ->
tmpDir = os.tmpdir()
appName = if process.platform is 'darwin' then 'Atom.app' else 'Atom'
buildDir = grunt.option('build-dir') ? path.join(tmpDir, 'atom-build')
installDir = grunt.option('install-dir')
atomShellDownloadDir = path.join(os.tmpdir(), 'atom-cached-atom-shells')
symbolsDir = path.join(buildDir, 'Atom.breakpad.syms')
shellAppDir = path.join(buildDir, appName)
if process.platform is 'win32'
contentsDir = shellAppDir
appDir = path.join(shellAppDir, 'resources', 'app')
installDir ?= path.join(process.env.ProgramFiles, appName)
killCommand = 'taskkill /F /IM atom.exe'
installDir = path.join(process.env.ProgramFiles, appName)
else if process.platform is 'darwin'
contentsDir = path.join(shellAppDir, 'Contents')
appDir = path.join(contentsDir, 'Resources', 'app')
installDir ?= path.join('/Applications', appName)
killCommand = 'pkill -9 Atom'
installDir = path.join('/Applications', appName)
else
contentsDir = shellAppDir
appDir = path.join(shellAppDir, 'resources', 'app')
installDir ?= process.env.INSTALL_PREFIX ? '/usr/local'
killCommand ='pkill -9 Atom'
installDir = process.env.INSTALL_PREFIX ? '/usr/local'
coffeeConfig =
glob_to_multiple:
@@ -125,8 +121,6 @@ module.exports = (grunt) ->
atom: {appDir, appName, symbolsDir, buildDir, contentsDir, installDir, shellAppDir}
docsOutputDir: 'docs/output/api'
coffee: coffeeConfig
less: lessConfig
@@ -216,7 +210,7 @@ module.exports = (grunt) ->
shell:
'kill-atom':
command: killCommand
command: 'pkill -9 Atom'
options:
stdout: false
stderr: false
+1 -1
Ver Arquivo
@@ -13,7 +13,7 @@
"github-releases": "~0.2.0",
"grunt": "~0.4.1",
"grunt-cli": "~0.1.9",
"grunt-coffeelint": "git+https://github.com/atom/grunt-coffeelint.git",
"grunt-coffeelint": "git://github.com/atom/grunt-coffeelint.git",
"grunt-contrib-csslint": "~0.1.2",
"grunt-contrib-coffee": "~0.9.0",
"grunt-contrib-less": "~0.8.0",
-15
Ver Arquivo
@@ -51,17 +51,7 @@ module.exports = (grunt) ->
path.join('pegjs', 'examples')
path.join('plist', 'tests')
path.join('xmldom', 'test')
path.join('combined-stream', 'test')
path.join('delayed-stream', 'test')
path.join('domhandler', 'test')
path.join('fstream-ignore', 'test')
path.join('harmony-collections', 'test')
path.join('lru-cache', 'test')
path.join('minimatch', 'test')
path.join('normalize-package-data', 'test')
path.join('npm', 'test')
path.join('jasmine-reporters', 'ext')
path.join('jasmine-node', 'node_modules', 'gaze')
path.join('build', 'Release', 'obj.target')
path.join('build', 'Release', 'obj')
path.join('build', 'Release', '.deps')
@@ -100,11 +90,6 @@ module.exports = (grunt) ->
cp path.join('resources', 'win', 'msvcp100.dll'), path.join(shellAppDir, 'msvcp100.dll')
cp path.join('resources', 'win', 'msvcr100.dll'), path.join(shellAppDir, 'msvcr100.dll')
# Set up chocolatey ignore and gui files
fs.writeFileSync path.join(appDir, 'apm', 'node_modules', 'atom-package-manager', 'bin', 'node.exe.ignore'), ''
fs.writeFileSync path.join(appDir, 'node_modules', 'symbols-view', 'vendor', 'ctags-win32.exe.ignore'), ''
fs.writeFileSync path.join(shellAppDir, 'atom.exe.gui'), ''
dependencies = ['compile', "generate-license:save"]
dependencies.push('copy-info-plist') if process.platform is 'darwin'
dependencies.push('set-exe-icon') if process.platform is 'win32'
+6 -15
Ver Arquivo
@@ -1,12 +1,12 @@
path = require 'path'
module.exports = (grunt) ->
{spawn} = require('./task-helpers')(grunt)
grunt.registerTask 'codesign', 'Codesign the app', ->
return unless process.platform is 'darwin'
done = @async()
if process.platform is 'darwin' and process.env.XCODE_KEYCHAIN
if process.env.XCODE_KEYCHAIN
unlockKeychain (error) ->
if error?
done(error)
@@ -22,15 +22,6 @@ module.exports = (grunt) ->
spawn {cmd, args}, (error) -> callback(error)
signApp = (callback) ->
switch process.platform
when 'darwin'
cmd = 'codesign'
args = ['-f', '-v', '-s', 'Developer ID Application: GitHub', grunt.config.get('atom.shellAppDir')]
spawn {cmd, args}, (error) -> callback(error)
when 'win32'
spawn {cmd: 'taskkill', args: ['/F', '/IM', 'atom.exe']}, ->
cmd = process.env.JANKY_SIGNTOOL ? 'signtool'
args = [path.join(grunt.config.get('atom.shellAppDir'), 'atom.exe')]
spawn {cmd, args}, (error) -> callback(error)
else
callback()
cmd = 'codesign'
args = ['-f', '-v', '-s', 'Developer ID Application: GitHub', grunt.config.get('atom.shellAppDir')]
spawn {cmd, args}, (error) -> callback(error)
+2 -4
Ver Arquivo
@@ -15,17 +15,15 @@ module.exports = (grunt) ->
grunt.registerTask 'build-docs', 'Builds the API docs in src', ->
done = @async()
docsOutputDir = grunt.config.get('docsOutputDir')
downloadIncludes (error, includePaths) ->
if error?
done(error)
else
rm(docsOutputDir)
rm('docs/output/api')
args = [
commonArgs...
'--title', 'Atom API Documentation'
'-o', docsOutputDir
'-o', 'docs/output/api'
'-r', 'docs/README.md'
'--stability', '1'
'src/'
+4 -6
Ver Arquivo
@@ -40,15 +40,13 @@ module.exports = (grunt) ->
mkdir path.dirname(shareDir)
cp shellAppDir, shareDir
# Create Atom.desktop if installation not in temporary folder
# Create Atom.desktop if installation in '/usr/local'
applicationsDir = path.join('/usr','share','applications')
tmpDir = if process.env.TMPDIR? then process.env.TMPDIR else '/tmp'
desktopInstallFile = path.join(installDir,'share','applications','Atom.desktop')
if installDir.indexOf(tmpDir) isnt 0
mkdir path.dirname(desktopInstallFile)
if installDir.indexOf(tmpDir) isnt 0 and fs.isDirectorySync(applicationsDir)
{description} = grunt.file.readJSON('package.json')
installDir = path.join(installDir,'.') # To prevent "Exec=/usr/local//share/atom/atom"
fillTemplate(desktopFile, {description, installDir, iconName})
cp desktopFile, desktopInstallFile
cp desktopFile, path.join(applicationsDir,'Atom.desktop')
# Create relative symbol link for apm.
process.chdir(binDir)
-18
Ver Arquivo
@@ -1,18 +0,0 @@
path = require 'path'
module.exports = (grunt) ->
grunt.registerTask 'output-long-paths', 'Log long paths in the built application', ->
shellAppDir = grunt.config.get('atom.shellAppDir')
longPaths = []
grunt.file.recurse shellAppDir, (absolutePath, rootPath, relativePath, fileName) ->
if relativePath
fullPath = path.join(relativePath, fileName)
else
fullPath = fileName
longPaths.push(fullPath) if fullPath.length >= 200
longPaths.sort (longPath1, longPath2) -> longPath2.length - longPath1.length
longPaths.forEach (longPath) ->
grunt.log.error "#{longPath.length} character path: #{longPath}"
+19 -29
Ver Arquivo
@@ -9,6 +9,16 @@ request = require 'request'
grunt = null
if process.platform is 'darwin'
assets = [
{assetName: 'atom-mac.zip', sourceName: 'Atom.app'}
{assetName: 'atom-mac-symbols.zip', sourceName: 'Atom.breakpad.syms'}
]
else
assets = [
{assetName: 'atom-windows.zip', sourceName: 'Atom'}
]
commitSha = process.env.JANKY_SHA1
token = process.env.ATOM_ACCESS_TOKEN
defaultHeaders =
@@ -20,19 +30,11 @@ module.exports = (gruntObject) ->
grunt.registerTask 'publish-build', 'Publish the built app', ->
return if process.env.JANKY_SHA1 and process.env.JANKY_BRANCH isnt 'master'
tasks = ['upload-assets']
tasks.unshift('build-docs', 'prepare-docs') if process.platform is 'darwin'
grunt.task.run(tasks)
grunt.registerTask 'prepare-docs', 'Move the build docs to the build dir', ->
fs.copySync(grunt.config.get('docsOutputDir'), path.join(grunt.config.get('atom.buildDir'), 'atom-docs'))
grunt.registerTask 'upload-assets', 'Upload the assets to a GitHub release', ->
done = @async()
buildDir = grunt.config.get('atom.buildDir')
assets = getAssets()
zipAssets buildDir, assets, (error) ->
zipApps buildDir, assets, (error) ->
return done(error) if error?
getAtomDraftRelease (error, release) ->
return done(error) if error?
@@ -41,38 +43,26 @@ module.exports = (gruntObject) ->
return done(error) if error?
uploadAssets(release, buildDir, assets, done)
getAssets = ->
if process.platform is 'darwin'
[
{assetName: 'atom-mac.zip', sourcePath: 'Atom.app'}
{assetName: 'atom-mac-symbols.zip', sourcePath: 'Atom.breakpad.syms'}
{assetName: 'atom-docs.zip', sourcePath: 'atom-docs'}
]
else
[
{assetName: 'atom-windows.zip', sourcePath: 'Atom'}
]
logError = (message, error, details) ->
grunt.log.error(message)
grunt.log.error(error.message ? error) if error?
grunt.log.error(details) if details
zipAssets = (buildDir, assets, callback) ->
zip = (directory, sourcePath, assetName, callback) ->
zipApps = (buildDir, assets, callback) ->
zip = (directory, sourceName, assetName, callback) ->
if process.platform is 'win32'
zipCommand = "C:/psmodules/7z.exe a -r #{assetName} #{sourcePath}"
zipCommand = "C:/psmodules/7z.exe a -r #{assetName} #{sourceName}"
else
zipCommand = "zip -r --symlinks #{assetName} #{sourcePath}"
zipCommand = "zip -r --symlinks #{assetName} #{sourceName}"
options = {cwd: directory, maxBuffer: Infinity}
child_process.exec zipCommand, options, (error, stdout, stderr) ->
logError("Zipping #{sourcePath} failed", error, stderr) if error?
logError("Zipping #{sourceName} failed", error, stderr) if error?
callback(error)
tasks = []
for {assetName, sourcePath} in assets
for {assetName, sourceName} in assets
fs.removeSync(path.join(buildDir, assetName))
tasks.push(zip.bind(this, buildDir, sourcePath, assetName))
tasks.push(zip.bind(this, buildDir, sourceName, assetName))
async.parallel(tasks, callback)
getAtomDraftRelease = (callback) ->
@@ -137,7 +127,7 @@ uploadAssets = (release, buildDir, assets, callback) ->
fs.createReadStream(assetPath).pipe(assetRequest)
tasks = []
for {assetName} in assets
for {assetName, sourceName} in assets
assetPath = path.join(buildDir, assetName)
tasks.push(upload.bind(this, release, assetName, assetPath))
async.parallel(tasks, callback)
+4 -7
Ver Arquivo
@@ -53,7 +53,9 @@ module.exports = (grunt) ->
continue unless isAtomPackage(packagePath)
packageSpecQueue.push(packagePath)
packageSpecQueue.concurrency = 1
# TODO: Restore concurrency on Windows
packageSpecQueue.concurrency = 1 unless process.platform is 'win32'
packageSpecQueue.drain = -> callback(null, failedPackages)
runCoreSpecs = (callback) ->
@@ -103,9 +105,4 @@ module.exports = (grunt) ->
failures.push "atom core" if coreSpecFailed
grunt.log.error("[Error]".red + " #{failures.join(', ')} spec(s) failed") if failures.length > 0
if process.platform is 'win32' and process.env.JANKY_SHA1
# Package specs are still flaky on Windows CI
done(!coreSpecFailed)
else
done(!coreSpecFailed and failedPackages.length == 0)
done(!coreSpecFailed and failedPackages.length == 0)
+22 -12
Ver Arquivo
@@ -11,31 +11,41 @@ value of a namespaced config key with `atom.config.get`:
@showInvisibles() if atom.config.get "editor.showInvisibles"
```
Or you can use the `::subscribe` with `atom.config.observe` to track changes
from any view object.
Or you can use the `::observeConfig` to track changes from any view object.
```coffeescript
class MyView extends View
initialize: ->
@subscribe atom.config.observe 'editor.fontSize', (newValue, {previous}) =>
@observeConfig 'editor.fontSize', () =>
@adjustFontSize()
```
The `atom.config.observe` method will call the given callback immediately with
the current value for the specified key path, and it will also call it in the
future whenever the value of that key path changes.
The `::observeConfig` method will call the given callback immediately with the
current value for the specified key path, and it will also call it in the future
whenever the value of that key path changes.
Subscriptions made with `::subscribe` are automatically canceled when the
Subscriptions made with `observeConfig` are automatically canceled when the
view is removed. You can cancel config subscriptions manually via the
`off` method on the subscription object that `atom.config.observe` returns.
`unobserveConfig` method.
```coffeescript
fontSizeSubscription = atom.config.observe 'editor.fontSize', (newValue, {previous}) =>
@adjustFontSize()
view1.unobserveConfig() # unobserve all properties
```
# ... later on
You can add the ability to observe config values to non-view classes by
extending their prototype with the `ConfigObserver` mixin:
fontSizeSubscription.off() # Stop observing
```coffeescript
{ConfigObserver} = require 'atom'
class MyClass
ConfigObserver.includeInto(this)
constructor: ->
@observeConfig 'editor.showInvisibles', -> # ...
destroy: ->
@unobserveConfig()
```
### Writing Config Settings
+2 -15
Ver Arquivo
@@ -198,19 +198,6 @@ Unstar a package; requires authentication.
Returns 204 No Content.
#### GET /api/packages/:name/stargazers
List the users that have starred a package.
Returns a list of user objects:
```json
[
{"login":"aperson"},
{"login":"anotherperson"},
]
```
### Atom updates
#### GET /api/updates
@@ -219,10 +206,10 @@ Atom update feed, following the format expected by [Squirrel](https://github.com
Returns:
```json
```
{
"name": "0.96.0",
"notes": "[HTML release notes]",
"notes": "[HTML release notes]"
"pub_date": "2014-05-19T15:52:06.000Z",
"url": "https://www.atom.io/api/updates/download"
}
-7
Ver Arquivo
@@ -61,13 +61,6 @@ and restart Atom. If Atom now works fine, you can make this setting permanent:
See also https://github.com/atom/atom/issues/2082.
### /usr/bin/env: node: No such file or directory
If you get this notice when attempting to `script/build`, you either do not
have nodejs installed, or node isn't identified as nodejs on your machine.
If it's the latter, entering `sudo ln -s /usr/bin/nodejs /usr/bin/node` into
your terminal may fix the issue.
### Linux build error reports in atom/atom
* Use [this search](https://github.com/atom/atom/search?q=label%3Abuild-error+label%3Alinux&type=Issues)
to get a list of reports about build errors on Linux.
+1 -1
Ver Arquivo
@@ -169,7 +169,7 @@ For example, to change the color of the cursor, you could add the following
rule to your _~/.atom/styles.less_ file:
```less
.editor.is-focused .cursor {
.editor .cursor {
border-color: pink;
}
```
+1 -69
Ver Arquivo
@@ -38,7 +38,7 @@ Atom uses [Jasmine](http://jasmine.github.io/2.0/introduction.html) as its spec
0. Add one or more expectations
The best way to learn about expectations is to read the [jasmine documentation](http://jasmine.github.io/1.3/introduction.html#section-Expectations) about them. Below is a simple example.
The best way to learn about expectations is to read the [jasmine documentation](http://jasmine.github.io/2.0/introduction.html#section-Expectations) about them. Below is a simple example.
```coffee
describe "when a test is written", ->
@@ -47,74 +47,6 @@ Atom uses [Jasmine](http://jasmine.github.io/2.0/introduction.html) as its spec
expect("oranges").not.toEqual("apples")
```
## Asynchronous specs
Writing Asynchronous specs can be tricky at first. Some examples.
0. Promises
Working with promises is rather easy in Atom. You can use our `waitsForPromise` function.
```coffee
describe "when we open a file", ->
it "should be opened in an editor", ->
waitsForPromise ->
atom.workspace.open('c.coffee').then (editor) ->
expect(editor.getPath()).toContain 'c.coffee'
```
This method can be used in the `describe`, `it`, `beforeEach` and `afterEach` functions.
```coffee
describe "when we open a file", ->
beforeEach ->
waitsForPromise ->
atom.workspace.open 'c.coffee'
it "should be opened in an editor", ->
expect(atom.workspace.getActiveEditor().getPath()).toContain 'c.coffee'
```
If you need to wait for multiple promises use a new `waitsForPromise` function for each promise. (Caution: Without `beforeEach` this example will fail!)
```coffee
describe "waiting for the packages to load", ->
beforeEach ->
waitsForPromise ->
atom.workspace.open('sample.js')
waitsForPromise ->
atom.packages.activatePackage('tabs')
waitsForPromise ->
atom.packages.activatePackage('tree-view')
it 'should have waited long enough', ->
expect(atom.packages.isPackageActive('tabs')).toBe true
expect(atom.packages.isPackageActive('tree-view')).toBe true
```
0. Asynchronous functions with callbacks
Specs for asynchronous functions can be done using the `waitsFor` and `runs` functions. A simple example.
```coffee
describe "fs.readdir(path, cb)", ->
it "is async", ->
spy = jasmine.createSpy('fs.readdirSpy')
fs.readdir('/tmp/example', spy)
waitsFor ->
spy.callCount > 0
runs ->
exp = [null, ['example.coffee']]
expect(spy.mostRecentCall.args).toEqual exp
expect(spy).toHaveBeenCalledWith(null, ['example.coffee'])
```
For a more detailed documentation on asynchronous tests please visit the [jasmine documentation](http://jasmine.github.io/1.3/introduction.html#section-Asynchronous_Support).
## Running specs
Most of the time you'll want to run specs by triggering the `window:run-package-specs` command. This command is not only to run package specs, it is also for Atom core specs. This will run all the specs in the current project's spec directory. If you want to run the Atom core specs and **all** the default package specs trigger the `window:run-all-specs` command.
-2
Ver Arquivo
@@ -69,8 +69,6 @@
'cmd-}': 'pane:show-next-item'
'cmd-alt-left': 'pane:show-previous-item'
'cmd-alt-right': 'pane:show-next-item'
'ctrl-pageup': 'pane:show-previous-item'
'ctrl-pagedown': 'pane:show-next-item'
'ctrl-tab': 'pane:show-next-item'
'ctrl-shift-tab': 'pane:show-previous-item'
'cmd-=': 'window:increase-font-size'
-2
Ver Arquivo
@@ -45,8 +45,6 @@
'shift-backspace': 'core:backspace'
'ctrl-tab': 'pane:show-next-item'
'ctrl-shift-tab': 'pane:show-previous-item'
'ctrl-pageup': 'pane:show-previous-item'
'ctrl-pagedown': 'pane:show-next-item'
'ctrl-shift-up': 'core:move-up'
'ctrl-shift-down': 'core:move-down'
'ctrl-=': 'window:increase-font-size'
-2
Ver Arquivo
@@ -47,8 +47,6 @@
'shift-backspace': 'core:backspace'
'ctrl-tab': 'pane:show-next-item'
'ctrl-shift-tab': 'pane:show-previous-item'
'ctrl-pageup': 'pane:show-previous-item'
'ctrl-pagedown': 'pane:show-next-item'
'ctrl-shift-up': 'core:move-up'
'ctrl-shift-down': 'core:move-down'
'ctrl-alt-up': 'editor:add-selection-above'
+41 -42
Ver Arquivo
@@ -1,7 +1,7 @@
{
"name": "atom",
"productName": "Atom",
"version": "0.111.0",
"version": "0.107.0",
"description": "A hackable text editor for the 21st Century.",
"main": "./src/browser/main.js",
"repository": {
@@ -17,7 +17,7 @@
"url": "http://github.com/atom/atom/raw/master/LICENSE.md"
}
],
"atomShellVersion": "0.13.3",
"atomShellVersion": "0.13.2",
"dependencies": {
"async": "0.2.6",
"atom-keymap": "^0.27.0",
@@ -27,7 +27,7 @@
"coffeestack": "0.7.0",
"delegato": "^1",
"emissary": "^1.2.1",
"first-mate": "^1.7.1",
"first-mate": "^1.7",
"fs-plus": "^2.2.3",
"fstream": "0.1.24",
"fuzzaldrin": "^1.1",
@@ -47,8 +47,8 @@
"random-words": "0.0.1",
"react-atom-fork": "^0.10.0",
"reactionary-atom-fork": "^0.9.0",
"runas": "0.5.4",
"scandal": "0.16.0",
"runas": "^0.5",
"scandal": "0.15.3",
"scoped-property-store": "^0.9.0",
"scrollbar-style": "^0.4.0",
"season": "^1.0.2",
@@ -62,81 +62,80 @@
"vm-compatibility-layer": "0.1.0"
},
"packageDependencies": {
"atom-dark-syntax": "0.19.0",
"atom-dark-ui": "0.32.0",
"atom-light-syntax": "0.20.0",
"atom-light-ui": "0.28.0",
"base16-tomorrow-dark-theme": "0.19.0",
"solarized-dark-syntax": "0.20.0",
"solarized-light-syntax": "0.11.0",
"atom-dark-syntax": "0.17.0",
"atom-dark-ui": "0.29.0",
"atom-light-syntax": "0.18.0",
"atom-light-ui": "0.25.0",
"base16-tomorrow-dark-theme": "0.17.0",
"solarized-dark-syntax": "0.18.0",
"solarized-light-syntax": "0.9.0",
"archive-view": "0.33.0",
"autocomplete": "0.28.0",
"autoflow": "0.17.0",
"autosave": "0.14.0",
"background-tips": "0.15.0",
"bookmarks": "0.27.0",
"bracket-matcher": "0.48.0",
"command-palette": "0.24.0",
"background-tips": "0.14.0",
"bookmarks": "0.25.0",
"bracket-matcher": "0.47.0",
"command-palette": "0.23.0",
"deprecation-cop": "0.7.0",
"dev-live-reload": "0.31.0",
"exception-reporting": "0.18.0",
"feedback": "0.33.0",
"find-and-replace": "0.125.0",
"fuzzy-finder": "0.56.0",
"git-diff": "0.35.0",
"find-and-replace": "0.120.0",
"fuzzy-finder": "0.55.0",
"git-diff": "0.34.0",
"go-to-line": "0.23.0",
"grammar-selector": "0.27.0",
"image-view": "0.36.0",
"image-view": "0.35.0",
"keybinding-resolver": "0.18.0",
"link": "0.24.0",
"markdown-preview": "0.90.0",
"markdown-preview": "0.83.0",
"metrics": "0.32.0",
"open-on-github": "0.29.0",
"open-on-github": "0.28.0",
"package-generator": "0.31.0",
"release-notes": "0.32.0",
"settings-view": "0.132.0",
"snippets": "0.47.0",
"settings-view": "0.128.0",
"snippets": "0.46.0",
"spell-check": "0.38.0",
"status-bar": "0.41.0",
"styleguide": "0.29.0",
"symbols-view": "0.59.0",
"tabs": "0.44.0",
"timecop": "0.21.0",
"tree-view": "0.108.0",
"symbols-view": "0.56.0",
"tabs": "0.42.0",
"timecop": "0.19.0",
"tree-view": "0.104.0",
"update-package-dependencies": "0.6.0",
"welcome": "0.17.0",
"whitespace": "0.23.0",
"wrap-guide": "0.21.0",
"welcome": "0.16.0",
"whitespace": "0.22.0",
"wrap-guide": "0.19.0",
"language-c": "0.21.0",
"language-coffee-script": "0.24.0",
"language-coffee-script": "0.22.0",
"language-css": "0.17.0",
"language-gfm": "0.42.0",
"language-gfm": "0.40.0",
"language-git": "0.9.0",
"language-go": "0.13.0",
"language-go": "0.12.0",
"language-html": "0.22.0",
"language-hyperlink": "0.10.0",
"language-java": "0.11.0",
"language-javascript": "0.33.0",
"language-java": "0.10.0",
"language-javascript": "0.28.0",
"language-json": "0.8.0",
"language-less": "0.12.0",
"language-less": "0.9.0",
"language-make": "0.10.0",
"language-objective-c": "0.11.0",
"language-perl": "0.9.0",
"language-php": "0.15.0",
"language-property-list": "0.7.0",
"language-python": "0.18.0",
"language-ruby": "0.32.0",
"language-ruby-on-rails": "0.15.0",
"language-ruby": "0.30.0",
"language-ruby-on-rails": "0.14.0",
"language-sass": "0.13.0",
"language-shellscript": "0.8.0",
"language-source": "0.7.0",
"language-sql": "0.9.0",
"language-sql": "0.8.0",
"language-text": "0.6.0",
"language-todo": "0.10.0",
"language-toml": "0.12.0",
"language-xml": "0.15.0",
"language-yaml": "0.11.0"
"language-yaml": "0.7.0"
},
"private": true,
"scripts": {
+6 -22
Ver Arquivo
@@ -31,7 +31,7 @@ function bootstrap() {
fs.mkdirSync(path.join(apmInstallPath, 'node_modules'));
var apmPath = path.resolve(__dirname, '..', 'apm', 'node_modules', 'atom-package-manager', 'bin', 'apm')
var apmFlags = process.env.JANKY_SHA1 || process.argv.indexOf('--no-color') !== -1 ? ' --no-color' : '';
var apmFlags = process.env.JANKY_SHA1 || process.argv.indexOf('--no-color') !== -1 ? '--no-color' : '';
var npmPath = path.resolve(__dirname, '..', 'build', 'node_modules', '.bin', 'npm');
var initialNpmCommand = fs.existsSync(npmPath) ? npmPath : 'npm';
@@ -39,28 +39,12 @@ function bootstrap() {
var packagesToDedupe = ['fs-plus', 'humanize-plus', 'oniguruma', 'roaster', 'season', 'grim'];
var buildInstallCommand = initialNpmCommand + npmFlags + 'install';
var buildInstallOptions = {cwd: path.resolve(__dirname, '..', 'build')};
var apmInstallCommand = npmPath + npmFlags + 'install';
var apmInstallOptions = {cwd: apmInstallPath};
var moduleInstallCommand = apmPath + ' install' + apmFlags;
var dedupeCommand = apmPath + ' dedupe' + apmFlags;
if (process.argv.indexOf('--no-quiet') === -1) {
buildInstallCommand += ' --quiet';
apmInstallCommand += ' --quiet';
moduleInstallCommand += ' --quiet';
dedupeCommand += ' --quiet';
buildInstallOptions.ignoreStdout = true;
apmInstallOptions.ignoreStdout = true;
}
var commands = [
{command: buildInstallCommand, message: 'Installing build modules...', options: buildInstallOptions},
{command: apmInstallCommand, message: 'Installing apm...', options: apmInstallOptions},
apmPath + ' clean' + apmFlags,
moduleInstallCommand,
dedupeCommand + ' ' + packagesToDedupe.join(' '),
{command: initialNpmCommand + npmFlags + 'install --quiet', message: 'Installing build modules...', options: {cwd: path.resolve(__dirname, '..', 'build'), ignoreStdout: true}},
{command: npmPath + npmFlags + 'install --quiet', message: 'Installing apm...', options: {cwd: apmInstallPath, ignoreStdout: true}},
apmPath + ' clean ' + apmFlags,
apmPath + ' install --quiet ' + apmFlags,
apmPath + ' dedupe --quiet ' + apmFlags + ' ' + packagesToDedupe.join(' '),
];
process.chdir(path.dirname(__dirname));
-27
Ver Arquivo
@@ -17,33 +17,6 @@ describe "ContextMenuManager", ->
expect(contextMenu.definitions['.selector'][0].label).toEqual 'label'
expect(contextMenu.definitions['.selector'][0].command).toEqual 'command'
it 'does not add duplicate menu items', ->
contextMenu.add 'file-path',
'.selector':
'label': 'command'
contextMenu.add 'file-path',
'.selector':
'label': 'command'
expect(contextMenu.definitions['.selector'][0].label).toEqual 'label'
expect(contextMenu.definitions['.selector'][0].command).toEqual 'command'
expect(contextMenu.definitions['.selector'].length).toBe 1
it 'allows duplicate commands with different labels', ->
contextMenu.add 'file-path',
'.selector':
'label': 'command'
contextMenu.add 'file-path',
'.selector':
'another label': 'command'
expect(contextMenu.definitions['.selector'][0].label).toEqual 'label'
expect(contextMenu.definitions['.selector'][0].command).toEqual 'command'
expect(contextMenu.definitions['.selector'][1].label).toEqual 'another label'
expect(contextMenu.definitions['.selector'][1].command).toEqual 'command'
it "loads submenus", ->
contextMenu.add 'file-path',
'.selector':
+7 -109
Ver Arquivo
@@ -47,15 +47,6 @@ describe "DisplayBuffer", ->
buffer.insert([0,0], oneHundredLines)
expect(displayBuffer.getLineCount()).toBe 100 + originalLineCount
it "reassigns the scrollTop if it exceeds the max possible value after lines are removed", ->
displayBuffer.manageScrollPosition = true
displayBuffer.setHeight(50)
displayBuffer.setLineHeightInPixels(10)
displayBuffer.setScrollTop(80)
buffer.delete([[8, 0], [10, 0]])
expect(displayBuffer.getScrollTop()).toBe 60
describe "soft wrapping", ->
beforeEach ->
displayBuffer.setSoftWrap(true)
@@ -215,19 +206,6 @@ describe "DisplayBuffer", ->
displayBuffer.setEditorWidthInChars(-1)
expect(displayBuffer.editorWidthInChars).not.toBe -1
it "sets ::scrollLeft to 0 and keeps it there when soft wrapping is enabled", ->
displayBuffer.setDefaultCharWidth(10)
displayBuffer.setWidth(50)
displayBuffer.manageScrollPosition = true
displayBuffer.setSoftWrap(false)
displayBuffer.setScrollLeft(Infinity)
expect(displayBuffer.getScrollLeft()).toBeGreaterThan 0
displayBuffer.setSoftWrap(true)
expect(displayBuffer.getScrollLeft()).toBe 0
displayBuffer.setScrollLeft(10)
expect(displayBuffer.getScrollLeft()).toBe 0
describe "primitive folding", ->
beforeEach ->
displayBuffer.destroy()
@@ -337,16 +315,6 @@ describe "DisplayBuffer", ->
expect(line0.fold).toBe outerFold
expect(line1.fold).toBeUndefined()
describe "when a fold ends where another fold begins", ->
it "continues to hide the lines inside the second fold", ->
fold2 = displayBuffer.createFold(4, 9)
fold1 = displayBuffer.createFold(0, 4)
displayBuffer.logLines(0, 20)
expect(displayBuffer.lineForRow(0).text).toMatch /^0/
expect(displayBuffer.lineForRow(1).text).toMatch /^10/
describe "when there is another display buffer pointing to the same buffer", ->
it "does not create folds in the other display buffer", ->
otherDisplayBuffer = new DisplayBuffer({buffer, tabLength})
@@ -656,19 +624,6 @@ describe "DisplayBuffer", ->
buffer.delete([[6, 0], [6, 65]])
expect(displayBuffer.getMaxLineLength()).toBe 62
it "correctly updates the location of the longest screen line when changes occur", ->
expect(displayBuffer.getLongestScreenRow()).toBe 6
buffer.delete([[0, 0], [2, 0]])
expect(displayBuffer.getLongestScreenRow()).toBe 4
buffer.delete([[4, 0], [5, 0]])
expect(displayBuffer.getLongestScreenRow()).toBe 1
expect(displayBuffer.getMaxLineLength()).toBe 62
buffer.delete([[2, 0], [4, 0]])
expect(displayBuffer.getLongestScreenRow()).toBe 1
expect(displayBuffer.getMaxLineLength()).toBe 62
describe "::destroy()", ->
it "unsubscribes all display buffer markers from their underlying buffer marker (regression)", ->
marker = displayBuffer.markBufferPosition([12, 2])
@@ -1031,44 +986,22 @@ describe "DisplayBuffer", ->
displayBuffer.setLineHeightInPixels(20)
displayBuffer.setDefaultCharWidth(10)
for char in ['r', 'e', 't', 'u', 'r', 'n']
displayBuffer.setScopedCharWidth(["source.js", "keyword.control.js"], char, 11)
displayBuffer.setScopedCharWidths(["source.js", "keyword.control.js"], r: 11, e: 11, t: 11, u: 11, n: 11)
{start, end} = marker.getPixelRange()
expect(start.top).toBe 5 * 20
expect(start.left).toBe (4 * 10) + (6 * 11)
describe "decorations", ->
[marker, decoration, decorationParams] = []
beforeEach ->
marker = displayBuffer.markBufferRange([[2, 13], [3, 15]])
decorationParams = {type: 'gutter', class: 'one'}
decoration = displayBuffer.decorateMarker(marker, decorationParams)
it "can add decorations associated with markers and remove them", ->
expect(decoration).toBeDefined()
expect(decoration.getParams()).toBe decorationParams
expect(displayBuffer.decorationForId(decoration.id)).toBe decoration
decoration = {type: 'gutter', class: 'one'}
marker = displayBuffer.markBufferRange([[2, 13], [3, 15]])
displayBuffer.addDecorationForMarker(marker, decoration)
expect(displayBuffer.decorationsForScreenRowRange(2, 3)[marker.id][0]).toBe decoration
decoration.destroy()
expect(!!displayBuffer.decorationsForScreenRowRange(2, 3)[marker.id]).toBeFalsy()
expect(!!displayBuffer.decorationForId(decoration.id)).toBeFalsy()
it "will not fail if the decoration is removed twice", ->
decoration.destroy()
decoration.destroy()
expect(displayBuffer.decorationForId(decoration.id)).not.toBeDefined()
describe "when a decoration is updated via Decoration::update()", ->
it "emits an 'updated' event containing the new and old params", ->
decoration.on 'updated', updatedSpy = jasmine.createSpy()
decoration.update type: 'gutter', class: 'two'
{oldParams, newParams} = updatedSpy.mostRecentCall.args[0]
expect(oldParams).toEqual decorationParams
expect(newParams).toEqual type: 'gutter', class: 'two', id: decoration.id
displayBuffer.removeDecorationForMarker(marker, decoration)
expect(displayBuffer.decorationsForScreenRowRange(2, 3)[marker.id]).not.toBeDefined()
describe "::setScrollTop", ->
beforeEach ->
@@ -1134,38 +1067,3 @@ describe "DisplayBuffer", ->
it "does not scroll vertically if the position is already in view", ->
displayBuffer.scrollToScreenPosition([4, 20], center: true)
expect(displayBuffer.getScrollTop()).toBe 0
describe "scroll width", ->
cursorWidth = 1
beforeEach ->
displayBuffer.setDefaultCharWidth(10)
it "recomputes the scroll width when the default character width changes", ->
expect(displayBuffer.getScrollWidth()).toBe 10 * 65 + cursorWidth
displayBuffer.setDefaultCharWidth(12)
expect(displayBuffer.getScrollWidth()).toBe 12 * 65 + cursorWidth
it "recomputes the scroll width when the max line length changes", ->
buffer.insert([6, 12], ' ')
expect(displayBuffer.getScrollWidth()).toBe 10 * 66 + cursorWidth
buffer.delete([[6, 10], [6, 12]], ' ')
expect(displayBuffer.getScrollWidth()).toBe 10 * 64 + cursorWidth
it "recomputes the scroll width when the scoped character widths change", ->
operatorWidth = 20
displayBuffer.setScopedCharWidth(['source.js', 'keyword.operator.js'], '<', operatorWidth)
expect(displayBuffer.getScrollWidth()).toBe 10 * 64 + operatorWidth + cursorWidth
it "recomputes the scroll width when the scoped character widths change in a batch", ->
operatorWidth = 20
displayBuffer.on 'character-widths-changed', changedSpy = jasmine.createSpy()
displayBuffer.batchCharacterMeasurement ->
displayBuffer.setScopedCharWidth(['source.js', 'keyword.operator.js'], '<', operatorWidth)
displayBuffer.setScopedCharWidth(['source.js', 'keyword.operator.js'], '?', operatorWidth)
expect(displayBuffer.getScrollWidth()).toBe 10 * 63 + operatorWidth * 2 + cursorWidth
expect(changedSpy.callCount).toBe 1
Diferenças do arquivo suprimidas por serem muito extensas Carregar Diff
-25
Ver Arquivo
@@ -785,19 +785,6 @@ describe "Editor", ->
editor.moveCursorLeft()
expect(editor.getScrollLeft()).toBe 58 * 10
it "scrolls down when inserting lines makes the document longer than the editor's height", ->
editor.setCursorScreenPosition([13, Infinity])
editor.insertNewline()
expect(editor.getScrollBottom()).toBe 14 * 10
editor.insertNewline()
expect(editor.getScrollBottom()).toBe 15 * 10
it "autoscrolls to the cursor when it moves due to undo", ->
editor.insertText('abc')
editor.setScrollTop(Infinity)
editor.undo()
expect(editor.getScrollTop()).toBe 0
describe "selection", ->
selection = null
@@ -1209,7 +1196,6 @@ describe "Editor", ->
editor.setHeight(50)
editor.setWidth(50)
editor.setHorizontalScrollbarHeight(0)
expect(editor.getScrollTop()).toBe 0
editor.setSelectedBufferRange([[5, 6], [6, 8]], autoscroll: true)
@@ -1496,17 +1482,6 @@ describe "Editor", ->
expect(cursor1.getBufferPosition()).toEqual [1, 5]
expect(cursor2.getBufferPosition()).toEqual [2, 7]
it "autoscrolls to the last cursor", ->
editor.manageScrollPosition = true
editor.setCursorScreenPosition([1, 2])
editor.addCursorAtScreenPosition([10, 4])
editor.setLineHeightInPixels(10)
editor.setHeight(50)
expect(editor.getScrollTop()).toBe 0
editor.insertText('a')
expect(editor.getScrollTop()).toBe 80
describe "when there are multiple non-empty selections", ->
describe "when the selections are on the same line", ->
it "replaces each selection range with the inserted characters", ->
-14
Ver Arquivo
@@ -205,20 +205,6 @@ describe "Project", ->
fs.writeFileSync(filePath, sampleContent)
fs.writeFileSync(commentFilePath, sampleCommentContent)
describe "when a file doesn't exist", ->
it "calls back with an error", ->
errors = []
missingPath = path.resolve('/not-a-file.js')
expect(fs.existsSync(missingPath)).toBeFalsy()
waitsForPromise ->
atom.project.replace /items/gi, 'items', [missingPath], (result, error) ->
errors.push(error)
runs ->
expect(errors).toHaveLength 1
expect(errors[0].path).toBe missingPath
describe "when called with unopened files", ->
it "replaces properly", ->
results = []
+1 -1
Ver Arquivo
@@ -37,7 +37,7 @@ jasmine.getEnv().addEqualityTester(_.isEqual) # Use underscore's definition of e
if process.platform is 'win32' and process.env.JANKY_SHA1
# Use longer timeout on Windows CI
jasmine.getEnv().defaultTimeoutInterval = 60000
jasmine.getEnv().defaultTimeoutInterval = 30000
else
jasmine.getEnv().defaultTimeoutInterval = 5000
+4 -68
Ver Arquivo
@@ -335,13 +335,12 @@ describe "TokenizedBuffer", ->
expect(screenLine0.text).toBe "# Econ 101#{tabAsSpaces}"
{ tokens } = screenLine0
expect(tokens.length).toBe 4
expect(tokens.length).toBe 3
expect(tokens[0].value).toBe "#"
expect(tokens[1].value).toBe " Econ 101"
expect(tokens[2].value).toBe tabAsSpaces
expect(tokens[2].scopes).toEqual tokens[1].scopes
expect(tokens[2].isAtomic).toBeTruthy()
expect(tokens[3].value).toBe ""
expect(tokenizedBuffer.lineForScreenRow(2).text).toBe "#{tabAsSpaces} buy()#{tabAsSpaces}while supply > demand"
@@ -412,7 +411,7 @@ describe "TokenizedBuffer", ->
expect(tokenizedBuffer.lineForScreenRow(2).tokens[1].bufferDelta).toBe 1
expect(tokenizedBuffer.lineForScreenRow(2).tokens[1].screenDelta).toBe 1
describe "when the buffer contains UTF-8 surrogate pairs", ->
describe "when the buffer contains surrogate pairs", ->
beforeEach ->
waitsForPromise ->
atom.packages.activatePackage('language-javascript')
@@ -430,7 +429,7 @@ describe "TokenizedBuffer", ->
tokenizedBuffer.destroy()
buffer.release()
it "renders each UTF-8 surrogate pair as its own atomic token", ->
it "renders each surrogate pair as its own atomic token", ->
screenLine0 = tokenizedBuffer.lineForScreenRow(0)
expect(screenLine0.text).toBe "'abc\uD835\uDF97def'"
{ tokens } = screenLine0
@@ -447,12 +446,11 @@ describe "TokenizedBuffer", ->
expect(screenLine1.text).toBe "//\uD835\uDF97xyz"
{ tokens } = screenLine1
expect(tokens.length).toBe 4
expect(tokens.length).toBe 3
expect(tokens[0].value).toBe '//'
expect(tokens[1].value).toBe '\uD835\uDF97'
expect(tokens[1].value).toBeTruthy()
expect(tokens[2].value).toBe 'xyz'
expect(tokens[3].value).toBe ''
describe "when the grammar is tokenized", ->
it "emits the `tokenized` event", ->
@@ -657,65 +655,3 @@ describe "TokenizedBuffer", ->
buffer.setText('\n\n\n')
expect(tokenizedBuffer.lineForScreenRow(1).indentLevel).toBe 0
describe "when the changed lines are surrounded by whitespace-only lines", ->
it "updates the indentLevel of empty lines that precede the change", ->
expect(tokenizedBuffer.lineForScreenRow(12).indentLevel).toBe 0
buffer.insert([12, 0], '\n')
buffer.insert([13, 0], ' ')
expect(tokenizedBuffer.lineForScreenRow(12).indentLevel).toBe 1
it "updates empty line indent guides when the empty line is the last line", ->
buffer.insert([12, 2], '\n')
# The newline and he tab need to be in two different operations to surface the bug
buffer.insert([12, 0], ' ')
expect(tokenizedBuffer.lineForScreenRow(13).indentLevel).toBe 1
buffer.insert([12, 0], ' ')
expect(tokenizedBuffer.lineForScreenRow(13).indentLevel).toBe 2
expect(tokenizedBuffer.lineForScreenRow(14)).not.toBeDefined()
it "updates the indentLevel of empty lines surrounding a change that inserts lines", ->
# create some new lines
buffer.insert([7, 0], '\n\n')
buffer.insert([5, 0], '\n\n')
expect(tokenizedBuffer.lineForScreenRow(5).indentLevel).toBe 3
expect(tokenizedBuffer.lineForScreenRow(6).indentLevel).toBe 3
expect(tokenizedBuffer.lineForScreenRow(9).indentLevel).toBe 3
expect(tokenizedBuffer.lineForScreenRow(10).indentLevel).toBe 3
expect(tokenizedBuffer.lineForScreenRow(11).indentLevel).toBe 2
tokenizedBuffer.on "changed", changeHandler = jasmine.createSpy('changeHandler')
buffer.setTextInRange([[7, 0], [8, 65]], ' one\n two\n three\n four')
delete changeHandler.argsForCall[0][0].bufferChange
expect(changeHandler).toHaveBeenCalledWith(start: 5, end: 10, delta: 2)
expect(tokenizedBuffer.lineForScreenRow(5).indentLevel).toBe 4
expect(tokenizedBuffer.lineForScreenRow(6).indentLevel).toBe 4
expect(tokenizedBuffer.lineForScreenRow(11).indentLevel).toBe 4
expect(tokenizedBuffer.lineForScreenRow(12).indentLevel).toBe 4
expect(tokenizedBuffer.lineForScreenRow(13).indentLevel).toBe 2
it "updates the indentLevel of empty lines surrounding a change that removes lines", ->
# create some new lines
buffer.insert([7, 0], '\n\n')
buffer.insert([5, 0], '\n\n')
tokenizedBuffer.on "changed", changeHandler = jasmine.createSpy('changeHandler')
buffer.setTextInRange([[7, 0], [8, 65]], ' ok')
delete changeHandler.argsForCall[0][0].bufferChange
expect(changeHandler).toHaveBeenCalledWith(start: 5, end: 10, delta: -1)
expect(tokenizedBuffer.lineForScreenRow(5).indentLevel).toBe 2
expect(tokenizedBuffer.lineForScreenRow(6).indentLevel).toBe 2
expect(tokenizedBuffer.lineForScreenRow(7).indentLevel).toBe 2 # new text
expect(tokenizedBuffer.lineForScreenRow(8).indentLevel).toBe 2
expect(tokenizedBuffer.lineForScreenRow(9).indentLevel).toBe 2
expect(tokenizedBuffer.lineForScreenRow(10).indentLevel).toBe 2 # }
-14
Ver Arquivo
@@ -4,20 +4,6 @@ describe "TokenizedLine", ->
beforeEach ->
waitsForPromise -> atom.packages.activatePackage('language-coffee-script')
describe "::isOnlyWhitespace()", ->
beforeEach ->
waitsForPromise ->
atom.project.open('coffee.coffee').then (o) -> editor = o
it "returns true when the line is only whitespace", ->
expect(editor.lineForScreenRow(3).isOnlyWhitespace()).toBe true
expect(editor.lineForScreenRow(7).isOnlyWhitespace()).toBe true
expect(editor.lineForScreenRow(23).isOnlyWhitespace()).toBe true
it "returns false when the line is not only whitespace", ->
expect(editor.lineForScreenRow(0).isOnlyWhitespace()).toBe false
expect(editor.lineForScreenRow(2).isOnlyWhitespace()).toBe false
describe "::getScopeTree()", ->
it "returns a tree whose inner nodes are scopes and whose leaf nodes are tokens in those scopes", ->
[tokens, tokenIndex] = []
-25
Ver Arquivo
@@ -309,28 +309,3 @@ describe "Workspace", ->
expect(handler.callCount).toBe 1
editorCopy = editor.copy()
expect(handler.callCount).toBe 2
it "stores the active grammars used by all the open editors", ->
waitsForPromise ->
atom.packages.activatePackage('language-javascript')
waitsForPromise ->
atom.packages.activatePackage('language-coffee-script')
waitsForPromise ->
atom.workspace.open('sample.coffee')
runs ->
atom.workspace.getActiveEditor().setText('i = /test/;')
state = atom.workspace.serialize()
expect(state.packagesWithActiveGrammars).toEqual ['language-coffee-script', 'language-javascript']
jsPackage = atom.packages.getLoadedPackage('language-javascript')
coffeePackage = atom.packages.getLoadedPackage('language-coffee-script')
spyOn(jsPackage, 'loadGrammarsSync')
spyOn(coffeePackage, 'loadGrammarsSync')
workspace2 = Workspace.deserialize(state)
expect(jsPackage.loadGrammarsSync.callCount).toBe 1
expect(coffeePackage.loadGrammarsSync.callCount).toBe 1
+7 -8
Ver Arquivo
@@ -135,6 +135,13 @@ class Atom extends Model
@executeJavaScriptInDevTools('InspectorFrontendAPI.showConsole()')
@emit 'uncaught-error', arguments...
nativeConsoleError = console.error
console.error = =>
@openDevTools()
@executeJavaScriptInDevTools('InspectorFrontendAPI.showConsole()')
nativeConsoleError.call console, arguments...
@unsubscribe()
@setBodyPlatformClass()
@@ -258,20 +265,13 @@ class Atom extends Model
deserializeProject: ->
Project = require './project'
startTime = Date.now()
@project ?= @deserializers.deserialize(@state.project) ? new Project(path: @getLoadSettings().initialPath)
@deserializeTimings.project = Date.now() - startTime
deserializeWorkspaceView: ->
Workspace = require './workspace'
WorkspaceView = require './workspace-view'
startTime = Date.now()
@workspace = Workspace.deserialize(@state.workspace) ? new Workspace
@workspaceView = new WorkspaceView(@workspace)
@deserializeTimings.workspace = Date.now() - startTime
@keymaps.defaultTarget = @workspaceView[0]
$(@workspaceViewParentSelector).append(@workspaceView)
@@ -280,7 +280,6 @@ class Atom extends Model
delete @state.packageStates
deserializeEditorWindow: ->
@deserializeTimings = {}
@deserializePackageStates()
@deserializeProject()
@deserializeWorkspaceView()
+1 -2
Ver Arquivo
@@ -60,8 +60,7 @@ class ContextMenuManager
# editor is in dev mode.
addBySelector: (selector, definition, {devMode}={}) ->
definitions = if devMode then @devModeDefinitions else @definitions
unless _.findWhere(definitions[selector], definition)
(definitions[selector] ?= []).push(definition)
(definitions[selector] ?= []).push(definition)
# Returns definitions which match the element and devMode.
definitionsForElement: (element, {devMode}={}) ->
+5 -18
Ver Arquivo
@@ -1,29 +1,16 @@
React = require 'react-atom-fork'
{div} = require 'reactionary-atom-fork'
{isEqualForProperties} = require 'underscore-plus'
module.exports =
CursorComponent = React.createClass
displayName: 'CursorComponent'
render: ->
{pixelRect, defaultCharWidth} = @props
{height, width} = pixelRect
width = defaultCharWidth if width is 0
WebkitTransform = @getTransform()
div className: 'cursor', style: {height, width, WebkitTransform}
getTransform: ->
{pixelRect, scrollTop, scrollLeft, useHardwareAcceleration} = @props
{top, left} = pixelRect
{editor, screenRange, scrollTop, scrollLeft, defaultCharWidth} = @props
{top, left, height, width} = editor.pixelRectForScreenRange(screenRange)
top -= scrollTop
left -= scrollLeft
width = defaultCharWidth if width is 0
WebkitTransform = "translate3d(#{left}px, #{top}px, 0px)"
if useHardwareAcceleration
"translate3d(#{left}px, #{top}px, 0px)"
else
"translate(#{left}px, #{top}px)"
shouldComponentUpdate: (newProps) ->
not isEqualForProperties(newProps, @props, 'pixelRect', 'scrollTop', 'scrollLeft', 'defaultCharWidth')
div className: 'cursor', style: {height, width, WebkitTransform}
+5 -5
Ver Arquivo
@@ -28,7 +28,9 @@ class Cursor extends Model
# Supports old editor view
@needsAutoscroll ?= @isLastCursor() and !textChanged
@autoscroll() if @editor.manageScrollPosition and @isLastCursor() and textChanged
# Supports react editor view
@autoscroll() if @needsAutoscroll and @editor.manageScrollPosition
@goalColumn = null
@@ -53,10 +55,8 @@ class Cursor extends Model
changePosition: (options, fn) ->
@clearSelection()
@needsAutoscroll = options.autoscroll ? @isLastCursor()
fn()
if @needsAutoscroll
@emit 'autoscrolled' # Support legacy editor
@autoscroll() if @needsAutoscroll and @editor.manageScrollPosition # Support react editor view
unless fn()
@emit 'autoscrolled' if @needsAutoscroll
getPixelRect: ->
@editor.pixelRectForScreenRange(@getScreenRange())
+8 -9
Ver Arquivo
@@ -12,7 +12,7 @@ CursorsComponent = React.createClass
cursorBlinkIntervalHandle: null
render: ->
{cursorPixelRects, scrollTop, scrollLeft, defaultCharWidth, useHardwareAcceleration} = @props
{editor, cursorScreenRanges, scrollTop, scrollLeft, defaultCharWidth} = @props
{blinkOff} = @state
className = 'cursors'
@@ -20,8 +20,8 @@ CursorsComponent = React.createClass
div {className},
if @isMounted()
for key, pixelRect of cursorPixelRects
CursorComponent({key, pixelRect, scrollTop, scrollLeft, defaultCharWidth, useHardwareAcceleration})
for key, screenRange of cursorScreenRanges
CursorComponent({key, editor, screenRange, scrollTop, scrollLeft, defaultCharWidth})
getInitialState: ->
blinkOff: false
@@ -34,14 +34,13 @@ CursorsComponent = React.createClass
shouldComponentUpdate: (newProps, newState) ->
not newState.blinkOff is @state.blinkOff or
not isEqualForProperties(newProps, @props, 'cursorPixelRects', 'scrollTop', 'scrollLeft', 'defaultCharWidth', 'useHardwareAcceleration')
not isEqualForProperties(newProps, @props,
'cursorScreenRanges', 'scrollTop', 'scrollLeft', 'lineHeightInPixels',
'defaultCharWidth', 'scopedCharacterWidthsChangeCount'
)
componentWillUpdate: (newProps) ->
cursorsMoved = @props.cursorPixelRects? and
isEqualForProperties(newProps, @props, 'defaultCharWidth', 'scopedCharacterWidthsChangeCount') and
not isEqual(newProps.cursorPixelRects, @props.cursorPixelRects)
@pauseCursorBlinking() if cursorsMoved
@pauseCursorBlinking() if @props.cursorScreenRanges and not isEqual(newProps.cursorScreenRanges, @props.cursorScreenRanges)
startBlinkingCursors: ->
@toggleCursorBlinkHandle = setInterval(@toggleCursorBlink, @props.cursorBlinkPeriod / 2) if @isMounted()
-57
Ver Arquivo
@@ -1,57 +0,0 @@
_ = require 'underscore-plus'
{Subscriber, Emitter} = require 'emissary'
idCounter = 0
nextId = -> idCounter++
module.exports =
class Decoration
Emitter.includeInto(this)
@isType: (decorationParams, type) ->
if _.isArray(decorationParams.type)
type in decorationParams.type
else
type is decorationParams.type
constructor: (@marker, @displayBuffer, @params) ->
@id = nextId()
@params.id = @id
@flashQueue = null
@isDestroyed = false
destroy: ->
return if @isDestroyed
@isDestroyed = true
@displayBuffer.removeDecoration(this)
@emit 'destoryed'
update: (newParams) ->
return if @isDestroyed
oldParams = @params
@params = newParams
@params.id = @id
@displayBuffer.decorationUpdated(this)
@emit 'updated', {oldParams, newParams}
getParams: ->
@params
isType: (type) ->
Decoration.isType(@params, type)
matchesPattern: (decorationPattern) ->
return false unless decorationPattern?
for key, value of decorationPattern
return false if @params[key] != value
true
flash: (klass, duration=500) ->
flashObject = {class: klass, duration}
@flashQueue ?= []
@flashQueue.push(flashObject)
@emit 'flash'
consumeNextFlash: ->
return @flashQueue.shift() if @flashQueue?.length > 0
null
+53 -95
Ver Arquivo
@@ -8,7 +8,6 @@ TokenizedBuffer = require './tokenized-buffer'
RowMap = require './row-map'
Fold = require './fold'
Token = require './token'
Decoration = require './decoration'
DisplayBufferMarker = require './display-buffer-marker'
class BufferToScreenConversionError extends Error
@@ -30,7 +29,6 @@ class DisplayBuffer extends Model
width: null
scrollTop: 0
scrollLeft: 0
scrollWidth: 0
verticalScrollMargin: 2
horizontalScrollMargin: 6
@@ -46,10 +44,8 @@ class DisplayBuffer extends Model
@charWidthsByScope = {}
@markers = {}
@foldsByMarkerId = {}
@decorationsById = {}
@decorationsByMarkerId = {}
@decorationMarkerChangedSubscriptions = {}
@decorationMarkerDestroyedSubscriptions = {}
@decorationMarkerSubscriptions = {}
@updateAllScreenLines()
@createFoldForMarker(marker) for marker in @buffer.findMarkers(@getFoldMarkerAttributes())
@subscribe @tokenizedBuffer, 'grammar-changed', (grammar) => @emit 'grammar-changed', grammar
@@ -184,12 +180,9 @@ class DisplayBuffer extends Model
getScrollTop: -> @scrollTop
setScrollTop: (scrollTop) ->
if @manageScrollPosition
@scrollTop = Math.round(Math.max(0, Math.min(@getMaxScrollTop(), scrollTop)))
@scrollTop = Math.max(0, Math.min(@getScrollHeight() - @getClientHeight(), scrollTop))
else
@scrollTop = Math.round(scrollTop)
getMaxScrollTop: ->
@getScrollHeight() - @getClientHeight()
@scrollTop = scrollTop
getScrollBottom: -> @scrollTop + @height
setScrollBottom: (scrollBottom) ->
@@ -199,13 +192,10 @@ class DisplayBuffer extends Model
getScrollLeft: -> @scrollLeft
setScrollLeft: (scrollLeft) ->
if @manageScrollPosition
@scrollLeft = Math.round(Math.max(0, Math.min(@getScrollWidth() - @getClientWidth(), scrollLeft)))
@scrollLeft = Math.max(0, Math.min(@getScrollWidth() - @getClientWidth(), scrollLeft))
@scrollLeft
else
@scrollLeft = Math.round(scrollLeft)
getMaxScrollLeft: ->
@getScrollWidth() - @getClientWidth()
@scrollLeft = scrollLeft
getScrollRight: -> @scrollLeft + @width
setScrollRight: (scrollRight) ->
@@ -216,11 +206,7 @@ class DisplayBuffer extends Model
setLineHeightInPixels: (@lineHeightInPixels) -> @lineHeightInPixels
getDefaultCharWidth: -> @defaultCharWidth
setDefaultCharWidth: (defaultCharWidth) ->
if defaultCharWidth isnt @defaultCharWidth
@defaultCharWidth = defaultCharWidth
@computeScrollWidth()
defaultCharWidth
setDefaultCharWidth: (@defaultCharWidth) -> @defaultCharWidth
getCursorWidth: -> 1
@@ -235,21 +221,13 @@ class DisplayBuffer extends Model
scope.charWidths ?= {}
scope.charWidths
batchCharacterMeasurement: (fn) ->
oldChangeCount = @scopedCharacterWidthsChangeCount
@batchingCharacterMeasurement = true
fn()
@batchingCharacterMeasurement = false
@characterWidthsChanged() if oldChangeCount isnt @scopedCharacterWidthsChangeCount
setScopedCharWidth: (scopeNames, char, width) ->
@getScopedCharWidths(scopeNames)[char] = width
@scopedCharacterWidthsChangeCount++
@characterWidthsChanged() unless @batchingCharacterMeasurement
@emit 'character-widths-changed', @scopedCharacterWidthsChangeCount++
characterWidthsChanged: ->
@computeScrollWidth()
@emit 'character-widths-changed', @scopedCharacterWidthsChangeCount
setScopedCharWidths: (scopeNames, charWidths) ->
_.extend(@getScopedCharWidths(scopeNames), charWidths)
@emit 'character-widths-changed', @scopedCharacterWidthsChangeCount++
clearScopedCharWidths: ->
@charWidthsByScope = {}
@@ -260,7 +238,7 @@ class DisplayBuffer extends Model
@getLineCount() * @getLineHeightInPixels()
getScrollWidth: ->
@scrollWidth
(@getMaxLineLength() * @getDefaultCharWidth()) + @getCursorWidth()
getVisibleRowRange: ->
return [0, 0] unless @getLineHeightInPixels() > 0
@@ -598,12 +576,6 @@ class DisplayBuffer extends Model
getMaxLineLength: ->
@maxLineLength
# Gets the row number of the longest screen line.
#
# Return a {}
getLongestScreenRow: ->
@longestScreenRow
# Given a buffer position, this converts it into a screen position.
#
# bufferPosition - An object that represents a buffer position. It can be either
@@ -757,48 +729,53 @@ class DisplayBuffer extends Model
rangeForAllLines: ->
new Range([0, 0], @clipScreenPosition([Infinity, Infinity]))
decorationForId: (id) ->
@decorationsById[id]
decorationsForScreenRowRange: (startScreenRow, endScreenRow) ->
decorationsByMarkerId = {}
for marker in @findMarkers(intersectsScreenRowRange: [startScreenRow, endScreenRow])
if decorations = @decorationsByMarkerId[marker.id]
decorationsByMarkerId[marker.id] = decorations
decorationsByMarkerId
decorateMarker: (marker, decorationParams) ->
decorationMatchesType: (decoration, type) ->
if _.isArray(decoration.type)
type in decoration.type
else
type is decoration.type
decorationMatchesPattern: (decoration, decorationPattern) ->
return false unless decoration? and decorationPattern?
for key, value of decorationPattern
return false if decoration[key] != value
true
addDecorationForMarker: (marker, decoration) ->
unless marker?
console.warn 'A null marker cannot be decorated'
return
marker = @getMarker(marker.id)
@decorationMarkerSubscriptions[marker.id] ?= @subscribe marker, 'destroyed', => @removeAllDecorationsForMarker(marker)
@decorationMarkerDestroyedSubscriptions[marker.id] ?= @subscribe marker, 'destroyed', =>
@removeAllDecorationsForMarker(marker)
@decorationMarkerChangedSubscriptions[marker.id] ?= @subscribe marker, 'changed', (event) =>
decorations = @decorationsByMarkerId[marker.id]
# Why check existence? Markers may get destroyed or decorations removed
# in the change handler. Bookmarks does this.
if decorations?
for decoration in decorations
@emit 'decoration-changed', marker, decoration, event
decoration = new Decoration(marker, this, decorationParams)
@decorationsByMarkerId[marker.id] ?= []
@decorationsByMarkerId[marker.id].push(decoration)
@decorationsById[decoration.id] = decoration
@emit 'decoration-added', marker, decoration
decoration
removeDecoration: (decoration) ->
{marker} = decoration
return unless decorations = @decorationsByMarkerId[marker.id]
index = decorations.indexOf(decoration)
removeDecorationForMarker: (marker, decorationPattern) ->
unless marker?
console.warn 'A decoration cannot be removed from a null marker'
return
if index > -1
decorations.splice(index, 1)
delete @decorationsById[decoration.id]
@emit 'decoration-removed', marker, decoration
@removedAllMarkerDecorations(marker) if decorations.length is 0
return unless @decorationMarkerSubscriptions[marker.id]?
decorations = @decorationsByMarkerId[marker.id]
for i in [decorations.length - 1..0]
decoration = decorations[i]
if @decorationMatchesPattern(decoration, decorationPattern)
decorations.splice(i, 1)
@emit 'decoration-removed', marker, decoration
@removedAllMarkerDecorations(marker) if decorations.length is 0
removeAllDecorationsForMarker: (marker) ->
decorations = @decorationsByMarkerId[marker.id].slice()
@@ -807,15 +784,9 @@ class DisplayBuffer extends Model
@removedAllMarkerDecorations(marker)
removedAllMarkerDecorations: (marker) ->
@decorationMarkerChangedSubscriptions[marker.id].off()
@decorationMarkerDestroyedSubscriptions[marker.id].off()
@decorationMarkerSubscriptions[marker.id].off()
delete @decorationsByMarkerId[marker.id]
delete @decorationMarkerChangedSubscriptions[marker.id]
delete @decorationMarkerDestroyedSubscriptions[marker.id]
decorationUpdated: (decoration) ->
@emit 'decoration-updated', decoration
delete @decorationMarkerSubscriptions[marker.id]
# Retrieves a {DisplayBufferMarker} based on its id.
#
@@ -983,26 +954,24 @@ class DisplayBuffer extends Model
handleTokenizedBufferChange: (tokenizedBufferChange) =>
{start, end, delta, bufferChange} = tokenizedBufferChange
@updateScreenLines(start, end + 1, delta, delayChangeEvent: bufferChange?)
@setScrollTop(Math.min(@getScrollTop(), @getMaxScrollTop())) if @manageScrollPosition and delta < 0
updateScreenLines: (startBufferRow, endBufferRow, bufferDelta=0, options={}) ->
startBufferRow = @rowMap.bufferRowRangeForBufferRow(startBufferRow)[0]
endBufferRow = @rowMap.bufferRowRangeForBufferRow(endBufferRow - 1)[1]
startScreenRow = @rowMap.screenRowRangeForBufferRow(startBufferRow)[0]
endScreenRow = @rowMap.screenRowRangeForBufferRow(endBufferRow - 1)[1]
{screenLines, regions} = @buildScreenLines(startBufferRow, endBufferRow + bufferDelta)
screenDelta = screenLines.length - (endScreenRow - startScreenRow)
{screenLines, regions} = @buildScreenLines(startBufferRow, endBufferRow + bufferDelta)
@screenLines[startScreenRow...endScreenRow] = screenLines
@rowMap.spliceRegions(startBufferRow, endBufferRow - startBufferRow, regions)
@findMaxLineLength(startScreenRow, endScreenRow, screenLines, screenDelta)
@findMaxLineLength(startScreenRow, endScreenRow, screenLines)
return if options.suppressChangeEvent
changeEvent =
start: startScreenRow
end: endScreenRow - 1
screenDelta: screenDelta
screenDelta: screenLines.length - (endScreenRow - startScreenRow)
bufferDelta: bufferDelta
if options.delayChangeEvent
@@ -1057,33 +1026,22 @@ class DisplayBuffer extends Model
{screenLines, regions}
findMaxLineLength: (startScreenRow, endScreenRow, newScreenLines, screenDelta) ->
oldMaxLineLength = @maxLineLength
findMaxLineLength: (startScreenRow, endScreenRow, newScreenLines) ->
if startScreenRow <= @longestScreenRow < endScreenRow
@longestScreenRow = 0
@maxLineLength = 0
maxLengthCandidatesStartRow = 0
maxLengthCandidates = @screenLines
else
@longestScreenRow += screenDelta if endScreenRow < @longestScreenRow
maxLengthCandidatesStartRow = startScreenRow
maxLengthCandidates = newScreenLines
for screenLine, i in maxLengthCandidates
screenRow = maxLengthCandidatesStartRow + i
for screenLine, screenRow in maxLengthCandidates
length = screenLine.text.length
if length > @maxLineLength
@longestScreenRow = screenRow
@longestScreenRow = maxLengthCandidatesStartRow + screenRow
@maxLineLength = length
@computeScrollWidth() if oldMaxLineLength isnt @maxLineLength
computeScrollWidth: ->
@scrollWidth = @pixelPositionForScreenPosition([@longestScreenRow, @maxLineLength]).left
@scrollWidth += 1 unless @getSoftWrap()
@setScrollLeft(Math.min(@getScrollLeft(), @getMaxScrollLeft()))
handleBufferMarkersUpdated: =>
if event = @pendingChangeEvent
@pendingChangeEvent = null
@@ -1094,7 +1052,7 @@ class DisplayBuffer extends Model
@emit 'marker-created', @getMarker(marker.id)
createFoldForMarker: (marker) ->
@decorateMarker(marker, type: 'gutter', class: 'folded')
@addDecorationForMarker(marker, type: 'gutter', class: 'folded')
new Fold(this, marker)
foldForMarker: (marker) ->
+47 -130
Ver Arquivo
@@ -12,7 +12,7 @@ ScrollbarComponent = require './scrollbar-component'
ScrollbarCornerComponent = require './scrollbar-corner-component'
SubscriberMixin = require './subscriber-mixin'
DummyHighlightDecoration = {id: 'dummy', startPixelPosition: {top: 0, left: 0}, endPixelPosition: {top: 0, left: 0}, decorations: [{class: 'dummy'}]}
DummyHighlightDecoration = {id: 'dummy', screenRange: new Range(new Point(0, 0), new Point(0, 0)), decorations: [{class: 'dummy'}]}
module.exports =
EditorComponent = React.createClass
@@ -26,9 +26,6 @@ EditorComponent = React.createClass
pendingScrollLeft: null
selectOnMouseMove: false
updateRequested: false
updatesPaused: false
updateRequestedWhilePaused: false
characterWidthRemeasurementRequested: false
cursorsMoved: false
selectionChanged: false
selectionAdded: false
@@ -47,10 +44,9 @@ EditorComponent = React.createClass
inputEnabled: true
scrollViewMeasurementInterval: 100
scopedCharacterWidthsChangeCount: null
scrollViewMeasurementPaused: false
render: ->
{focused, fontSize, lineHeight, fontFamily, showIndentGuide, showInvisibles, showLineNumbers, visible} = @state
{focused, fontSize, lineHeight, fontFamily, showIndentGuide, showInvisibles, visible} = @state
{editor, cursorBlinkPeriod, cursorBlinkResumeDelay} = @props
maxLineNumberDigits = editor.getLineCount().toString().length
invisibles = if showInvisibles then @state.invisibles else {}
@@ -59,7 +55,7 @@ EditorComponent = React.createClass
if @isMounted()
renderedRowRange = @getRenderedRowRange()
[renderedStartRow, renderedEndRow] = renderedRowRange
cursorPixelRects = @getCursorPixelRects(renderedRowRange)
cursorScreenRanges = @getCursorScreenRanges(renderedRowRange)
decorations = editor.decorationsForScreenRowRange(renderedStartRow, renderedEndRow)
highlightDecorations = @getHighlightDecorations(decorations)
@@ -72,13 +68,12 @@ EditorComponent = React.createClass
lineHeightInPixels = editor.getLineHeightInPixels()
defaultCharWidth = editor.getDefaultCharWidth()
scrollViewHeight = editor.getHeight()
lineWidth = Math.max(scrollWidth, editor.getWidth())
horizontalScrollbarHeight = editor.getHorizontalScrollbarHeight()
verticalScrollbarWidth = editor.getVerticalScrollbarWidth()
verticallyScrollable = editor.verticallyScrollable()
horizontallyScrollable = editor.horizontallyScrollable()
hiddenInputStyle = @getHiddenInputPosition()
hiddenInputStyle.WebkitTransform = 'translateZ(0)' if @useHardwareAcceleration
hiddenInputStyle.WebkitTransform = 'translateZ(0)'
if @mouseWheelScreenRow? and not (renderedStartRow <= @mouseWheelScreenRow < renderedEndRow)
mouseWheelScreenRow = @mouseWheelScreenRow
@@ -87,12 +82,11 @@ EditorComponent = React.createClass
className += ' has-selection' if hasSelection
div className: className, style: {fontSize, lineHeight, fontFamily}, tabIndex: -1,
if showLineNumbers
GutterComponent {
ref: 'gutter', onMouseDown: @onGutterMouseDown, onWidthChanged: @onGutterWidthChanged,
lineDecorations, defaultCharWidth, editor, renderedRowRange, maxLineNumberDigits, scrollViewHeight,
scrollTop, scrollHeight, lineHeightInPixels, @pendingChanges, mouseWheelScreenRow, @useHardwareAcceleration
}
GutterComponent {
ref: 'gutter', onMouseDown: @onGutterMouseDown, onWidthChanged: @onGutterWidthChanged,
lineDecorations, defaultCharWidth, editor, renderedRowRange, maxLineNumberDigits, scrollViewHeight,
scrollTop, scrollHeight, lineHeightInPixels, @pendingChanges, mouseWheelScreenRow
}
div ref: 'scrollView', className: 'scroll-view', onMouseDown: @onMouseDown,
InputComponent
@@ -103,15 +97,15 @@ EditorComponent = React.createClass
onBlur: @onInputBlurred
CursorsComponent {
scrollTop, scrollLeft, cursorPixelRects, cursorBlinkPeriod, cursorBlinkResumeDelay,
lineHeightInPixels, defaultCharWidth, @scopedCharacterWidthsChangeCount, @useHardwareAcceleration
editor, scrollTop, scrollLeft, cursorScreenRanges, cursorBlinkPeriod, cursorBlinkResumeDelay,
lineHeightInPixels, defaultCharWidth, @scopedCharacterWidthsChangeCount
}
LinesComponent {
ref: 'lines',
editor, lineHeightInPixels, defaultCharWidth, lineDecorations, highlightDecorations,
showIndentGuide, renderedRowRange, @pendingChanges, scrollTop, scrollLeft,
@scrollingVertically, scrollHeight, scrollWidth, mouseWheelScreenRow, invisibles,
visible, scrollViewHeight, @scopedCharacterWidthsChangeCount, lineWidth, @useHardwareAcceleration
visible, scrollViewHeight, @scopedCharacterWidthsChangeCount
}
ScrollbarComponent
@@ -167,7 +161,7 @@ EditorComponent = React.createClass
componentDidMount: ->
{editor} = @props
@scrollViewMeasurementIntervalId = setInterval(@measureScrollView, @scrollViewMeasurementInterval)
@scrollViewMeasurementIntervalId = setInterval(@requestScrollViewMeasurement, @scrollViewMeasurementInterval)
@observeEditor()
@listenForDOMEvents()
@@ -187,6 +181,8 @@ EditorComponent = React.createClass
clearInterval(@scrollViewMeasurementIntervalId)
@scrollViewMeasurementIntervalId = null
componentWillUpdate: ->
componentDidUpdate: (prevProps, prevState) ->
cursorsMoved = @cursorsMoved
selectionChanged = @selectionChanged
@@ -206,28 +202,14 @@ EditorComponent = React.createClass
@remeasureCharacterWidthsIfNeeded(prevState)
requestUpdate: ->
if @updatesPaused
@updateRequestedWhilePaused = true
return
if @performSyncUpdates ? EditorComponent.performSyncUpdates
@forceUpdate()
else unless @updateRequested
@updateRequested = true
setImmediate =>
process.nextTick =>
@updateRequested = false
@forceUpdate() if @isMounted()
requestAnimationFrame: (fn) ->
@updatesPaused = true
@pauseScrollViewMeasurement()
requestAnimationFrame =>
fn()
@updatesPaused = false
if @updateRequestedWhilePaused and @isMounted()
@updateRequestedWhilePaused = false
@forceUpdate()
getRenderedRowRange: ->
{editor, lineOverdrawMargin} = @props
[visibleStartRow, visibleEndRow] = editor.getVisibleRowRange()
@@ -260,43 +242,22 @@ EditorComponent = React.createClass
cursorScreenRanges[cursor.id] = screenRange
cursorScreenRanges
getCursorPixelRects: (renderedRowRange) ->
{editor} = @props
[renderedStartRow, renderedEndRow] = renderedRowRange
cursorPixelRects = {}
for selection in editor.getSelections() when selection.isEmpty()
{cursor} = selection
screenRange = cursor.getScreenRange()
if renderedStartRow <= screenRange.start.row < renderedEndRow
cursorPixelRects[cursor.id] = editor.pixelRectForScreenRange(screenRange)
cursorPixelRects
getLineDecorations: (decorationsByMarkerId) ->
{editor} = @props
decorationsByScreenRow = {}
for markerId, decorations of decorationsByMarkerId
marker = editor.getMarker(markerId)
screenRange = null
headScreenRow = null
if marker.isValid()
for decoration in decorations
if decoration.isType('gutter') or decoration.isType('line')
decorationParams = decoration.getParams()
if editor.decorationMatchesType(decoration, 'gutter') or editor.decorationMatchesType(decoration, 'line')
screenRange ?= marker.getScreenRange()
headScreenRow ?= marker.getHeadScreenPosition().row
startRow = screenRange.start.row
endRow = screenRange.end.row
endRow-- if not screenRange.isEmpty() and screenRange.end.column == 0
for screenRow in [startRow..endRow]
continue if decorationParams.onlyHead and screenRow isnt headScreenRow
if screenRange.isEmpty()
continue if decorationParams.onlyNonEmpty
else
continue if decorationParams.onlyEmpty
decorationsByScreenRow[screenRow] ?= []
decorationsByScreenRow[screenRow].push decorationParams
decorationsByScreenRow[screenRow].push decoration
decorationsByScreenRow
@@ -305,17 +266,11 @@ EditorComponent = React.createClass
filteredDecorations = {}
for markerId, decorations of decorationsByMarkerId
marker = editor.getMarker(markerId)
screenRange = marker.getScreenRange()
if marker.isValid() and not screenRange.isEmpty()
if marker.isValid() and not marker.getScreenRange().isEmpty()
for decoration in decorations
if decoration.isType('highlight')
decorationParams = decoration.getParams()
filteredDecorations[markerId] ?=
id: markerId
startPixelPosition: editor.pixelPositionForScreenPosition(screenRange.start)
endPixelPosition: editor.pixelPositionForScreenPosition(screenRange.end)
decorations: []
filteredDecorations[markerId].decorations.push decorationParams
if editor.decorationMatchesType(decoration, 'highlight')
filteredDecorations[markerId] ?= {id: markerId, screenRange: marker.getScreenRange(), decorations: []}
filteredDecorations[markerId].decorations.push decoration
# At least in Chromium 31, removing the last highlight causes a rendering
# artifact where chunks of the lines disappear, so we always leave this
@@ -332,8 +287,6 @@ EditorComponent = React.createClass
@subscribe editor, 'selection-added', @onSelectionAdded
@subscribe editor, 'decoration-added', @onDecorationChanged
@subscribe editor, 'decoration-removed', @onDecorationChanged
@subscribe editor, 'decoration-changed', @onDecorationChanged
@subscribe editor, 'decoration-updated', @onDecorationChanged
@subscribe editor, 'character-widths-changed', @onCharacterWidthsChanged
@subscribe editor.$scrollTop.changes, @onScrollTopChanged
@subscribe editor.$scrollLeft.changes, @requestUpdate
@@ -372,13 +325,12 @@ EditorComponent = React.createClass
# 5. textInput fired; event.data == the completion string
selectedText = null
node.addEventListener 'compositionstart', ->
node.addEventListener 'compositionstart', =>
selectedText = editor.getSelectedText()
node.addEventListener 'compositionupdate', (event) ->
node.addEventListener 'compositionupdate', (event) =>
editor.insertText(event.data, select: true, undo: 'skip')
node.addEventListener 'compositionend', (event) ->
node.addEventListener 'compositionend', =>
editor.insertText(selectedText, select: true, undo: 'skip')
event.target.value = ''
listenForCommands: ->
{parentView, editor, mini} = @props
@@ -498,9 +450,7 @@ EditorComponent = React.createClass
@subscribe atom.config.observe 'editor.showIndentGuide', @setShowIndentGuide
@subscribe atom.config.observe 'editor.invisibles', @setInvisibles
@subscribe atom.config.observe 'editor.showInvisibles', @setShowInvisibles
@subscribe atom.config.observe 'editor.showLineNumbers', @setShowLineNumbers
@subscribe atom.config.observe 'editor.scrollSensitivity', @setScrollSensitivity
@subscribe atom.config.observe 'editor.useHardwareAcceleration', @setUseHardwareAcceleration
onFocus: ->
@refs.input.focus()
@@ -534,25 +484,24 @@ EditorComponent = React.createClass
onVerticalScroll: (scrollTop) ->
{editor} = @props
return if @updateRequested or scrollTop is editor.getScrollTop()
return if scrollTop is editor.getScrollTop()
animationFramePending = @pendingScrollTop?
@pendingScrollTop = scrollTop
unless animationFramePending
@requestAnimationFrame =>
pendingScrollTop = @pendingScrollTop
requestAnimationFrame =>
@props.editor.setScrollTop(@pendingScrollTop)
@pendingScrollTop = null
@props.editor.setScrollTop(pendingScrollTop)
onHorizontalScroll: (scrollLeft) ->
{editor} = @props
return if @updateRequested or scrollLeft is editor.getScrollLeft()
return if scrollLeft is editor.getScrollLeft()
animationFramePending = @pendingScrollLeft?
@pendingScrollLeft = scrollLeft
unless animationFramePending
@requestAnimationFrame =>
requestAnimationFrame =>
@props.editor.setScrollLeft(@pendingScrollLeft)
@pendingScrollLeft = null
@@ -573,7 +522,7 @@ EditorComponent = React.createClass
@clearMouseWheelScreenRowAfterDelay()
unless animationFramePending
@requestAnimationFrame =>
requestAnimationFrame =>
{editor} = @props
editor.setScrollTop(editor.getScrollTop() + @pendingVerticalScrollDelta)
editor.setScrollLeft(editor.getScrollLeft() + @pendingHorizontalScrollDelta)
@@ -591,7 +540,7 @@ EditorComponent = React.createClass
return unless event.button is 0 # only handle the left mouse button
{editor} = @props
{detail, shiftKey, metaKey, ctrlKey} = event
{detail, shiftKey, metaKey} = event
screenPosition = @screenPositionForMouseEvent(event)
if event.target?.classList.contains('fold-marker')
@@ -599,18 +548,15 @@ EditorComponent = React.createClass
editor.unfoldBufferRow(bufferRow)
return
switch detail
when 1
if shiftKey
editor.selectToScreenPosition(screenPosition)
else if metaKey or (ctrlKey and process.platform isnt 'darwin')
editor.addCursorAtScreenPosition(screenPosition)
else
editor.setCursorScreenPosition(screenPosition)
when 2
editor.getLastSelection().selectWord()
when 3
editor.getLastSelection().selectLine()
if shiftKey
editor.selectToScreenPosition(screenPosition)
else if metaKey
editor.addCursorAtScreenPosition(screenPosition)
else
editor.setCursorScreenPosition(screenPosition)
switch detail
when 2 then editor.selectWord()
when 3 then editor.selectLine()
@handleDragUntilMouseUp event, (screenPosition) ->
editor.selectToScreenPosition(screenPosition)
@@ -655,7 +601,6 @@ EditorComponent = React.createClass
onStylesheetsChanged: (stylesheet) ->
@refreshScrollbars() if @containsScrollbarSelector(stylesheet)
@requestCharacterWidthRemeasurement()
onScreenLinesChanged: (change) ->
{editor} = @props
@@ -678,7 +623,7 @@ EditorComponent = React.createClass
onScrollTopChanged: ->
@scrollingVertically = true
@requestUpdate()
@onStoppedScrollingAfterDelay ?= debounce(@onStoppedScrolling, 200)
@onStoppedScrollingAfterDelay ?= debounce(@onStoppedScrolling, 100)
@onStoppedScrollingAfterDelay()
onStoppedScrolling: ->
@@ -705,7 +650,7 @@ EditorComponent = React.createClass
dragging = false
lastMousePosition = {}
animationLoop = =>
@requestAnimationFrame =>
requestAnimationFrame =>
if dragging
screenPosition = @screenPositionForMouseEvent(lastMousePosition)
dragHandler(screenPosition)
@@ -732,18 +677,8 @@ EditorComponent = React.createClass
window.addEventListener('mousemove', onMouseMove)
window.addEventListener('mouseup', onMouseUp)
pauseScrollViewMeasurement: ->
@scrollViewMeasurementPaused = true
@resumeScrollViewMeasurementAfterDelay ?= debounce(@resumeScrollViewMeasurement, 100)
@resumeScrollViewMeasurementAfterDelay()
resumeScrollViewMeasurement: ->
@scrollViewMeasurementPaused = false
resumeScrollViewMeasurementAfterDelay: null # created lazily
requestScrollViewMeasurement: ->
return if @scrollViewMeasurementRequested
return if @measurementPending
@scrollViewMeasurementRequested = true
requestAnimationFrame =>
@@ -755,7 +690,6 @@ EditorComponent = React.createClass
# and use the scrollHeight / scrollWidth as its height and width in
# calculations.
measureScrollView: ->
return if @scrollViewMeasurementPaused
return unless @isMounted()
{editor} = @props
@@ -770,8 +704,6 @@ EditorComponent = React.createClass
if position is 'absolute' or width
clientWidth = scrollViewNode.clientWidth
paddingLeft = parseInt(getComputedStyle(scrollViewNode).paddingLeft)
clientWidth -= paddingLeft
editor.setWidth(clientWidth) if clientWidth > 0
measureLineHeightAndCharWidthsIfNeeded: (prevState) ->
@@ -796,13 +728,6 @@ EditorComponent = React.createClass
else if @remeasureCharacterWidthsWhenShown and @state.visible and not prevState.visible
@remeasureCharacterWidths()
requestCharacterWidthRemeasurement: ->
unless @characterWidthRemeasurementRequested
@characterWidthRemeasurementRequested = true
setImmediate =>
@characterWidthRemeasurementRequested = false
@remeasureCharacterWidths()
remeasureCharacterWidths: ->
@remeasureCharacterWidthsWhenShown = false
@refs.lines.remeasureCharacterWidths()
@@ -910,18 +835,10 @@ EditorComponent = React.createClass
setShowInvisibles: (showInvisibles) ->
@setState({showInvisibles})
setShowLineNumbers: (showLineNumbers) ->
@setState({showLineNumbers})
setScrollSensitivity: (scrollSensitivity) ->
if scrollSensitivity = parseInt(scrollSensitivity)
@scrollSensitivity = Math.abs(scrollSensitivity) / 100
setUseHardwareAcceleration: (useHardwareAcceleration=true) ->
unless @useHardwareAcceleration is useHardwareAcceleration
@useHardwareAcceleration = useHardwareAcceleration
@requestUpdate()
screenPositionForMouseEvent: (event) ->
pixelPosition = @pixelPositionForMouseEvent(event)
@props.editor.screenPositionForPixelPosition(pixelPosition)
@@ -930,9 +847,9 @@ EditorComponent = React.createClass
{editor} = @props
{clientX, clientY} = event
linesClientRect = @refs.lines.getDOMNode().getBoundingClientRect()
top = clientY - linesClientRect.top
left = clientX - linesClientRect.left
scrollViewClientRect = @refs.scrollView.getDOMNode().getBoundingClientRect()
top = clientY - scrollViewClientRect.top + editor.getScrollTop()
left = clientX - scrollViewClientRect.left + editor.getScrollLeft()
{top, left}
getModel: ->
-1
Ver Arquivo
@@ -57,7 +57,6 @@ class EditorView extends View
softTabs: true
softWrapAtPreferredLineLength: false
scrollSensitivity: 40
useHardwareAcceleration: true
@nextEditorId: 1
+47 -34
Ver Arquivo
@@ -146,7 +146,6 @@ class Editor extends Model
selections: null
suppressSelectionMerging: false
updateBatchDepth: 0
selectionFlashDuration: 500
@delegatesMethods 'suggestedIndentForBufferRow', 'autoIndentBufferRow', 'autoIndentBufferRows',
'autoDecreaseIndentForBufferRow', 'toggleLineCommentForBufferRow', 'toggleLineCommentsForBufferRows',
@@ -218,8 +217,6 @@ class Editor extends Model
@subscribe @displayBuffer, 'soft-wrap-changed', (args...) => @emit 'soft-wrap-changed', args...
@subscribe @displayBuffer, "decoration-added", (args...) => @emit 'decoration-added', args...
@subscribe @displayBuffer, "decoration-removed", (args...) => @emit 'decoration-removed', args...
@subscribe @displayBuffer, "decoration-changed", (args...) => @emit 'decoration-changed', args...
@subscribe @displayBuffer, "decoration-updated", (args...) => @emit 'decoration-updated', args...
@subscribe @displayBuffer, "character-widths-changed", (changeCount) => @emit 'character-widths-changed', changeCount
getViewClass: ->
@@ -1087,34 +1084,53 @@ class Editor extends Model
@displayBuffer.decorationsForScreenRowRange(startScreenRow, endScreenRow)
# Public: Adds a decoration that tracks a {Marker}. When the marker moves,
# is invalidated, or is destroyed, the decoration will be updated to reflect
# the marker's state.
# is invalidated, or is destroyed, the decoration will be updated to reflect the marker's state.
#
# marker - A {Marker} you want this decoration to follow.
# decoration - An {Object} representing the decoration eg. `{type: 'gutter', class: 'linter-error'}`
# The decoration can contain the following keys:
# * type: There are a few supported decoration types:
# * `gutter`: Applies the decoration to the line numbers spanned by the
# marker.
# * `line`: Applies the decoration to the lines spanned by the marker.
# * `highlight`: Applies the decoration to a "highlight" behind the
# marked range. When the user selects text, the selection is
# visualized with a highlight decoration internally.
# * class: This CSS class will be applied to the decorated line number,
# line, or highlight.
# * onlyHead: If `true`, the decoration will only be applied to the head
# of the marker. Only applicable to the `line` and `gutter` types.
# * onlyEmpty: If `true`, the decoration will only be applied if the
# associated marker is empty. Only applicable to the `line` and
# `gutter` types.
# * onlyNonEmpty: If `true`, the decoration will only be applied if the
# associated marker is non-empty. Only applicable to the `line` and
# gutter types.
decorateMarker: (marker, decoration) ->
@displayBuffer.decorateMarker(marker, decoration)
# There are a few supported decoration types:
# * `gutter`: `{type: 'gutter', class: 'linter-error'}` Will add a class to the gutter rows associated with the marker.
# * `line`: `{type: 'line', class: 'linter-error'}` Will add a class to the editor lines associated with the marker.
# * `highlight`: `{type: 'highlight', class: 'linter-error'}` Will highlight the region of the buffer associated with the marker. Your specified class will be added to the highlight.
#
# marker - the {Marker} you want this decoration to follow
# decoration - the {Object} decoration eg. `{type: 'gutter', class: 'linter-error'}`
#
# Returns nothing
addDecorationForMarker: (marker, decoration) ->
@displayBuffer.addDecorationForMarker(marker, decoration)
decorationForId: (id) ->
@displayBuffer.decorationForId(id)
# Public: Removes all decorations associated with a {Marker} that match a
# `decorationPattern` and stop tracking the {Marker}.
#
# ```coffee
# marker = editor.markBufferRange([[4, 13], [5, 17]])
# editor.removeDecorationForMarker(marker, {type: 'gutter', class: 'linter-error'})
# ```
#
# All decorations matching a pattern will be removed. For example, you might
# have decorations with a namespace like this attached to a row:
#
# ```coffee
# [
# {type: 'gutter', namespace: 'myns', class: 'something'},
# {type: 'gutter', namespace: 'myns', class: 'something-else'}
# ]
# ```
#
# You can remove both with:
#
# ```coffee
# editor.removeDecorationForMarker(marker, {namespace: 'myns'})
# ```
#
# marker - the {Marker} to detach from
# decorationPattern - the {Object} decoration type to filter by eg. `{type: 'gutter', class: 'linter-error'}`
#
# Returns nothing
removeDecorationForMarker: (marker, decorationPattern) ->
@displayBuffer.removeDecorationForMarker(marker, decorationPattern)
decorationMatchesType: (decoration, type) ->
@displayBuffer.decorationMatchesType(decoration, type)
# Public: Get the {DisplayBufferMarker} for the given marker id.
getMarker: (id) ->
@@ -1221,9 +1237,7 @@ class Editor extends Model
addCursor: (marker) ->
cursor = new Cursor(editor: this, marker: marker)
@cursors.push(cursor)
@decorateMarker(marker, type: 'gutter', class: 'cursor-line')
@decorateMarker(marker, type: 'gutter', class: 'cursor-line-no-selection', onlyHead: true, onlyEmpty: true)
@decorateMarker(marker, type: 'line', class: 'cursor-line', onlyEmpty: true)
@addDecorationForMarker(marker, type: ['gutter', 'line'], class: 'cursor-line')
@emit 'cursor-added', cursor
cursor
@@ -1250,6 +1264,7 @@ class Editor extends Model
if selection.intersectsBufferRange(selectionBufferRange)
return selection
else
@addDecorationForMarker(marker, type: 'highlight', class: 'selection')
@emit 'selection-added', selection
selection
@@ -1959,8 +1974,6 @@ class Editor extends Model
getLineHeightInPixels: -> @displayBuffer.getLineHeightInPixels()
setLineHeightInPixels: (lineHeightInPixels) -> @displayBuffer.setLineHeightInPixels(lineHeightInPixels)
batchCharacterMeasurement: (fn) -> @displayBuffer.batchCharacterMeasurement(fn)
getScopedCharWidth: (scopeNames, char) -> @displayBuffer.getScopedCharWidth(scopeNames, char)
setScopedCharWidth: (scopeNames, char, width) -> @displayBuffer.setScopedCharWidth(scopeNames, char, width)
-5
Ver Arquivo
@@ -35,11 +35,6 @@ class Fold
# Returns a {Range}.
getBufferRange: ({includeNewline}={}) ->
range = @marker.getRange()
if range.end.row > range.start.row and nextFold = @displayBuffer.largestFoldStartingAtBufferRow(range.end.row)
nextRange = nextFold.getBufferRange()
range = new Range(range.start, nextRange.end)
if includeNewline
range = range.copy()
range.end.row++
+6 -15
Ver Arquivo
@@ -2,7 +2,6 @@ _ = require 'underscore-plus'
React = require 'react-atom-fork'
{div} = require 'reactionary-atom-fork'
{isEqual, isEqualForProperties, multiplyString, toArray} = require 'underscore-plus'
Decoration = require './decoration'
SubscriberMixin = require './subscriber-mixin'
WrapperDiv = document.createElement('div')
@@ -16,22 +15,14 @@ GutterComponent = React.createClass
measuredWidth: null
render: ->
{scrollHeight, scrollViewHeight, onMouseDown} = @props
{scrollHeight, scrollViewHeight, scrollTop, onMouseDown} = @props
div className: 'gutter', onClick: @onClick, onMouseDown: onMouseDown,
# The line-numbers div must have the 'editor-colors' class so it has an
# opaque background to avoid sub-pixel anti-aliasing problems on the GPU
div className: 'gutter line-numbers editor-colors', ref: 'lineNumbers', style:
height: Math.max(scrollHeight, scrollViewHeight)
WebkitTransform: @getTransform()
getTransform: ->
{scrollTop, useHardwareAcceleration} = @props
if useHardwareAcceleration
"translate3d(0px, #{-scrollTop}px, 0px)"
else
"translate(0px, #{-scrollTop}px)"
WebkitTransform: "translate3d(0px, #{-scrollTop}px, 0px)"
componentWillMount: ->
@lineNumberNodesById = {}
@@ -48,7 +39,7 @@ GutterComponent = React.createClass
shouldComponentUpdate: (newProps) ->
return true unless isEqualForProperties(newProps, @props,
'renderedRowRange', 'scrollTop', 'lineHeightInPixels', 'mouseWheelScreenRow', 'lineDecorations',
'scrollViewHeight', 'useHardwareAcceleration'
'scrollViewHeight'
)
{renderedRowRange, pendingChanges, lineDecorations} = newProps
@@ -155,7 +146,7 @@ GutterComponent = React.createClass
classes = ''
if lineDecorations? and decorations = lineDecorations[screenRow]
for decoration in decorations
if Decoration.isType(decoration, 'gutter')
if editor.decorationMatchesType(decoration, 'gutter')
classes += decoration.class + ' '
classes += "foldable " if bufferRow >= 0 and editor.isFoldableAtBufferRow(bufferRow)
@@ -187,11 +178,11 @@ GutterComponent = React.createClass
if previousDecorations?
for decoration in previousDecorations
node.classList.remove(decoration.class) if Decoration.isType(decoration, 'gutter') and not _.deepContains(decorations, decoration)
node.classList.remove(decoration.class) if editor.decorationMatchesType(decoration, 'gutter') and not _.deepContains(decorations, decoration)
if decorations?
for decoration in decorations
if Decoration.isType(decoration, 'gutter') and not _.deepContains(previousDecorations, decoration)
if editor.decorationMatchesType(decoration, 'gutter') and not _.deepContains(previousDecorations, decoration)
node.classList.add(decoration.class)
unless @screenRowsByLineNumberId[lineNumberId] is screenRow
+14 -37
Ver Arquivo
@@ -1,47 +1,27 @@
React = require 'react-atom-fork'
{div} = require 'reactionary-atom-fork'
{isEqualForProperties} = require 'underscore-plus'
module.exports =
HighlightComponent = React.createClass
displayName: 'HighlightComponent'
render: ->
{startPixelPosition, endPixelPosition, decoration} = @props
{editor, screenRange, decoration} = @props
{start, end} = screenRange
rowCount = end.row - start.row + 1
startPixelPosition = editor.pixelPositionForScreenPosition(start)
endPixelPosition = editor.pixelPositionForScreenPosition(end)
className = 'highlight'
className += " #{decoration.class}" if decoration.class?
div {className},
if endPixelPosition.top is startPixelPosition.top
@renderSingleLineRegions()
if rowCount is 1
@renderSingleLineRegions(startPixelPosition, endPixelPosition)
else
@renderMultiLineRegions()
@renderMultiLineRegions(startPixelPosition, endPixelPosition, rowCount)
componentDidMount: ->
{editor, decoration} = @props
if decoration.id?
@decoration = editor.decorationForId(decoration.id)
@decoration.on 'flash', @startFlashAnimation
@startFlashAnimation()
componentWillUnmount: ->
@decoration?.off 'flash', @startFlashAnimation
startFlashAnimation: ->
return unless flash = @decoration.consumeNextFlash()
node = @getDOMNode()
node.classList.remove(flash.class)
requestAnimationFrame =>
node.classList.add(flash.class)
clearTimeout(@flashTimeoutId)
removeFlashClass = -> node.classList.remove(flash.class)
@flashTimeoutId = setTimeout(removeFlashClass, flash.duration)
renderSingleLineRegions: ->
{startPixelPosition, endPixelPosition, lineHeightInPixels} = @props
renderSingleLineRegions: (startPixelPosition, endPixelPosition) ->
{lineHeightInPixels} = @props
[
div className: 'region', key: 0, style:
@@ -51,8 +31,8 @@ HighlightComponent = React.createClass
width: endPixelPosition.left - startPixelPosition.left
]
renderMultiLineRegions: ->
{startPixelPosition, endPixelPosition, lineHeightInPixels} = @props
renderMultiLineRegions: (startPixelPosition, endPixelPosition, rowCount) ->
{lineHeightInPixels} = @props
regions = []
index = 0
@@ -66,11 +46,11 @@ HighlightComponent = React.createClass
)
# Middle rows, extending from left side to right side of screen
if endPixelPosition.top - startPixelPosition.top > lineHeightInPixels
if rowCount > 2
regions.push(
div className: 'region', key: index++, style:
top: startPixelPosition.top + lineHeightInPixels
height: endPixelPosition.top - startPixelPosition.top - lineHeightInPixels
height: (rowCount - 2) * lineHeightInPixels
left: 0
right: 0
)
@@ -85,6 +65,3 @@ HighlightComponent = React.createClass
)
regions
shouldComponentUpdate: (newProps) ->
not isEqualForProperties(newProps, @props, 'startPixelPosition', 'endPixelPosition', 'lineHeightInPixels')
+3 -4
Ver Arquivo
@@ -8,16 +8,15 @@ HighlightsComponent = React.createClass
displayName: 'HighlightsComponent'
render: ->
div className: 'highlights',
@renderHighlights() if @isMounted()
div className: 'highlights', @renderHighlights()
renderHighlights: ->
{editor, highlightDecorations, lineHeightInPixels} = @props
highlightComponents = []
for markerId, {startPixelPosition, endPixelPosition, decorations} of highlightDecorations
for markerId, {screenRange, decorations} of highlightDecorations
for decoration in decorations
highlightComponents.push(HighlightComponent({editor, key: "#{markerId}-#{decoration.class}", startPixelPosition, endPixelPosition, decoration, lineHeightInPixels}))
highlightComponents.push(HighlightComponent({key: "#{markerId}-#{decoration.class}", screenRange, decoration, editor, lineHeightInPixels}))
highlightComponents
+22 -38
Ver Arquivo
@@ -4,7 +4,6 @@ React = require 'react-atom-fork'
{debounce, isEqual, isEqualForProperties, multiplyString, toArray} = require 'underscore-plus'
{$$} = require 'space-pen'
Decoration = require './decoration'
HighlightsComponent = require './highlights-component'
DummyLineNode = $$(-> @div className: 'line', style: 'position: absolute; visibility: hidden;', => @span 'x')[0]
@@ -17,25 +16,17 @@ LinesComponent = React.createClass
render: ->
if @isMounted()
{editor, highlightDecorations, scrollHeight, scrollWidth} = @props
{editor, highlightDecorations, scrollTop, scrollLeft, scrollHeight, scrollWidth} = @props
{lineHeightInPixels, defaultCharWidth, scrollViewHeight, scopedCharacterWidthsChangeCount} = @props
style =
height: Math.max(scrollHeight, scrollViewHeight)
width: scrollWidth
WebkitTransform: @getTransform()
WebkitTransform: "translate3d(#{-scrollLeft}px, #{-scrollTop}px, 0px)"
# The lines div must have the 'editor-colors' class so it has an opaque
# background to avoid sub-pixel anti-aliasing problems on the GPU
div {className: 'lines editor-colors', style},
HighlightsComponent({editor, highlightDecorations, lineHeightInPixels, defaultCharWidth, scopedCharacterWidthsChangeCount})
getTransform: ->
{scrollTop, scrollLeft, useHardwareAcceleration} = @props
if useHardwareAcceleration
"translate3d(#{-scrollLeft}px, #{-scrollTop}px, 0px)"
else
"translate(#{-scrollLeft}px, #{-scrollTop}px)"
HighlightsComponent({editor, highlightDecorations, lineHeightInPixels, defaultCharWidth, scopedCharacterWidthsChangeCount}) if @isMounted()
componentWillMount: ->
@measuredLines = new WeakSet
@@ -48,16 +39,13 @@ LinesComponent = React.createClass
return true unless isEqualForProperties(newProps, @props,
'renderedRowRange', 'lineDecorations', 'highlightDecorations', 'lineHeightInPixels', 'defaultCharWidth',
'scrollTop', 'scrollLeft', 'showIndentGuide', 'scrollingVertically', 'invisibles', 'visible',
'scrollViewHeight', 'mouseWheelScreenRow', 'scopedCharacterWidthsChangeCount', 'lineWidth', 'useHardwareAcceleration'
'scrollViewHeight', 'mouseWheelScreenRow', 'scopedCharacterWidthsChangeCount'
)
{renderedRowRange, pendingChanges} = newProps
[renderedStartRow, renderedEndRow] = renderedRowRange
for change in pendingChanges
if change.screenDelta is 0
return true unless change.end < renderedStartRow or renderedEndRow <= change.start
else
return true unless renderedEndRow <= change.start
return true unless change.end < renderedStartRow or renderedEndRow <= change.start
false
@@ -66,20 +54,20 @@ LinesComponent = React.createClass
@clearScreenRowCaches() unless prevProps.lineHeightInPixels is @props.lineHeightInPixels
@removeLineNodes() unless isEqualForProperties(prevProps, @props, 'showIndentGuide', 'invisibles')
@updateLines(@props.lineWidth isnt prevProps.lineWidth)
@updateLines()
@measureCharactersInNewLines() if visible and not scrollingVertically
clearScreenRowCaches: ->
@screenRowsByLineId = {}
@lineIdsByScreenRow = {}
updateLines: (updateWidth) ->
updateLines: ->
{editor, renderedRowRange, showIndentGuide, selectionChanged, lineDecorations} = @props
[startRow, endRow] = renderedRowRange
visibleLines = editor.linesForScreenRows(startRow, endRow - 1)
@removeLineNodes(visibleLines)
@appendOrUpdateVisibleLineNodes(visibleLines, startRow, updateWidth)
@appendOrUpdateVisibleLineNodes(visibleLines, startRow)
removeLineNodes: (visibleLines=[]) ->
{mouseWheelScreenRow} = @props
@@ -95,7 +83,7 @@ LinesComponent = React.createClass
delete @renderedDecorationsByLineId[lineId]
node.removeChild(lineNode)
appendOrUpdateVisibleLineNodes: (visibleLines, startRow, updateWidth) ->
appendOrUpdateVisibleLineNodes: (visibleLines, startRow) ->
{lineDecorations} = @props
newLines = null
@@ -105,7 +93,7 @@ LinesComponent = React.createClass
screenRow = startRow + index
if @hasLineNode(line.id)
@updateLineNode(line, screenRow, updateWidth)
@updateLineNode(line, screenRow)
else
newLines ?= []
newLinesHTML ?= ""
@@ -130,18 +118,18 @@ LinesComponent = React.createClass
@lineNodesByLineId.hasOwnProperty(lineId)
buildLineHTML: (line, screenRow) ->
{editor, mini, showIndentGuide, lineHeightInPixels, lineDecorations, lineWidth} = @props
{editor, mini, showIndentGuide, lineHeightInPixels, lineDecorations} = @props
{tokens, text, lineEnding, fold, isSoftWrapped, indentLevel} = line
classes = ''
if decorations = lineDecorations[screenRow]
for decoration in decorations
if Decoration.isType(decoration, 'line')
if editor.decorationMatchesType(decoration, 'line')
classes += decoration.class + ' '
classes += 'line'
top = screenRow * lineHeightInPixels
lineHTML = "<div class=\"#{classes}\" style=\"position: absolute; top: #{top}px; width: #{lineWidth}px;\" data-screen-row=\"#{screenRow}\">"
lineHTML = "<div class=\"#{classes}\" style=\"position: absolute; top: #{top}px;\" data-screen-row=\"#{screenRow}\">"
if text is ""
lineHTML += @buildEmptyLineInnerHTML(line)
@@ -158,7 +146,7 @@ LinesComponent = React.createClass
if showIndentGuide and indentLevel > 0
indentSpan = "<span class='indent-guide'>#{multiplyString(' ', tabLength)}</span>"
multiplyString(indentSpan, indentLevel)
multiplyString(indentSpan, indentLevel + 1)
else
"&nbsp;"
@@ -215,8 +203,8 @@ LinesComponent = React.createClass
scopeStack.push(scope)
"<span class=\"#{scope.replace(/\.+/g, ' ')}\">"
updateLineNode: (line, screenRow, updateWidth) ->
{editor, lineHeightInPixels, lineDecorations, lineWidth} = @props
updateLineNode: (line, screenRow) ->
{editor, lineHeightInPixels, lineDecorations} = @props
lineNode = @lineNodesByLineId[line.id]
decorations = lineDecorations[screenRow]
@@ -224,15 +212,13 @@ LinesComponent = React.createClass
if previousDecorations?
for decoration in previousDecorations
lineNode.classList.remove(decoration.class) if Decoration.isType(decoration, 'line') and not _.deepContains(decorations, decoration)
lineNode.classList.remove(decoration.class) if editor.decorationMatchesType(decoration, 'line') and not _.deepContains(decorations, decoration)
if decorations?
for decoration in decorations
if Decoration.isType(decoration, 'line') and not _.deepContains(previousDecorations, decoration)
if editor.decorationMatchesType(decoration, 'line') and not _.deepContains(previousDecorations, decoration)
lineNode.classList.add(decoration.class)
lineNode.style.width = lineWidth + 'px' if updateWidth
unless @screenRowsByLineId[line.id] is screenRow
lineNode.style.top = screenRow * lineHeightInPixels + 'px'
lineNode.dataset.screenRow = screenRow
@@ -262,12 +248,10 @@ LinesComponent = React.createClass
[visibleStartRow, visibleEndRow] = @props.renderedRowRange
node = @getDOMNode()
editor.batchCharacterMeasurement =>
for tokenizedLine in editor.linesForScreenRows(visibleStartRow, visibleEndRow - 1)
unless @measuredLines.has(tokenizedLine)
lineNode = @lineNodesByLineId[tokenizedLine.id]
@measureCharactersInLine(tokenizedLine, lineNode)
return
for tokenizedLine in editor.linesForScreenRows(visibleStartRow, visibleEndRow - 1)
unless @measuredLines.has(tokenizedLine)
lineNode = @lineNodesByLineId[tokenizedLine.id]
@measureCharactersInLine(tokenizedLine, lineNode)
measureCharactersInLine: (tokenizedLine, lineNode) ->
{editor} = @props
+4 -24
Ver Arquivo
@@ -67,6 +67,7 @@ class Package
@loadKeymaps()
@loadMenus()
@loadStylesheets()
@grammarsPromise = @loadGrammars()
@scopedPropertiesPromise = @loadScopedProperties()
@requireMainModule() unless @hasActivationEvents()
@@ -82,8 +83,6 @@ class Package
@scopedProperties = []
activate: ->
@grammarsPromise ?= @loadGrammars()
unless @activationDeferred?
@activationDeferred = Q.defer()
@measure 'activateTime', =>
@@ -129,9 +128,8 @@ class Package
atom.contextMenu.add(menuPath, map['context-menu']) for [menuPath, map] in @menus
atom.menu.add(map.menu) for [menuPath, map] in @menus when map.menu
unless @grammarsActivated
grammar.activate() for grammar in @grammars
@grammarsActivated = true
grammar.activate() for grammar in @grammars
@grammarsActivated = true
scopedProperties.activate() for scopedProperties in @scopedProperties
@scopedPropertiesActivated = true
@@ -175,32 +173,14 @@ class Package
else
fs.listSync(stylesheetDirPath, ['css', 'less'])
loadGrammarsSync: ->
return if @grammarsLoaded
grammarsDirPath = path.join(@path, 'grammars')
grammarPaths = fs.listSync(grammarsDirPath, ['json', 'cson'])
for grammarPath in grammarPaths
try
grammar = atom.syntax.readGrammarSync(grammarPath)
grammar.packageName = @name
@grammars.push(grammar)
grammar.activate()
catch error
console.warn("Failed to load grammar: #{grammarPath}", error.stack ? error)
@grammarsLoaded = true
@grammarsActivated = true
loadGrammars: ->
return Q() if @grammarsLoaded
@grammars = []
loadGrammar = (grammarPath, callback) =>
atom.syntax.readGrammar grammarPath, (error, grammar) =>
if error?
console.warn("Failed to load grammar: #{grammarPath}", error.stack ? error)
else
grammar.packageName = @name
@grammars.push(grammar)
grammar.activate() if @grammarsActivated
callback()
-4
Ver Arquivo
@@ -8,8 +8,6 @@ class PaneContainer extends Model
atom.deserializers.add(this)
Serializable.includeInto(this)
@version: 1
@properties
root: -> new Pane
activePane: null
@@ -29,12 +27,10 @@ class PaneContainer extends Model
deserializeParams: (params) ->
params.root = atom.deserializers.deserialize(params.root, container: this)
params.destroyEmptyPanes = atom.config.get('core.destroyEmptyPanes')
params.activePane = params.root.getPanes().find (pane) -> pane.id is params.activePaneId
params
serializeParams: (params) ->
root: @root?.serialize()
activePaneId: @activePane.id
replaceChild: (oldChild, newChild) ->
throw new Error("Replacing non-existent child") if oldChild isnt @root
+3 -1
Ver Arquivo
@@ -40,12 +40,14 @@ class Pane extends Model
@subscribe @items.onRemoval (item, index) =>
@unsubscribe item if typeof item.on is 'function'
@activate() if params?.active
# Called by the Serializable mixin during serialization.
serializeParams: ->
id: @id
items: compact(@items.map((item) -> item.serialize?()))
activeItemUri: @activeItem?.getUri?()
focused: @focused
active: @active
# Called by the Serializable mixin during deserialization.
deserializeParams: (params) ->
-4
Ver Arquivo
@@ -239,9 +239,6 @@ class Project extends Model
task.on 'scan:result-found', (result) =>
iterator(result) unless @isPathModified(result.filePath)
task.on 'scan:file-error', (error) ->
iterator(null, error)
if _.isFunction(options.onPathsSearched)
task.on 'scan:paths-searched', (numberOfPathsSearched) ->
options.onPathsSearched(numberOfPathsSearched)
@@ -286,7 +283,6 @@ class Project extends Model
checkFinished()
task.on 'replace:path-replaced', iterator
task.on 'replace:file-error', (error) -> iterator(null, error)
for buffer in @getBuffers()
continue unless buffer.getPath() in filePaths
-2
Ver Arquivo
@@ -202,6 +202,4 @@ class ReactEditorView extends View
updateDisplay: -> # No-op shim for package specs
resetDisplay: -> # No-op shim for package specs
redraw: -> # No-op shim
+2 -4
Ver Arquivo
@@ -6,10 +6,8 @@ module.exports = (filePaths, regexSource, regexFlags, replacementText) ->
replacer = new PathReplacer()
regex = new RegExp(regexSource, regexFlags)
replacer.on 'file-error', ({code, path, message}) ->
emit('replace:file-error', {code, path, message})
replacer.on 'path-replaced', (result) ->
emit('replace:path-replaced', result)
replacer.replacePaths(regex, replacementText, filePaths, -> callback())
replacer.replacePaths regex, replacementText, filePaths, ->
callback()
-3
Ver Arquivo
@@ -9,9 +9,6 @@ module.exports = (rootPath, regexSource, options) ->
searcher = new PathSearcher()
scanner = new PathScanner(rootPath, options)
searcher.on 'file-error', ({code, path, message}) ->
emit('scan:file-error', {code, path, message})
searcher.on 'results-found', (result) ->
emit('scan:result-found', result)
-6
Ver Arquivo
@@ -15,8 +15,6 @@ class Selection extends Model
constructor: ({@cursor, @marker, @editor, id}) ->
@assignId(id)
@cursor.selection = this
@decoration = @editor.decorateMarker(@marker, type: 'highlight', class: 'selection')
@marker.on 'changed', => @screenRangeChanged()
@marker.on 'destroyed', =>
@destroyed = true
@@ -78,12 +76,9 @@ class Selection extends Model
options.reversed ?= @isReversed()
@editor.destroyFoldsIntersectingBufferRange(bufferRange) unless options.preserveFolds
@modifySelection =>
needsFlash = options.flash
delete options.flash if options.flash?
@cursor.needsAutoscroll = false if @needsAutoscroll?
@marker.setBufferRange(bufferRange, options)
@autoscroll() if @needsAutoscroll and @editor.manageScrollPosition
@decoration.flash('flash', @editor.selectionFlashDuration) if needsFlash
# Public: Returns the starting and ending buffer rows the selection is
# highlighting.
@@ -325,7 +320,6 @@ class Selection extends Model
text = @normalizeIndents(text, options.indentBasis)
newBufferRange = @editor.buffer.setTextInRange(oldBufferRange, text, pick(options, 'undo'))
if options.select
@setBufferRange(newBufferRange, reversed: wasReversed)
else
+4 -4
Ver Arquivo
@@ -2,8 +2,8 @@ _ = require 'underscore-plus'
textUtils = require './text-utils'
WhitespaceRegexesByTabLength = {}
LeadingSpaceRegex = /^[ ]+/
TrailingSpaceRegex = /[ ]+$/
LeadingWhitespaceRegex = /^[ ]+/
TrailingWhitespaceRegex = /[ ]+$/
EscapeRegex = /[&"'<>]/g
CharacterRegex = /./g
StartCharacterRegex = /^./
@@ -151,7 +151,7 @@ class Token
leadingHtml = ''
trailingHtml = ''
if @hasLeadingWhitespace and match = LeadingSpaceRegex.exec(@value)
if @hasLeadingWhitespace and match = LeadingWhitespaceRegex.exec(@value)
classes = 'leading-whitespace'
classes += ' indent-guide' if hasIndentGuide
classes += ' invisible-character' if invisibles.space
@@ -161,7 +161,7 @@ class Token
startIndex = match[0].length
if @hasTrailingWhitespace and match = TrailingSpaceRegex.exec(@value)
if @hasTrailingWhitespace and match = TrailingWhitespaceRegex.exec(@value)
tokenIsOnlyWhitespace = match[0].length is @value.length
classes = 'trailing-whitespace'
classes += ' indent-guide' if hasIndentGuide and not @hasLeadingWhitespace and tokenIsOnlyWhitespace
+4 -22
Ver Arquivo
@@ -161,26 +161,13 @@ class TokenizedBuffer extends Model
previousEndStack = @stackForRow(end) # used in spill detection below
newTokenizedLines = @buildTokenizedLinesForRows(start, end + delta, @stackForRow(start - 1))
_.spliceWithArray(@tokenizedLines, start, end - start + 1, newTokenizedLines)
start = @retokenizeWhitespaceRowsIfIndentLevelChanged(start - 1, -1)
end = @retokenizeWhitespaceRowsIfIndentLevelChanged(newRange.end.row + 1, 1) - delta
newEndStack = @stackForRow(end + delta)
if newEndStack and not _.isEqual(newEndStack, previousEndStack)
@invalidateRow(end + delta + 1)
@emit "changed", { start, end, delta, bufferChange: e }
retokenizeWhitespaceRowsIfIndentLevelChanged: (row, increment) ->
line = @tokenizedLines[row]
if line?.isOnlyWhitespace() and @indentLevelForRow(row) isnt line.indentLevel
while line?.isOnlyWhitespace()
@tokenizedLines[row] = @buildTokenizedTokenizedLineForRow(row, @stackForRow(row - 1))
row += increment
line = @tokenizedLines[row]
row - increment
buildTokenizedLinesForRows: (startRow, endRow, startingStack) ->
ruleStack = startingStack
stopTokenizingAt = startRow + @chunkSize
@@ -231,27 +218,22 @@ class TokenizedBuffer extends Model
indentLevelForRow: (row) ->
line = @buffer.lineForRow(row)
indentLevel = 0
if line is ''
nextRow = row + 1
lineCount = @getLineCount()
while nextRow < lineCount
nextLine = @buffer.lineForRow(nextRow)
unless nextLine is ''
indentLevel = Math.ceil(@indentLevelForLine(nextLine))
break
return @indentLevelForLine(nextLine) unless nextLine is ''
nextRow++
previousRow = row - 1
while previousRow >= 0
previousLine = @buffer.lineForRow(previousRow)
unless previousLine is ''
indentLevel = Math.max(Math.ceil(@indentLevelForLine(previousLine)), indentLevel)
break
return @indentLevelForLine(previousLine) unless previousLine is ''
previousRow--
indentLevel
0
else
@indentLevelForLine(line)
-8
Ver Arquivo
@@ -152,14 +152,6 @@ class TokenizedLine
break
false
isOnlyWhitespace: ->
if @text == ''
true
else
for token in @tokens
return false unless token.isOnlyWhitespace()
true
tokenAtIndex: (index) ->
@tokens[index]
-18
Ver Arquivo
@@ -46,9 +46,6 @@ class Workspace extends Model
# Called by the Serializable mixin during deserialization
deserializeParams: (params) ->
for packageName in params.packagesWithActiveGrammars ? []
atom.packages.getLoadedPackage(packageName)?.loadGrammarsSync()
params.paneContainer = PaneContainer.deserialize(params.paneContainer)
params
@@ -56,21 +53,6 @@ class Workspace extends Model
serializeParams: ->
paneContainer: @paneContainer.serialize()
fullScreen: atom.isFullScreen()
packagesWithActiveGrammars: @getPackageNamesWithActiveGrammars()
getPackageNamesWithActiveGrammars: ->
packageNames = []
addGrammar = ({includedGrammarScopes, packageName}={}) ->
return unless packageName
# Prevent cycles
return if packageNames.indexOf(packageName) isnt -1
packageNames.push(packageName)
for scopeName in includedGrammarScopes ? []
addGrammar(atom.syntax.grammarForScopeName(scopeName))
addGrammar(editor.getGrammar()) for editor in @getEditors()
_.uniq(packageNames)
editorAdded: (editor) ->
@emit 'editor-created', editor
-14
Ver Arquivo
@@ -19,17 +19,3 @@
}
}
}
.define-selection-flash-color-if-not-defined() { @syntax-selection-flash-color: rgba(100, 255, 100, 0.7); }
.define-selection-flash-color-if-not-defined();
@-webkit-keyframes flash {
from { background-color: @syntax-selection-flash-color; }
to { background-color: null; }
}
.editor .flash.selection .region {
-webkit-animation-name: flash;
-webkit-animation-duration: .5s;
-webkit-animation-iteration-count: 1;
}
-1
Ver Arquivo
@@ -5,7 +5,6 @@
@syntax-text-color: #333;
@syntax-cursor-color: #333;
@syntax-selection-color: #69c;
@syntax-selection-flash-color: #00f; // Color the selection is 'flashed' when you run find next
@syntax-background-color: #fff;
// Guide colors