Comparar commits

...

103 Commits

Autor SHA1 Mensagem Data
Kevin Sawicki ff70ae633d Correct broken link to npm 2013-07-12 17:30:05 -07:00
Kevin Sawicki d1f372e439 Rebuild native modules when atom-shell is upgraded
Spawn an apm rebuild when the atom shell version changes
after running the update-atom-shell script.

Closes #618
2013-07-12 14:48:10 -07:00
Kevin Sawicki 041f52aaaa Upgrade apm 2013-07-12 14:07:03 -07:00
Kevin Sawicki 270d17814e Move right border to tree view resizer
This allows the border to still show when the tree view
scrolls horizontally.

Closes #622
2013-07-12 13:59:52 -07:00
Kevin Sawicki 16095c8086 Add New Window to File menu
Closes #626
2013-07-11 20:22:43 -07:00
Coby Chapple 94e2dbbc2c extraneous paren in package docs 2013-07-11 10:20:29 +01:00
Kevin Sawicki 12580bce83 Guard against missing file path in getScore() 2013-07-10 08:54:15 -07:00
Cheng Zhao 753b11cf15 Register Atom to handle atom:// scheme URLs. 2013-07-10 18:57:26 +08:00
Kevin Sawicki 0fee962faa Mention j/k support 2013-07-09 09:22:35 -07:00
Kevin Sawicki ed1f51b987 Map k/j to up/down in archive-view 2013-07-08 18:57:58 -07:00
Kevin Sawicki f1bdcaedc1 Support moving up/down in tree view with k/j keys 2013-07-08 17:06:16 -07:00
Kevin Sawicki 2efbe9ce4e Run partial-clean during deploy task 2013-07-08 11:29:46 -07:00
Kevin Sawicki 3366c4d6a5 Remove node_modules before bootstrapping 2013-07-08 11:29:28 -07:00
Kevin Sawicki acb69a4221 Format stack traces in console reporter
This generates valid CoffeeScript line/column numbers and
also removes noisy lines from jasmine.js and from the grunt
stack portion for the initial test process spawn.
2013-07-06 15:39:32 -07:00
Kevin Sawicki b3b501ef07 Set stack trace overflow to auto
This keeps the stack trace text inside the spec box when the window
in narrower than the stack trace lines.
2013-07-06 14:27:23 -07:00
Kevin Sawicki e34d8e4c42 Display CoffeeScript line numbers in stack traces
Use coffeestack to convert stack traces to have CoffeeScript
line and column numbers in the output instead of JavaScript line
and column numbers.
2013-07-06 14:27:16 -07:00
Kevin Sawicki adebae6c47 Remove jasmine.js lines from displayed stack trace
This removes the noise from the setup and compare lines that occur in
jasmine.js and only displays the lines that are generated from within
the failing spec.
2013-07-06 14:03:13 -07:00
Kevin Sawicki 4ae0d8af9f Use tantamount for _.isEqual() implementation
This code was needed in telepath so it was pulled out as a
standalone module with the exact same behavior as was previously
in Atom.
2013-07-06 13:54:46 -07:00
Kevin Sawicki 651bbaa3ce Create an empty ~/.atom/config.cson when missing
Closes #614
2013-07-05 09:17:44 -07:00
Kevin Sawicki & Nathan Sobo 0448ba5ceb Remove atom-shell during partial-clean task instead of clean task 2013-07-03 17:53:43 -07:00
Kevin Sawicki & Nathan Sobo 6d70bf9106 Remove node_modules during script/cibuild so they recompile during bootstrap 2013-07-03 17:53:43 -07:00
Cheng Zhao 857629e07e Revert "Revert "Upgrade apm: update node to v0.10.12.""
This reverts commit 18c5c788d7.
2013-07-04 08:52:13 +08:00
Cheng Zhao 18c5c788d7 Revert "Upgrade apm: update node to v0.10.12."
This reverts commit 433beac9aa.
2013-07-04 08:37:59 +08:00
Cheng Zhao a8e7a9a091 Should also clean atom-shell. 2013-07-04 07:22:15 +08:00
Kevin Sawicki 59097ddf96 Remove ~/.atom/.node-gyp during clean 2013-07-03 09:26:04 -07:00
Cheng Zhao 433beac9aa Upgrade apm: update node to v0.10.12. 2013-07-03 18:23:41 +08:00
Kevin Sawicki c7f6e87132 Only use event.which when key identifier is non-ASCII
Previously event.which was used when it was less than the key identifier
which broke fn-delete since that generates a valid key identifier but a
lower event.which value that does not translate to 'delete' using the char
code converter.

Close #611
2013-07-02 13:13:45 -07:00
Garen Torikian 64e2fee975 Merge pull request #610 from github/add-nooutput-to-biscotto
Bump the biscotto version
2013-07-02 11:13:20 -07:00
Garen Torikian df35cb0756 Bump the biscotto version
This prevents doc builds from occuring when you're only interested in stats/missing
2013-07-02 11:07:58 -07:00
Kevin Sawicki & Nathan Sobo 0e6a3c52ad Add comments to view cache ivars 2013-07-02 10:13:59 -07:00
Kevin Sawicki b786bcc774 Store views that don't implement setModel() by their item
Previously viewForItem() would create a new view each time it was called
with an item whose view did not implement setModel() even if a view for that
item already existed in the pane.

Now a WeakMap is used to map items to their view so they can be reused
and cleaned up even when the view does not implement setModel().
2013-07-02 09:41:46 -07:00
Kevin Sawicki 6cb13e843c Mention more fixed and added items 2013-07-02 09:08:57 -07:00
Kevin Sawicki 7e76721712 Don't call realpathSync for non-existent directory 2013-07-01 13:23:47 -07:00
Nathan Sobo 23df564189 Release any leftover buffers in Project.destroy 2013-07-01 14:21:42 -06:00
Nathan Sobo 0c17ed9c33 Return a clone of @buffers from Project.getBuffers
Previously, we traversed the EditSessions. Not necessary.
2013-07-01 14:21:42 -06:00
Kevin Sawicki cde9ae02fe Prevent clash between path require and variable name 2013-07-01 13:07:35 -07:00
Kevin Sawicki 77017c2cd3 Compare against realpath of HOME 2013-07-01 12:59:31 -07:00
Kevin Sawicki 7615d54337 Support calling fsUtils.absolute() with a '~' path 2013-07-01 12:46:50 -07:00
Kevin Sawicki 6b591b121d Interpolate pathToCreate instead of path
This regressed as part of the migration to using helpers from
path instead of fs-utils.

Close #608
2013-07-01 12:10:52 -07:00
Kevin Sawicki & Nathan Sobo 268edf16d8 Make setModel optional in pane item view classes 2013-07-01 10:53:34 -07:00
Kevin Sawicki 01f220fb1b Support non-English keyboard languages
Use event.which if it is lower than the parsed key identifier.
This is the case when a non-English keyboard language is selected and
a physical English keyboard is being used.

This allows keybindings to still work even when the physical key pressed
is different than the key it maps to for the currently selected language.

Closes #585
2013-06-28 16:36:55 -07:00
Kevin Sawicki 53a92751e6 Add missing @ before call to confirmSync 2013-06-28 10:06:41 -07:00
Nathan Sobo b66431e3a6 Delete atom.windowState in global afterEach
It seems like the windowState was getting saved to disk, causing weird
window state to be loaded on the next test run and a spec to fail.
2013-06-28 04:39:31 -06:00
Nathan Sobo 5a9e45f9d8 Upgrade telepath 2013-06-28 04:39:31 -06:00
Kevin Sawicki 8561bb34a8 Save and restore spec window dimensions
Closes #597
2013-06-28 04:39:30 -06:00
Kevin Sawicki & Nathan Sobo d55c09c9d3 Nuke documentation threshold specs
We're going to make it a lint task that's run via grunt.
2013-06-28 04:39:30 -06:00
Kevin Sawicki & Nathan Sobo f4300b8cab Fix specs due to scrollTop/Left becoming methods on EditSession 2013-06-28 04:39:30 -06:00
Kevin Sawicki & Nathan Sobo f3f9c2c921 Show active item from Pane constructor if state has activeItemUri 2013-06-28 04:39:30 -06:00
Kevin Sawicki & Nathan Sobo 33dca9315c Add PaneContainer.getState 2013-06-28 04:39:30 -06:00
Kevin Sawicki & Nathan Sobo c596514d11 Accept documents in EditSession and replicate scroll position 2013-06-28 04:39:30 -06:00
Kevin Sawicki & Nathan Sobo 390b03647e Don't clear #jasmine-content when window.debugContent is true 2013-06-28 04:39:30 -06:00
Kevin Sawicki & Nathan Sobo 5b00cf1701 Rename Buffer -> TextBuffer to match file and deserializer name 2013-06-28 04:39:29 -06:00
Kevin Sawicki & Nathan Sobo 95e69ad858 Use .getState() instead of .serialize() in replication specs 2013-06-28 04:39:29 -06:00
Kevin Sawicki & Nathan Sobo ef0363e8ff Use jasmine-focused npm instead of spec/jasmine-focused.coffee 2013-06-28 04:39:29 -06:00
Kevin Sawicki & Nathan Sobo a62cd0f16a Replicate active pane item 2013-06-28 04:39:29 -06:00
Kevin Sawicki & Nathan Sobo f340828506 Use .getState() instead of .serialize() when mutating panes 2013-06-28 04:39:29 -06:00
Kevin Sawicki & Nathan Sobo 8b0a68dd4a Return this from $.fn.attachToDom spec helper 2013-06-28 04:39:29 -06:00
Kevin Sawicki 1049a677bf Set dimension of spec window 2013-06-28 04:39:29 -06:00
Kevin Sawicki d2bc415042 Remove telepath from package.json 2013-06-28 04:39:28 -06:00
Kevin Sawicki b439e6239d Add telepath as submodule 2013-06-28 04:39:28 -06:00
Kevin Sawicki b999c71ad6 Auto-insert clipboard when it is a GUID 2013-06-28 04:39:28 -06:00
Kevin Sawicki 9f31f9a76b Add loading view when joining session 2013-06-28 04:39:28 -06:00
Kevin Sawicki & Nathan Sobo 7fe356b649 Ensure events are delivered in order 2013-06-28 04:39:28 -06:00
Kevin Sawicki & Nathan Sobo b5aa0b900c Remove output listener when connection is closed 2013-06-28 04:39:28 -06:00
Kevin Sawicki & Nathan Sobo cd4622fbeb Serialize project in window state 2013-06-28 04:39:27 -06:00
Kevin Sawicki & Nathan Sobo 89192c2ee2 Extract helpers to session-utils 2013-06-28 04:39:27 -06:00
Kevin Sawicki & Nathan Sobo b5b408d134 Open new window when joining collaboration session 2013-06-28 04:39:27 -06:00
Kevin Sawicki b08f320ed5 Remove mini class to give id enough room 2013-06-28 04:39:27 -06:00
Kevin Sawicki 4c7025ae81 Add message to join prompt 2013-06-28 04:39:27 -06:00
Kevin Sawicki 554af1becb Add initial collaboration keymap 2013-06-28 04:39:27 -06:00
Kevin Sawicki 6d49e0fd57 Pass through all window settings as load settings 2013-06-28 04:39:26 -06:00
Kevin Sawicki 31d872fbfe Add atom.openWindow() 2013-06-28 04:39:26 -06:00
Kevin Sawicki b842a727ee Support sending in windowState to AtomWindow ctor 2013-06-28 04:39:26 -06:00
Kevin Sawicki & Nathan Sobo 0851b4d011 Replicate pane splitting and removal
We're using Peer.js to stream changes to shared telepath documents
between participants.

We're replacing the rootView of joiners in a somewhat hacky way,
but replication of pane splits and items is fully tested.
2013-06-28 04:39:26 -06:00
Kevin Sawicki & Nathan Sobo 8a7c57994d Remove parens from require 2013-06-28 04:39:26 -06:00
Kevin Sawicki & Nathan Sobo 6480e956af Keep resident window state object 2013-06-28 04:39:26 -06:00
Kevin Sawicki & Nathan Sobo 9c95a4751b Return telepath documents from getWindowState() 2013-06-28 04:39:25 -06:00
Kevin Sawicki & Nathan Sobo d283834978 Add initial document sharing over peerJS connection 2013-06-28 04:38:22 -06:00
Kevin Sawicki 66b490b5da Add initial collaboration package 2013-06-28 04:38:22 -06:00
Kevin Sawicki 0d252ab9fd Use parent directory as resource path 2013-06-27 09:19:37 -07:00
Kevin Sawicki 3e8de2d22d Use config to retrieve contents directory 2013-06-27 09:18:22 -07:00
Kevin Sawicki 52aee1d050 💄 2013-06-27 09:11:15 -07:00
Kevin Sawicki ff9dc2c5af Look under atom instead of globals for buildDir 2013-06-27 09:10:18 -07:00
Kevin Sawicki 3b8cdb58e2 Rename docs to docs-task 2013-06-27 09:08:16 -07:00
Kevin Sawicki bd14aeee17 Move Grunt tasks to tasks directory 2013-06-27 09:07:33 -07:00
Cheng Zhao e434f7c0a9 💄 2013-06-27 22:39:41 +08:00
Cheng Zhao 837e3000d3 Merge pull request #605 from github/beforeunload
Use beforeunload handler to control whether window should close
2013-06-27 07:33:35 -07:00
Cheng Zhao e1c2aa0da1 Fix specs regarding beforeunload event. 2013-06-27 21:31:07 +08:00
Cheng Zhao e7aac2ef6e Show confirm close dialog as sheet. 2013-06-27 21:30:47 +08:00
Cheng Zhao f9545acde6 Show window before opening devtools.
It may happen that an exception is thrown before window is shown.
2013-06-27 19:29:35 +08:00
Cheng Zhao 45ce8e1d63 Ask for close confirmation in beforeunload handler. 2013-06-27 18:39:29 +08:00
Cheng Zhao bdbec54f24 Make PaneContainer.confirmClose() synchronous. 2013-06-27 16:21:14 +08:00
Cheng Zhao 1df48d1725 Fix spec of confirmSync in 'window:close'. 2013-06-27 15:07:38 +08:00
Cheng Zhao 6c0f4c09d9 Make Pane.promptToSaveItem synchronous. 2013-06-27 12:40:36 +08:00
Cheng Zhao f45ce3a7ee Upgrade apm: update to node v0.10.12. 2013-06-27 10:59:09 +08:00
Kevin Sawicki dc6e624eda Add grunt tasks to generate and lint docs
Closes #604
2013-06-26 19:25:50 -07:00
Kevin Sawicki e67676b01c Use deleteSelectedText() instead of delete()
Selection.delete() adds to the selection if it is empty which
we don't want to do when replacing selected text.

Closes #603
2013-06-26 19:03:45 -07:00
Kevin Sawicki f37ae7e4e7 Upgrade dev dependencies 2013-06-26 08:57:52 -07:00
Kevin Sawicki f913f6a8d5 Upgrade dependencies 2013-06-26 08:56:04 -07:00
Kevin Sawicki 20991381bd Remove unneeded stdout/stderr output forwarding 2013-06-25 17:47:21 -07:00
Kevin Sawicki 6930fe0eff Mention keymap fixes 2013-06-25 13:47:39 -07:00
Kevin Sawicki f3b50eed3b Migrate close bindings from editor namespace to pane
These were left over from the pane migration still under
the editor namespace and were previously not accessible via
a keybinding.
2013-06-25 13:15:39 -07:00
probablycorey a4217909c0 Don't check for updates in background if version is a sha
If the version is a 7 char sha, then we assume it is a local build.
2013-06-25 09:54:03 -07:00
76 arquivos alterados com 3458 adições e 663 exclusões
+3
Ver Arquivo
@@ -4,3 +4,6 @@
[submodule "vendor/apm"]
path = vendor/apm
url = https://github.com/github/apm.git
[submodule "vendor/telepath"]
path = vendor/telepath
url = https://github.com/github/telepath.git
+12
Ver Arquivo
@@ -1,3 +1,15 @@
* Fixed: cmd-n now works when no windows are open
* Fixed: Error selecting a grammar for an untitled editor
* Added: j/k now can be used to navigate the tree view and archive editor
* Fixed: Atom can now be launched when ~/.atom/config.cson doesn't exist
* Added: Initial collaboration sessions
* Fixed: Empty lines being deleted via uppercase/downcase command
* Fixed: Keybindings not working when using non-English keyboard language
* Fixed: cmd-shift-p and cmd-alt-w not doing anything when pressed
* Improved: Use grunt (instead of rake) for build system
* Fixed: Java files not syntax highlighting correctly.
* Fixed: LESS/CSS now indents properly after hitting enter.
+13 -143
Ver Arquivo
@@ -1,29 +1,28 @@
fs = require 'fs'
path = require 'path'
walkdir = require 'walkdir'
module.exports = (grunt) ->
APP_NAME = "Atom.app"
BUILD_DIR = grunt.option('build-dir') ? "/tmp/atom-build/"
SHELL_APP_DIR = path.join(BUILD_DIR, APP_NAME)
CONTENTS_DIR = path.join(SHELL_APP_DIR, 'Contents')
APP_DIR = path.join(CONTENTS_DIR, "Resources", "app")
INSTALL_DIR = path.join('/Applications', APP_NAME)
appName = 'Atom.app'
buildDir = grunt.option('build-dir') ? '/tmp/atom-build'
shellAppDir = path.join(buildDir, appName)
contentsDir = path.join(shellAppDir, 'Contents')
appDir = path.join(contentsDir, 'Resources', 'app')
installDir = path.join('/Applications', appName)
grunt.initConfig
pkg: grunt.file.readJSON('package.json')
atom: {appDir, appName, buildDir, contentsDir, installDir, shellAppDir}
coffee:
options:
sourceMap: true
glob_to_multiple:
expand: true
src: [
'src/**/*.coffee'
'static/**/*.coffee'
]
dest: APP_DIR
dest: appDir
ext: '.js'
less:
@@ -39,7 +38,7 @@ module.exports = (grunt) ->
'static/**/*.less'
'themes/**/*.less'
]
dest: APP_DIR
dest: appDir
ext: '.css'
cson:
@@ -52,7 +51,7 @@ module.exports = (grunt) ->
'static/**/*.cson'
'themes/**/*.cson'
]
dest: APP_DIR
dest: appDir
ext: '.json'
coffeelint:
@@ -61,7 +60,6 @@ module.exports = (grunt) ->
level: 'error'
max_line_length:
level: 'ignore'
src: [
'dot-atom/**/*.coffee'
'src/**/*.coffee'
@@ -110,138 +108,10 @@ module.exports = (grunt) ->
grunt.loadNpmTasks('grunt-contrib-csslint')
grunt.loadNpmTasks('grunt-contrib-coffee')
grunt.loadNpmTasks('grunt-contrib-less')
grunt.registerTask 'partial-clean', 'Delete some of the build files', ->
rm BUILD_DIR
rm '/tmp/atom-coffee-cache'
rm '/tmp/atom-cached-atom-shells'
rm 'node'
grunt.registerTask 'clean', 'Delete all the build files', ->
rm 'node_modules'
grunt.task.run('partial-clean')
grunt.registerTask 'build', 'Build the application', ->
rm SHELL_APP_DIR
mkdir path.dirname(BUILD_DIR)
cp 'atom-shell/Atom.app', SHELL_APP_DIR
mkdir APP_DIR
cp 'atom.sh', path.join(APP_DIR, 'atom.sh')
cp 'package.json', path.join(APP_DIR, 'package.json')
directories = [
'benchmark'
'dot-atom'
'spec'
'vendor'
]
{devDependencies, dependencies} = grunt.file.readJSON('package.json')
for child in fs.readdirSync('node_modules')
directory = path.join('node_modules', child)
try
{name} = grunt.file.readJSON(path.join(directory, 'package.json'))
if not devDependencies[name]? or dependencies[name]?
directories.push(directory)
catch e
directories.push(directory)
ignoredPaths = [
path.join('git-utils', 'deps')
path.join('oniguruma', 'deps')
path.join('vendor', 'apm')
path.join('vendor', 'bootstrap', 'docs')
]
ignoredPaths = ignoredPaths.map (ignoredPath) -> "(#{ignoredPath})"
nodeModulesFilter = new RegExp(ignoredPaths.join('|'))
for directory in directories
cp directory, path.join(APP_DIR, directory), filter: nodeModulesFilter
cp 'src', path.join(APP_DIR, 'src'), filter: /.+\.(cson|coffee|less)$/
cp 'static', path.join(APP_DIR, 'static'), filter: /.+\.less$/
cp 'themes', path.join(APP_DIR, 'themes'), filter: /.+\.(cson|less)$/
grunt.file.recurse path.join('resources', 'mac'), (sourcePath, rootDirectory, subDirectory='', filename) ->
unless /.+\.plist/.test(sourcePath)
grunt.file.copy(sourcePath, path.resolve(APP_DIR, '..', subDirectory, filename))
grunt.task.run('compile', 'copy-info-plist')
grunt.registerTask 'copy-info-plist', 'Copy plist', ->
plistPath = path.join(CONTENTS_DIR, 'Info.plist')
helperPlistPath = path.join(CONTENTS_DIR, 'Frameworks/Atom Helper.app/Contents/Info.plist')
# Copy custom plist files
cp 'resources/mac/atom-Info.plist', plistPath
cp 'resources/mac/helper-Info.plist', helperPlistPath
grunt.registerTask 'set-development-version', "Sets version to current sha", ->
done = @async()
spawn cmd: 'script/set-version', args: [BUILD_DIR], (error, result, code) ->
done(error)
grunt.registerTask 'codesign', 'Codesign the app', ->
done = @async()
args = ["-f", "-v", "-s", "Developer ID Application: GitHub", SHELL_APP_DIR]
spawn cmd: "codesign", args: args, (error) -> done(error)
grunt.registerTask 'install', 'Install the built application', ->
rm INSTALL_DIR
mkdir path.dirname(INSTALL_DIR)
cp SHELL_APP_DIR, INSTALL_DIR
grunt.registerTask 'update-atom-shell', 'Update atom-shell', ->
done = @async()
spawn cmd: 'script/update-atom-shell', (error) -> done(error)
grunt.registerTask 'test', 'Run the specs', ->
done = @async()
commands = []
commands.push (callback) ->
spawn cmd: 'pkill', args: ['Atom'], -> callback()
commands.push (callback) ->
atomBinary = path.join(CONTENTS_DIR, 'MacOS', 'Atom')
spawn cmd: atomBinary, args: ['--test', "--resource-path=#{__dirname}"], (error, result) ->
process.stderr.write(result.stderr)
process.stdout.write(result.stdout)
callback(error)
grunt.util.async.waterfall commands, (error) -> done(error)
grunt.registerTask 'nof', 'Un-focus all specs', ->
nof = require.resolve('.bin/nof')
spawn({cmd: nof, args: ['spec', 'src']}, @async())
grunt.loadTasks('tasks')
grunt.registerTask('compile', ['coffee', 'less', 'cson'])
grunt.registerTask('lint', ['coffeelint', 'csslint', 'lesslint'])
grunt.registerTask('ci', ['lint', 'partial-clean', 'update-atom-shell', 'build', 'test'])
grunt.registerTask('deploy', ['update-atom-shell', 'build', 'codesign'])
grunt.registerTask('deploy', ['partial-clean', 'update-atom-shell', 'build', 'codesign'])
grunt.registerTask('default', ['update-atom-shell', 'build', 'set-development-version', 'install'])
spawn = (options, callback) ->
grunt.util.spawn options, (error, results, code) ->
grunt.log.errorlns results.stderr if results.stderr
callback(error, results, code)
cp = (source, destination, {filter}={}) ->
walkdir.sync source, (sourcePath, stats) ->
return if filter?.test(sourcePath)
destinationPath = path.join(destination, path.relative(source, sourcePath))
if stats.isSymbolicLink()
grunt.file.mkdir(path.dirname(destinationPath))
fs.symlinkSync(fs.readlinkSync(sourcePath), destinationPath)
else if stats.isFile()
grunt.file.copy(sourcePath, destinationPath)
if grunt.file.exists(destinationPath)
fs.chmodSync(destinationPath, fs.statSync(sourcePath).mode)
grunt.log.writeln("Copied #{source.cyan} to #{destination.cyan}.")
mkdir = (args...) ->
grunt.file.mkdir(args...)
rm = (args...) ->
grunt.file.delete(args..., force: true) if grunt.file.exists(args...)
+1 -1
Ver Arquivo
@@ -29,7 +29,7 @@ on creating your first package.
## package.json
Similar to [npm packages](http://en.wikipedia.org/wiki/Npm_(software)), Atom packages
Similar to [npm packages](http://en.wikipedia.org/wiki/Npm_(software\)), Atom packages
can contain a _package.json_ file in their top-level directory. This file contains metadata
about the package, such as the path to its "main" module, library dependencies,
and manifests specifying the order in which its resources should be loaded.
+13 -10
Ver Arquivo
@@ -8,19 +8,19 @@
},
"dependencies": {
"coffee-script": "1.6.2",
"ctags": "0.3.0",
"ctags": "0.5.0",
"oniguruma": "0.16.0",
"mkdirp": "0.3.5",
"git-utils": "0.17.0",
"git-utils": "0.19.0",
"underscore": "1.4.4",
"d3": "3.0.8",
"coffee-cache": "0.1.0",
"pegjs": "0.7.0",
"async": "0.2.6",
"nak": "0.2.16",
"spellchecker": "0.3.0",
"pathwatcher": "0.3.0",
"keytar": "0.4.0",
"spellchecker": "0.6.0",
"pathwatcher": "0.5.0",
"keytar": "0.9.0",
"ls-archive": "0.9.0",
"temp": "0.5.0",
"rimraf": "2.1.4",
@@ -30,9 +30,12 @@
"roaster": "0.0.5",
"jqueryui-browser": "1.10.2-1",
"optimist": "0.4.0",
"season": "0.7.0",
"season": "0.10.0",
"humanize-plus": "1.1.0",
"semver": "1.1.4",
"guid": "0.0.10",
"tantamount": "0.3.0",
"coffeestack": "0.4.0",
"c-tmbundle": "1.0.0",
"coffee-script-tmbundle": "2.0.0",
"css-tmbundle": "1.0.0",
@@ -67,16 +70,16 @@
"nslog": "0.1.0"
},
"devDependencies": {
"biscotto": "0.0.11",
"biscotto": "0.0.12",
"grunt": "~0.4.1",
"grunt-cli": "~0.1.9",
"grunt-coffeelint": "0.0.6",
"grunt-lesslint": "0.7.0",
"grunt-cson": "0.3.0",
"grunt-lesslint": "0.8.0",
"grunt-cson": "0.5.0",
"grunt-contrib-csslint": "~0.1.2",
"grunt-contrib-coffee": "~0.7.0",
"grunt-contrib-less": "~0.5.2",
"jasmine-focused": "~0.6.0",
"jasmine-focused": "~0.7.0",
"walkdir": "0.0.7"
},
"private": true,
+11
Ver Arquivo
@@ -36,6 +36,17 @@
<string>speakeasy.pem</string>
<key>SUScheduledCheckInterval</key>
<string>3600</string>
<key>CFBundleURLTypes</key>
<array>
<dict>
<key>CFBundleURLSchemes</key>
<array>
<string>atom</string>
</array>
<key>CFBundleURLName</key>
<string>Atom Shared Session Protocol</string>
</dict>
</array>
<key>CFBundleDocumentTypes</key>
<array>
<dict>
+1
Ver Arquivo
@@ -7,4 +7,5 @@ cd "$(dirname "$0")/.."
rm -rf ~/.atom
git clean -dff
rm -fr node_modules
./script/test
+1
Ver Arquivo
@@ -6,6 +6,7 @@ set -ex
# xcode
cd "$(dirname "$0")/../.."
rm -fr node_modules
./script/bootstrap
./node_modules/.bin/grunt --build-dir="$BUILT_PRODUCTS_DIR" deploy
+1 -26
Ver Arquivo
@@ -3,7 +3,7 @@ RootView = require 'root-view'
{$$} = require 'space-pen'
fsUtils = require 'fs-utils'
Exec = require('child_process').exec
path = require('path')
path = require 'path'
describe "the `atom` global", ->
beforeEach ->
@@ -293,28 +293,3 @@ describe "the `atom` global", ->
describe ".getVersion", ->
it "returns the current version number", ->
expect(typeof atom.getVersion()).toBe 'string'
describe "API documentation", ->
it "meets a minimum threshold for /app (with no errors)", ->
docRunner = jasmine.createSpy("docRunner")
Exec "./node_modules/.bin/coffee ./node_modules/.bin/biscotto -- --statsOnly src/app/", cwd: project.resolve('../..'), docRunner
waitsFor ->
docRunner.callCount > 0
runs ->
# error
expect(docRunner.argsForCall[0][0]).toBeNull()
results = docRunner.argsForCall[0][1].split("\n")
results.pop()
errors = parseInt results.pop().match(/\d+/)
if errors > 0
console.error results.join('\n')
throw new Error("There were errors compiling documentation. See console for details.")
coverage = parseFloat results.pop().match(/.+?%/)
expect(coverage).toBeGreaterThan 75
# stderr
expect(docRunner.argsForCall[0][2]).toBe ''
+8
Ver Arquivo
@@ -1,6 +1,7 @@
fs = require 'fs'
fsUtils = require 'fs-utils'
path = require 'path'
CSON = require 'season'
describe "Config", ->
describe ".get(keyPath)", ->
@@ -210,6 +211,13 @@ describe "Config", ->
config.set("hair", "blonde") # trigger a save
expect(config.save).not.toHaveBeenCalled()
describe "when the config file does not exist", ->
it "creates it with an empty object", ->
fsUtils.makeTree(config.configDirPath)
config.loadUserConfig()
expect(fsUtils.exists(config.configFilePath)).toBe true
expect(CSON.readFileSync(config.configFilePath)).toEqual {}
describe ".observeUserConfig()", ->
updatedHandler = null
@@ -0,0 +1,26 @@
{createSite} = require 'telepath'
Editor = require 'editor'
describe "EditSession replication", ->
[editSession1, editSession2] = []
beforeEach ->
editSession1 = project.open('sample.js')
doc1 = editSession1.getState()
doc2 = doc1.clone(createSite(2))
doc1.connect(doc2)
editSession2 = deserialize(doc2)
it "replicates the scroll position", ->
editor1 = new Editor(editSession1)
editor2 = new Editor(editSession2)
editor1.attachToDom().width(50).height(50)
editor2.attachToDom().width(50).height(50)
editor1.scrollTop(10)
expect(editor1.scrollTop()).toBe 10
expect(editor2.scrollTop()).toBe 10
editor2.scrollLeft(20)
expect(editor2.scrollLeft()).toBe 20
expect(editor1.scrollLeft()).toBe 20
+20
Ver Arquivo
@@ -2117,6 +2117,26 @@ describe "EditSession", ->
expect(editSession.isFoldedAtScreenRow(4)).toBeTruthy()
expect(buffer.lineForRow(3)).toBe ' var pivot = items.shift(), current, left = [], right = [];'
describe ".replaceSelectedText(options, fn)", ->
describe "when no text is selected", ->
it "inserts the text returned from the function at the cursor position", ->
editSession.replaceSelectedText {}, -> '123'
expect(buffer.lineForRow(0)).toBe '123var quicksort = function () {'
editSession.replaceSelectedText {selectWordIfEmpty: true}, -> 'var'
editSession.setCursorBufferPosition([0])
expect(buffer.lineForRow(0)).toBe 'var quicksort = function () {'
editSession.setCursorBufferPosition([10])
editSession.replaceSelectedText null, -> ''
expect(buffer.lineForRow(10)).toBe ''
describe "when text is selected", ->
it "replaces the selected text with the text returned from the function", ->
editSession.setSelectedBufferRange([[0, 1], [0, 3]])
editSession.replaceSelectedText {}, -> 'ia'
expect(buffer.lineForRow(0)).toBe 'via quicksort = function () {'
describe ".transpose()", ->
it "swaps two characters", ->
editSession.buffer.setText("abc")
+6 -6
Ver Arquivo
@@ -124,7 +124,7 @@ describe "Editor", ->
previousScrollTop = editor.scrollTop()
previousScrollLeft = editor.scrollLeft()
newEditSession.scrollTop = 120
newEditSession.setScrollTop(120)
newEditSession.setSelectedBufferRange([[40, 0], [43, 1]])
editor.edit(newEditSession)
@@ -214,18 +214,18 @@ describe "Editor", ->
expect(editor.scrollTop()).toBe 50
it "sets the new scroll top position on the active edit session", ->
expect(editor.activeEditSession.scrollTop).toBe 0
expect(editor.activeEditSession.getScrollTop()).toBe 0
editor.scrollTop(123)
expect(editor.activeEditSession.scrollTop).toBe 123
expect(editor.activeEditSession.getScrollTop()).toBe 123
describe ".scrollHorizontally(pixelPosition)", ->
it "sets the new scroll left position on the active edit session", ->
editor.attachToDom(heightInLines: 5)
setEditorWidthInChars(editor, 5)
expect(editor.activeEditSession.scrollLeft).toBe 0
expect(editor.activeEditSession.getScrollLeft()).toBe 0
editor.scrollHorizontally(left: 50)
expect(editor.activeEditSession.scrollLeft).toBeGreaterThan 0
expect(editor.activeEditSession.scrollLeft).toBe editor.scrollLeft()
expect(editor.activeEditSession.getScrollLeft()).toBeGreaterThan 0
expect(editor.activeEditSession.getScrollLeft()).toBe editor.scrollLeft()
describe "editor:attached event", ->
it 'only triggers an editor:attached event when it is first added to the DOM', ->
+12
Ver Arquivo
@@ -35,10 +35,22 @@ describe "Keymap", ->
keymap.handleKeyEvent(event)
expect(event.keystrokes).toBe 'alt-meta-x'
event = keydownEvent(',', metaKey: true)
event.which = 188
keymap.handleKeyEvent(event)
expect(event.keystrokes).toBe 'meta-,'
describe "when no binding matches the event's keystroke", ->
it "does not return false so the event continues to propagate", ->
expect(keymap.handleKeyEvent(keydownEvent('0', target: fragment[0]))).not.toBe false
describe "when a non-English keyboard language is used", ->
it "uses the physical character pressed instead of the character it maps to in the current language", ->
event = keydownEvent('U+03B6', metaKey: true) # This is the 'z' key using the Greek keyboard layout
event.which = 122
keymap.handleKeyEvent(event)
expect(event.keystrokes).toBe 'meta-z'
describe "when at least one binding fully matches the event's keystroke", ->
describe "when the event's target node matches a selector with a matching binding", ->
it "triggers the command event associated with that binding on the target node and returns false", ->
@@ -0,0 +1,82 @@
{createSite} = require 'telepath'
{View} = require 'space-pen'
PaneContainer = require 'pane-container'
Pane = require 'pane'
describe "PaneContainer replication", ->
[container1, container2, pane1a, pane1b, pane1c] = []
class TestView extends View
@deserialize: ({name}) -> new TestView(name)
@content: -> @div tabindex: -1
initialize: (@name) -> @text(@name)
serialize: -> { deserializer: 'TestView', @name }
getState: -> @serialize()
getUri: -> "/tmp/#{@name}"
isEqual: (other) -> @name is other.name
beforeEach ->
registerDeserializer(TestView)
container1 = new PaneContainer
pane1a = new Pane(new TestView('A'))
container1.setRoot(pane1a)
pane1b = pane1a.splitRight(new TestView('B'))
pane1c = pane1b.splitDown(new TestView('C'))
doc1 = container1.getState()
doc2 = doc1.clone(createSite(2))
doc1.connect(doc2)
container2 = deserialize(doc2)
afterEach ->
unregisterDeserializer(TestView)
it "replicates the inital state of a pane container with splits", ->
expect(container1.find('.row > :eq(0):contains(A)')).toExist()
expect(container1.find('.row > :eq(1)')).toHaveClass 'column'
expect(container1.find('.row > :eq(1) > :eq(0):contains(B)')).toExist()
expect(container1.find('.row > :eq(1) > :eq(1):contains(C)')).toExist()
expect(container2.find('.row > :eq(0):contains(A)')).toExist()
expect(container2.find('.row > :eq(1)')).toHaveClass 'column'
expect(container2.find('.row > :eq(1) > :eq(0):contains(B)')).toExist()
expect(container2.find('.row > :eq(1) > :eq(1):contains(C)')).toExist()
it "replicates the splitting of panes", ->
container1.attachToDom().width(400).height(200)
container2.attachToDom().width(400).height(200)
pane1d = pane1a.splitRight(new TestView('D'))
expect(container1.find('.row > :eq(1):contains(D)')).toExist()
expect(container2.find('.row > :eq(1):contains(D)')).toExist()
expect(container2.find('.row > :eq(1):contains(D)').outerWidth()).toBe container1.find('.row > :eq(1):contains(D)').outerWidth()
pane1d.splitDown(new TestView('E'))
expect(container1.find('.row > :eq(1)')).toHaveClass('column')
expect(container1.find('.row > :eq(1) > :eq(0):contains(D)')).toExist()
expect(container1.find('.row > :eq(1) > :eq(1):contains(E)')).toExist()
expect(container2.find('.row > :eq(1)')).toHaveClass('column')
expect(container2.find('.row > :eq(1) > :eq(0):contains(D)')).toExist()
expect(container2.find('.row > :eq(1) > :eq(1):contains(E)')).toExist()
it "replicates removal of panes", ->
pane1c.remove()
expect(container1.find('.row > :eq(0):contains(A)')).toExist()
expect(container1.find('.row > :eq(1):contains(B)')).toExist()
expect(container2.find('.row > :eq(0):contains(A)')).toExist()
expect(container2.find('.row > :eq(1):contains(B)')).toExist()
pane1b.remove()
expect(container1.find('> :eq(0):contains(A)')).toExist()
expect(container2.find('> :eq(0):contains(A)')).toExist()
pane1a.remove()
expect(container1.children()).not.toExist()
expect(container2.children()).not.toExist()
+12 -26
Ver Arquivo
@@ -20,7 +20,7 @@ describe "PaneContainer", ->
container = new PaneContainer
pane1 = new Pane(new TestView('1'))
container.append(pane1)
container.setRoot(pane1)
pane2 = pane1.splitRight(new TestView('2'))
pane3 = pane2.splitDown(new TestView('3'))
@@ -151,41 +151,27 @@ describe "PaneContainer", ->
expect(item.saved).toBeTruthy()
describe ".confirmClose()", ->
it "resolves the returned promise after modified files are saved", ->
it "returns true after modified files are saved", ->
pane1.itemAtIndex(0).isModified = -> true
pane2.itemAtIndex(0).isModified = -> true
spyOn(atom, "confirm").andCallFake (a, b, c, d, e, f, g, noSaveFn) -> noSaveFn()
spyOn(atom, "confirmSync").andReturn(0)
promiseHandler = jasmine.createSpy("promiseHandler")
failedPromiseHandler = jasmine.createSpy("failedPromiseHandler")
promise = container.confirmClose()
promise.done promiseHandler
promise.fail failedPromiseHandler
waitsFor ->
promiseHandler.wasCalled
saved = container.confirmClose()
runs ->
expect(failedPromiseHandler).not.toHaveBeenCalled()
expect(atom.confirm).toHaveBeenCalled()
expect(saved).toBeTruthy()
expect(atom.confirmSync).toHaveBeenCalled()
it "rejects the returned promise if the user cancels saving", ->
it "returns false if the user cancels saving", ->
pane1.itemAtIndex(0).isModified = -> true
pane2.itemAtIndex(0).isModified = -> true
spyOn(atom, "confirm").andCallFake (a, b, c, d, e, cancelFn, f, g) -> cancelFn()
spyOn(atom, "confirmSync").andReturn(1)
promiseHandler = jasmine.createSpy("promiseHandler")
failedPromiseHandler = jasmine.createSpy("failedPromiseHandler")
promise = container.confirmClose()
promise.done promiseHandler
promise.fail failedPromiseHandler
waitsFor ->
failedPromiseHandler.wasCalled
saved = container.confirmClose()
runs ->
expect(promiseHandler).not.toHaveBeenCalled()
expect(atom.confirm).toHaveBeenCalled()
expect(saved).toBeFalsy()
expect(atom.confirmSync).toHaveBeenCalled()
describe "serialization", ->
it "can be serialized and deserialized, and correctly adjusts dimensions of deserialized panes after attach", ->
@@ -198,7 +184,7 @@ describe "PaneContainer", ->
expect(newContainer.find('.row > :contains(1)').width()).toBe 150
expect(newContainer.find('.row > .column > :contains(2)').height()).toBe 100
it "removes empty panes on deserialization", ->
xit "removes empty panes on deserialization", ->
# only deserialize pane 1's view successfully
TestView.deserialize = ({name}) -> new TestView(name) if name is '1'
newContainer = deserialize(container.serialize())
+40
Ver Arquivo
@@ -0,0 +1,40 @@
PaneContainer = require 'pane-container'
Pane = require 'pane'
{createSite} = require 'telepath'
describe "Pane replication", ->
[editSession1a, editSession1b, container1, pane1, doc1] = []
[editSession2a, editSession2b, container2, pane2, doc2] = []
beforeEach ->
editSession1a = project.open('sample.js')
editSession1b = project.open('sample.txt')
container1 = new PaneContainer
pane1 = new Pane(editSession1a, editSession1b)
container1.setRoot(pane1)
doc1 = container1.getState()
doc2 = doc1.clone(createSite(2))
doc1.connect(doc2)
container2 = deserialize(doc2)
pane2 = container2.getRoot()
it "replicates the initial state of the panes", ->
expect(pane2.items).toEqual(pane1.items)
it "replicates addition and removal of pane items", ->
pane1.addItem(project.open('css.css'), 1)
expect(pane2.items).toEqual(pane1.items)
pane1.removeItemAtIndex(2)
expect(pane2.items).toEqual(pane1.items)
it "replicates the movement of pane items", ->
pane1.moveItem(editSession1a, 1)
expect(pane2.items).toEqual(pane1.items)
it "replicates which pane item is active", ->
pane1.showNextItem()
expect(pane2.activeItem).toEqual pane1.activeItem
pane1.showNextItem()
expect(pane2.activeItem).toEqual pane1.activeItem
+83 -48
Ver Arquivo
@@ -1,19 +1,31 @@
PaneContainer = require 'pane-container'
Pane = require 'pane'
{$$} = require 'space-pen'
{View} = require 'space-pen'
$ = require 'jquery'
describe "Pane", ->
[container, view1, view2, editSession1, editSession2, pane] = []
class TestView extends View
@deserialize: ({id, text}) -> new TestView({id, text})
@content: ({id, text}) -> @div class: 'test-view', id: id, tabindex: -1, text
initialize: ({@id, @text}) ->
serialize: -> { deserializer: 'TestView', @id, @text }
getUri: -> @id
isEqual: (other) -> @id == other.id and @text == other.text
beforeEach ->
registerDeserializer(TestView)
container = new PaneContainer
view1 = $$ -> @div id: 'view-1', tabindex: -1, 'View 1'
view2 = $$ -> @div id: 'view-2', tabindex: -1, 'View 2'
view1 = new TestView(id: 'view-1', text: 'View 1')
view2 = new TestView(id: 'view-2', text: 'View 2')
editSession1 = project.open('sample.js')
editSession2 = project.open('sample.txt')
pane = new Pane(view1, editSession1, view2, editSession2)
container.append(pane)
container.setRoot(pane)
afterEach ->
unregisterDeserializer(TestView)
describe ".initialize(items...)", ->
it "displays the first item in the pane", ->
@@ -56,7 +68,7 @@ describe "Pane", ->
describe "when the given item isn't yet in the items list on the pane", ->
view3 = null
beforeEach ->
view3 = $$ -> @div id: 'view-3', "View 3"
view3 = new TestView(id: 'view-3', text: "View 3")
pane.showItem(editSession1)
expect(pane.getActiveItemIndex()).toBe 1
@@ -82,13 +94,43 @@ describe "Pane", ->
expect(editor.activeEditSession).toBe editSession1
describe "when a valid view has already been appended for another item", ->
it "recycles the existing view by assigning the selected item to it", ->
pane.showItem(editSession1)
pane.showItem(editSession2)
expect(pane.itemViews.find('.editor').length).toBe 1
editor = pane.activeView
expect(editor.css('display')).toBe ''
expect(editor.activeEditSession).toBe editSession2
describe "when the view has a setModel method", ->
it "recycles the existing view by assigning the selected item to it", ->
pane.showItem(editSession1)
pane.showItem(editSession2)
expect(pane.itemViews.find('.editor').length).toBe 1
editor = pane.activeView
expect(editor.css('display')).toBe ''
expect(editor.activeEditSession).toBe editSession2
describe "when the view does not have a setModel method", ->
it "creates a new view with the item", ->
initialViewCount = pane.itemViews.find('.test-view').length
model1 =
id: 'test-model-1'
text: 'Test Model 1'
serialize: -> {@id, @text}
getViewClass: -> TestView
model2 =
id: 'test-model-2'
text: 'Test Model 2'
serialize: -> {@id, @text}
getViewClass: -> TestView
pane.showItem(model1)
pane.showItem(model2)
expect(pane.itemViews.find('.test-view').length).toBe initialViewCount + 2
pane.showPreviousItem()
expect(pane.itemViews.find('.test-view').length).toBe initialViewCount + 2
pane.removeItem(model2)
expect(pane.itemViews.find('.test-view').length).toBe initialViewCount + 1
pane.removeItem(model1)
expect(pane.itemViews.find('.test-view').length).toBe initialViewCount
describe "when showing a view item", ->
it "appends it to the itemViews div if it hasn't already been appended and shows it", ->
@@ -106,28 +148,17 @@ describe "Pane", ->
describe "if the item is modified", ->
beforeEach ->
spyOn(atom, 'confirm')
spyOn(atom, 'showSaveDialog')
spyOn(editSession2, 'save')
spyOn(editSession2, 'saveAs')
atom.confirm.selectOption = (buttonText) ->
for arg, i in @argsForCall[0] when arg is buttonText
@argsForCall[0][i + 1]?()
editSession2.insertText('a')
expect(editSession2.isModified()).toBeTruthy()
pane.destroyItem(editSession2)
it "presents a dialog with the option to save the item first", ->
expect(atom.confirm).toHaveBeenCalled()
expect(pane.getItems().indexOf(editSession2)).not.toBe -1
expect(editSession2.destroyed).toBeFalsy()
describe "if the [Save] option is selected", ->
describe "when the item has a uri", ->
it "saves the item before removing and destroying it", ->
atom.confirm.selectOption('Save')
spyOn(atom, 'confirmSync').andReturn(0)
pane.destroyItem(editSession2)
expect(editSession2.save).toHaveBeenCalled()
expect(pane.getItems().indexOf(editSession2)).toBe -1
@@ -137,11 +168,11 @@ describe "Pane", ->
it "presents a save-as dialog, then saves the item with the given uri before removing and destroying it", ->
editSession2.buffer.setPath(undefined)
atom.confirm.selectOption('Save')
spyOn(atom, 'showSaveDialogSync').andReturn("/selected/path")
spyOn(atom, 'confirmSync').andReturn(0)
pane.destroyItem(editSession2)
expect(atom.showSaveDialog).toHaveBeenCalled()
atom.showSaveDialog.argsForCall[0][0]("/selected/path")
expect(atom.showSaveDialogSync).toHaveBeenCalled()
expect(editSession2.saveAs).toHaveBeenCalledWith("/selected/path")
expect(pane.getItems().indexOf(editSession2)).toBe -1
@@ -149,7 +180,8 @@ describe "Pane", ->
describe "if the [Don't Save] option is selected", ->
it "removes and destroys the item without saving it", ->
atom.confirm.selectOption("Don't Save")
spyOn(atom, 'confirmSync').andReturn(2)
pane.destroyItem(editSession2)
expect(editSession2.save).not.toHaveBeenCalled()
expect(pane.getItems().indexOf(editSession2)).toBe -1
@@ -157,7 +189,8 @@ describe "Pane", ->
describe "if the [Cancel] option is selected", ->
it "does not save, remove, or destroy the item", ->
atom.confirm.selectOption("Cancel")
spyOn(atom, 'confirmSync').andReturn(1)
pane.destroyItem(editSession2)
expect(editSession2.save).not.toHaveBeenCalled()
expect(pane.getItems().indexOf(editSession2)).not.toBe -1
@@ -188,8 +221,9 @@ describe "Pane", ->
describe "when the pane is focused", ->
it "shifts focus to the next pane", ->
expect(container.getRoot()).toBe pane
container.attachToDom()
pane2 = pane.splitRight($$ -> @div class: 'view-3', tabindex: -1, 'View 3')
pane2 = pane.splitRight(new TestView(id: 'view-3', text: 'View 3'))
pane.focus()
expect(pane).toMatchSelector(':has(:focus)')
pane.removeItem(item) for item in pane.getItems()
@@ -236,7 +270,7 @@ describe "Pane", ->
[pane2, view3] = []
beforeEach ->
view3 = $$ -> @div id: 'view-3', "View 3"
view3 = new TestView(id: 'view-3', text: "View 3")
pane2 = pane.splitRight(view3)
it "moves the item to the given pane at the given index", ->
@@ -309,7 +343,7 @@ describe "Pane", ->
describe "when the current item has no uri", ->
beforeEach ->
spyOn(atom, 'showSaveDialog')
spyOn(atom, 'showSaveDialogSync').andReturn('/selected/path')
describe "when the current item has a saveAs method", ->
it "opens a save dialog and saves the current item as the selected path", ->
@@ -319,19 +353,18 @@ describe "Pane", ->
pane.trigger 'core:save'
expect(atom.showSaveDialog).toHaveBeenCalled()
atom.showSaveDialog.argsForCall[0][0]('/selected/path')
expect(atom.showSaveDialogSync).toHaveBeenCalled()
expect(editSession2.saveAs).toHaveBeenCalledWith('/selected/path')
describe "when the current item has no saveAs method", ->
it "does nothing", ->
expect(pane.activeItem.saveAs).toBeUndefined()
pane.trigger 'core:save'
expect(atom.showSaveDialog).not.toHaveBeenCalled()
expect(atom.showSaveDialogSync).not.toHaveBeenCalled()
describe "core:save-as", ->
beforeEach ->
spyOn(atom, 'showSaveDialog')
spyOn(atom, 'showSaveDialogSync').andReturn('/selected/path')
describe "when the current item has a saveAs method", ->
it "opens the save dialog and calls saveAs on the item with the selected path", ->
@@ -340,15 +373,14 @@ describe "Pane", ->
pane.trigger 'core:save-as'
expect(atom.showSaveDialog).toHaveBeenCalled()
atom.showSaveDialog.argsForCall[0][0]('/selected/path')
expect(atom.showSaveDialogSync).toHaveBeenCalled()
expect(editSession2.saveAs).toHaveBeenCalledWith('/selected/path')
describe "when the current item does not have a saveAs method", ->
it "does nothing", ->
expect(pane.activeItem.saveAs).toBeUndefined()
pane.trigger 'core:save-as'
expect(atom.showSaveDialog).not.toHaveBeenCalled()
expect(atom.showSaveDialogSync).not.toHaveBeenCalled()
describe "pane:show-next-item and pane:show-previous-item", ->
it "advances forward/backward through the pane's items, looping around at either end", ->
@@ -489,8 +521,8 @@ describe "Pane", ->
beforeEach ->
pane1 = pane
pane.showItem(editSession1)
view3 = $$ -> @div id: 'view-3', 'View 3'
view4 = $$ -> @div id: 'view-4', 'View 4'
view3 = new TestView(id: 'view-3', text: 'View 3')
view4 = new TestView(id: 'view-4', text: 'View 4')
describe "splitRight(items...)", ->
it "builds a row if needed, then appends a new pane after itself", ->
@@ -677,18 +709,21 @@ describe "Pane", ->
expect(pane.itemForUri(editSession2.getUri())).toBe editSession2
describe "serialization", ->
it "can serialize and deserialize the pane and all its serializable items", ->
it "can serialize and deserialize the pane and all its items", ->
newPane = deserialize(pane.serialize())
expect(newPane.getItems()).toEqual [editSession1, editSession2]
expect(newPane.getItems()).toEqual [view1, editSession1, view2, editSession2]
it "restores the active item on deserialization if it serializable", ->
it "restores the active item on deserialization", ->
pane.showItem(editSession2)
newPane = deserialize(pane.serialize())
expect(newPane.activeItem).toEqual editSession2
it "defaults to the first item on deserialization if the active item was not serializable", ->
xit "defaults to the first item on deserialization if the active item was not serializable", ->
expect(view2.serialize?()).toBeFalsy()
pane.showItem(view2)
console.log pane.serialize().toObject()
newPane = deserialize(pane.serialize())
expect(newPane.activeItem).toEqual editSession1
@@ -699,7 +734,7 @@ describe "Pane", ->
state = pane.serialize()
pane.remove()
newPane = deserialize(state)
container.append(newPane)
container.setRoot(newPane)
expect(newPane).toMatchSelector(':has(:focus)')
$(document.activeElement).blur()
+48 -49
Ver Arquivo
@@ -39,64 +39,63 @@ describe "RootView", ->
expect(rootView.getActiveView().getText()).toBe buffer.getText()
expect(rootView.title).toBe "untitled - #{project.getPath()}"
describe "when the serialized RootView has a project", ->
describe "when there are open editors", ->
it "constructs the view with the same panes", ->
rootView.attachToDom()
pane1 = rootView.getActivePane()
pane2 = pane1.splitRight()
pane3 = pane2.splitRight()
pane4 = pane2.splitDown()
pane2.showItem(project.open('b'))
pane3.showItem(project.open('../sample.js'))
pane3.activeItem.setCursorScreenPosition([2, 4])
pane4.showItem(project.open('../sample.txt'))
pane4.activeItem.setCursorScreenPosition([0, 2])
pane2.focus()
describe "when there are open editors", ->
it "constructs the view with the same panes", ->
rootView.attachToDom()
pane1 = rootView.getActivePane()
pane2 = pane1.splitRight()
pane3 = pane2.splitRight()
pane4 = pane2.splitDown()
pane2.showItem(project.open('b'))
pane3.showItem(project.open('../sample.js'))
pane3.activeItem.setCursorScreenPosition([2, 4])
pane4.showItem(project.open('../sample.txt'))
pane4.activeItem.setCursorScreenPosition([0, 2])
pane2.focus()
viewState = rootView.serialize()
rootView.remove()
window.rootView = deserialize(viewState)
rootView.attachToDom()
viewState = rootView.serialize()
rootView.remove()
window.rootView = deserialize(viewState)
rootView.attachToDom()
expect(rootView.getEditors().length).toBe 4
editor1 = rootView.panes.find('.row > .pane .editor:eq(0)').view()
editor3 = rootView.panes.find('.row > .pane .editor:eq(1)').view()
editor2 = rootView.panes.find('.row > .column > .pane .editor:eq(0)').view()
editor4 = rootView.panes.find('.row > .column > .pane .editor:eq(1)').view()
expect(rootView.getEditors().length).toBe 4
editor1 = rootView.panes.find('.row > .pane .editor:eq(0)').view()
editor3 = rootView.panes.find('.row > .pane .editor:eq(1)').view()
editor2 = rootView.panes.find('.row > .column > .pane .editor:eq(0)').view()
editor4 = rootView.panes.find('.row > .column > .pane .editor:eq(1)').view()
expect(editor1.getPath()).toBe project.resolve('a')
expect(editor2.getPath()).toBe project.resolve('b')
expect(editor3.getPath()).toBe project.resolve('../sample.js')
expect(editor3.getCursorScreenPosition()).toEqual [2, 4]
expect(editor4.getPath()).toBe project.resolve('../sample.txt')
expect(editor4.getCursorScreenPosition()).toEqual [0, 2]
expect(editor1.getPath()).toBe project.resolve('a')
expect(editor2.getPath()).toBe project.resolve('b')
expect(editor3.getPath()).toBe project.resolve('../sample.js')
expect(editor3.getCursorScreenPosition()).toEqual [2, 4]
expect(editor4.getPath()).toBe project.resolve('../sample.txt')
expect(editor4.getCursorScreenPosition()).toEqual [0, 2]
# ensure adjust pane dimensions is called
expect(editor1.width()).toBeGreaterThan 0
expect(editor2.width()).toBeGreaterThan 0
expect(editor3.width()).toBeGreaterThan 0
expect(editor4.width()).toBeGreaterThan 0
# ensure adjust pane dimensions is called
expect(editor1.width()).toBeGreaterThan 0
expect(editor2.width()).toBeGreaterThan 0
expect(editor3.width()).toBeGreaterThan 0
expect(editor4.width()).toBeGreaterThan 0
# ensure correct editor is focused again
expect(editor2.isFocused).toBeTruthy()
expect(editor1.isFocused).toBeFalsy()
expect(editor3.isFocused).toBeFalsy()
expect(editor4.isFocused).toBeFalsy()
# ensure correct editor is focused again
expect(editor2.isFocused).toBeTruthy()
expect(editor1.isFocused).toBeFalsy()
expect(editor3.isFocused).toBeFalsy()
expect(editor4.isFocused).toBeFalsy()
expect(rootView.title).toBe "#{path.basename(editor2.getPath())} - #{project.getPath()}"
expect(rootView.title).toBe "#{path.basename(editor2.getPath())} - #{project.getPath()}"
describe "where there are no open editors", ->
it "constructs the view with no open editors", ->
rootView.getActivePane().remove()
expect(rootView.getEditors().length).toBe 0
describe "where there are no open editors", ->
it "constructs the view with no open editors", ->
rootView.getActivePane().remove()
expect(rootView.getEditors().length).toBe 0
viewState = rootView.serialize()
rootView.remove()
window.rootView = deserialize(viewState)
viewState = rootView.serialize()
rootView.remove()
window.rootView = deserialize(viewState)
rootView.attachToDom()
expect(rootView.getEditors().length).toBe 0
rootView.attachToDom()
expect(rootView.getEditors().length).toBe 0
describe "focus", ->
describe "when there is an active view", ->
+6
Ver Arquivo
@@ -75,6 +75,12 @@ describe "the `syntax` global", ->
expect(syntax.selectGrammar('more.test', '')).toBe grammar1
describe "when there is no file path", ->
it "does not throw an exception (regression)", ->
expect(-> syntax.selectGrammar(null, '#!/usr/bin/ruby')).not.toThrow()
expect(-> syntax.selectGrammar(null, '')).not.toThrow()
expect(-> syntax.selectGrammar(null, null)).not.toThrow()
describe ".removeGrammar(grammar)", ->
it "removes the grammar, so it won't be returned by selectGrammar", ->
grammar = syntax.selectGrammar('foo.js')
+33 -24
Ver Arquivo
@@ -38,30 +38,43 @@ describe "Window", ->
expect($("body")).not.toHaveClass("is-blurred")
describe "window:close event", ->
describe "when no pane items are modified", ->
it "calls window.closeWithoutConfirm", ->
spyOn window, 'closeWithoutConfirm'
$(window).trigger 'window:close'
expect(window.closeWithoutConfirm).toHaveBeenCalled()
it "closes the window", ->
spyOn(window, 'close')
$(window).trigger 'window:close'
expect(window.close).toHaveBeenCalled()
it "emits the beforeunload event", ->
$(window).off 'beforeunload'
beforeunload = jasmine.createSpy('beforeunload').andReturn(false)
$(window).on 'beforeunload', beforeunload
$(window).trigger 'window:close'
expect(beforeunload).toHaveBeenCalled()
describe "beforeunload event", ->
describe "when pane items are are modified", ->
it "prompts user to save and and calls window.closeWithoutConfirm", ->
spyOn(window, 'closeWithoutConfirm')
spyOn(atom, "confirm").andCallFake (a, b, c, d, e, f, g, noSave) -> noSave()
it "prompts user to save and and calls rootView.confirmClose", ->
spyOn(rootView, 'confirmClose').andCallThrough()
spyOn(atom, "confirmSync").andReturn(2)
editSession = rootView.open("sample.js")
editSession.insertText("I look different, I feel different.")
$(window).trigger 'window:close'
expect(window.closeWithoutConfirm).toHaveBeenCalled()
expect(atom.confirm).toHaveBeenCalled()
$(window).trigger 'beforeunload'
expect(rootView.confirmClose).toHaveBeenCalled()
expect(atom.confirmSync).toHaveBeenCalled()
it "prompts user to save and aborts if dialog is canceled", ->
spyOn(window, 'closeWithoutConfirm')
spyOn(atom, "confirm").andCallFake (a, b, c, d, e, cancel) -> cancel()
it "prompts user to save and handler returns true if don't save", ->
spyOn(atom, "confirmSync").andReturn(2)
editSession = rootView.open("sample.js")
editSession.insertText("I look different, I feel different.")
$(window).trigger 'window:close'
expect(window.closeWithoutConfirm).not.toHaveBeenCalled()
expect(atom.confirm).toHaveBeenCalled()
expect(window.onbeforeunload(new Event('beforeunload'))).toBeTruthy()
expect(atom.confirmSync).toHaveBeenCalled()
it "prompts user to save and handler returns false if dialog is canceled", ->
spyOn(atom, "confirmSync").andReturn(1)
editSession = rootView.open("sample.js")
editSession.insertText("I look different, I feel different.")
expect(window.onbeforeunload(new Event('beforeunload'))).toBeFalsy()
expect(atom.confirmSync).toHaveBeenCalled()
describe "requireStylesheet(path)", ->
it "synchronously loads css at the given path and installs a style tag for it in the head", ->
@@ -125,18 +138,14 @@ describe "Window", ->
describe ".unloadEditorWindow()", ->
it "saves the serialized state of the window so it can be deserialized after reload", ->
windowState = {}
jasmine.unspy(atom, 'setWindowState')
spyOn(atom, 'setWindowState').andCallFake (key, value) -> windowState[key] = value
# JSON.stringify removes keys with undefined values
rootViewState = rootView.serialize()
syntaxState = syntax.serialize()
window.unloadEditorWindow()
expect(windowState.rootView).toEqual rootViewState
expect(windowState.syntax).toEqual syntaxState
expect(atom.getWindowState().getObject('rootView')).toEqual rootViewState.toObject()
expect(atom.getWindowState().getObject('syntax')).toEqual syntaxState
expect(atom.saveWindowState).toHaveBeenCalled()
it "unsubscribes from all buffers", ->
rootView.open('sample.js')
+17 -2
Ver Arquivo
@@ -1,6 +1,19 @@
$ = require 'jquery'
{View, $$} = require 'space-pen'
_ = require 'underscore'
{convertStackTrace} = require 'coffeestack'
sourceMaps = {}
formatStackTrace = (stackTrace) ->
return stackTrace unless stackTrace
jasminePath = require.resolve('jasmine')
jasminePattern = new RegExp("\\(#{_.escapeRegExp(jasminePath)}:\\d+:\\d+\\)\\s*$")
convertedLines = []
for line in stackTrace.split('\n')
convertedLines.push(line) unless jasminePattern.test(line)
convertStackTrace(convertedLines.join('\n'), sourceMaps)
module.exports =
class AtomReporter extends View
@@ -42,6 +55,7 @@ class AtomReporter extends View
reportSpecResults: (spec) ->
@completeSpecCount++
spec.endedAt = new Date().getTime()
@specComplete(spec)
@updateStatusView(spec)
@@ -99,7 +113,7 @@ class AtomReporter extends View
rootSuite = rootSuite.parentSuite while rootSuite.parentSuite
@message.text rootSuite.description
time = "#{Math.round((new Date().getTime() - @startedAt.getTime()) / 10)}"
time = "#{Math.round((spec.endedAt - @startedAt.getTime()) / 10)}"
time = "0#{time}" if time.length < 3
@time.text "#{time[0...-2]}.#{time[-2..]}s"
@@ -166,9 +180,10 @@ class SpecResultView extends View
@description.html @spec.description
for result in @spec.results().getItems() when not result.passed()
stackTrace = formatStackTrace(result.trace.stack)
@specFailures.append $$ ->
@div result.message, class: 'resultMessage fail'
@div result.trace.stack, class: 'stackTrace' if result.trace.stack
@div stackTrace, class: 'stackTrace' if stackTrace
attach: ->
@parentSuiteView().append this
-30
Ver Arquivo
@@ -1,30 +0,0 @@
setGlobalFocusPriority = (priority) ->
env = jasmine.getEnv()
env.focusPriority = 1 unless env.focusPriority
env.focusPriority = priority if priority > env.focusPriority
window.fdescribe = (description, specDefinitions, priority) ->
priority = 1 unless priority
setGlobalFocusPriority(priority)
suite = describe(description, specDefinitions)
suite.focusPriority = priority
suite
window.ffdescribe = (description, specDefinitions) ->
fdescribe(description, specDefinitions, 2)
window.fffdescribe = (description, specDefinitions) ->
fdescribe(description, specDefinitions, 3)
window.fit = (description, definition, priority) ->
priority = 1 unless priority
setGlobalFocusPriority(priority)
spec = it(description, definition)
spec.focusPriority = priority
spec
window.ffit = (description, specDefinitions) ->
fit(description, specDefinitions, 2)
window.fffit = (description, specDefinitions) ->
fit(description, specDefinitions, 3)
+9 -5
Ver Arquivo
@@ -1,5 +1,5 @@
require 'window'
window.setUpEnvironment()
window.setUpEnvironment('spec')
window.restoreDimensions()
nakedLoad 'jasmine-jquery'
@@ -25,6 +25,9 @@ keymap.loadBundledKeymaps()
[bindingSetsToRestore, bindingSetsByFirstKeystrokeToRestore] = []
$(window).on 'core:close', -> window.close()
$(window).on 'unload', ->
atom.windowMode = 'spec'
atom.saveWindowState()
$('html,body').css('overflow', 'auto')
jasmine.getEnv().addEqualityTester(_.isEqual) # Use underscore's definition of equality for toEqual assertions
@@ -41,7 +44,7 @@ beforeEach ->
window.resetTimeouts()
atom.windowMode = 'editor'
atom.packageStates = {}
spyOn(atom, 'setWindowState')
spyOn(atom, 'saveWindowState')
syntax.clearGrammarOverrides()
syntax.clearProperties()
@@ -89,8 +92,9 @@ afterEach ->
if git?
git.destroy()
window.git = null
$('#jasmine-content').empty()
jasmine.unspy(atom, 'setWindowState')
$('#jasmine-content').empty() unless window.debugContent
delete atom.windowState
jasmine.unspy(atom, 'saveWindowState')
ensureNoPathSubscriptions()
syntax.off()
waits(0) # yield to ui thread to make screen update more frequently
@@ -230,7 +234,7 @@ $.fn.enableKeymap = ->
@on 'keydown', (e) => window.keymap.handleKeyEvent(e)
$.fn.attachToDom = ->
$('#jasmine-content').append(this)
@appendTo($('#jasmine-content'))
$.fn.simulateDomAttachment = ->
$('<html>').append(this)
+9 -2
Ver Arquivo
@@ -1,4 +1,5 @@
fsUtils = require 'fs-utils'
fs = require 'fs'
path = require 'path'
describe "fsUtils", ->
@@ -100,7 +101,7 @@ describe "fsUtils", ->
paths = fsUtils.listSync(project.getPath(), ['.css', 'coffee'])
expect(paths).toContain project.resolve('css.css')
expect(paths).toContain project.resolve('coffee.coffee')
expect(path).toMatch /(css|coffee)$/ for path in paths
expect(listedPath).toMatch /(css|coffee)$/ for listedPath in paths
describe ".list(path, [extensions,] callback)", ->
paths = null
@@ -123,4 +124,10 @@ describe "fsUtils", ->
runs ->
expect(paths).toContain project.resolve('css.css')
expect(paths).toContain project.resolve('coffee.coffee')
expect(path).toMatch /(css|coffee)$/ for path in paths
expect(listedPath).toMatch /(css|coffee)$/ for listedPath in paths
describe ".absolute(relativePath)", ->
it "converts a leading ~ segment to the HOME directory", ->
expect(fsUtils.absolute('~')).toBe fs.realpathSync(process.env.HOME)
expect(fsUtils.absolute(path.join('~', 'does', 'not', 'exist'))).toBe path.join(process.env.HOME, 'does', 'not', 'exist')
expect(fsUtils.absolute('~test')).toBe '~test'
+32 -20
Ver Arquivo
@@ -7,6 +7,8 @@ ipc = require 'ipc'
remote = require 'remote'
crypto = require 'crypto'
path = require 'path'
dialog = remote.require 'dialog'
telepath = require 'telepath'
window.atom =
loadedThemes: []
@@ -173,6 +175,9 @@ window.atom =
openConfig: ->
ipc.sendChannel('open-config')
openWindow: (windowSettings) ->
ipc.sendChannel('open-window', windowSettings)
confirm: (message, detailedMessage, buttonLabelsAndCallbacks...) ->
buttons = []
callbacks = []
@@ -181,18 +186,22 @@ window.atom =
buttons.push buttonLabelsAndCallbacks.shift()
callbacks.push buttonLabelsAndCallbacks.shift()
chosen = remote.require('dialog').showMessageBox
chosen = @confirmSync(message, detailedMessage, buttons)
callbacks[chosen]?()
confirmSync: (message, detailedMessage, buttons, browserWindow = null) ->
dialog.showMessageBox browserWindow,
type: 'info'
message: message
detail: detailedMessage
buttons: buttons
callbacks[chosen]?()
showSaveDialog: (callback) ->
callback(showSaveDialogSync())
showSaveDialogSync: ->
currentWindow = remote.getCurrentWindow()
result = remote.require('dialog').showSaveDialog currentWindow, title: 'Save File'
callback(result)
dialog.showSaveDialog currentWindow, title: 'Save File'
openDevTools: ->
remote.getCurrentWindow().openDevTools()
@@ -227,8 +236,8 @@ window.atom =
getWindowStatePath: ->
switch @windowMode
when 'config'
filename = 'config'
when 'config', 'spec'
filename = @windowMode
when 'editor'
{initialPath} = @getLoadSettings()
if initialPath
@@ -240,20 +249,12 @@ window.atom =
else
null
saveWindowState: (windowState) ->
windowStateJson = JSON.stringify(windowState)
if windowStatePath = @getWindowStatePath()
fsUtils.writeSync(windowStatePath, windowStateJson)
else
@getLoadSettings().windowState = windowStateJson
setWindowState: (keyPath, value) ->
windowState = @getWindowState()
_.setValueForKeyPath(windowState, keyPath, value)
@saveWindowState(windowState)
windowState.set(keyPath, value)
windowState
getWindowState: (keyPath) ->
loadWindowState: ->
if windowStatePath = @getWindowStatePath()
if fsUtils.exists(windowStatePath)
try
@@ -269,10 +270,21 @@ window.atom =
console.warn "Error parsing window state: #{windowStatePath}", error.stack, error
windowState ?= {}
if keyPath
_.valueForKeyPath(windowState, keyPath)
telepath.Document.create(windowState, site: telepath.createSite(1))
saveWindowState: ->
windowStateJson = JSON.stringify(@getWindowState().toObject())
if windowStatePath = @getWindowStatePath()
fsUtils.writeSync(windowStatePath, windowStateJson)
else
windowState
@getLoadSettings().windowState = windowStateJson
getWindowState: (keyPath) ->
@windowState ?= @loadWindowState()
if keyPath
@windowState.get(keyPath)
else
@windowState
update: ->
ipc.sendChannel 'install-update'
+13 -10
Ver Arquivo
@@ -66,16 +66,19 @@ class Config
@observeUserConfig()
loadUserConfig: ->
if fsUtils.exists(@configFilePath)
try
userConfig = CSON.readFileSync(@configFilePath)
_.extend(@settings, userConfig)
@configFileHasErrors = false
@trigger 'updated'
catch e
@configFileHasErrors = true
console.error "Failed to load user config '#{@configFilePath}'", e.message
console.error e.stack
if !fsUtils.exists(@configFilePath)
fsUtils.makeTree(path.dirname(@configFilePath))
CSON.writeFileSync(@configFilePath, {})
try
userConfig = CSON.readFileSync(@configFilePath)
_.extend(@settings, userConfig)
@configFileHasErrors = false
@trigger 'updated'
catch e
@configFileHasErrors = true
console.error "Failed to load user config '#{@configFilePath}'", e.message
console.error e.stack
observeUserConfig: ->
@watchSubscription ?= pathWatcher.watch @configFilePath, (eventType) =>
+57 -33
Ver Arquivo
@@ -1,3 +1,7 @@
_ = require 'underscore'
fsUtils = require 'fs-utils'
path = require 'path'
telepath = require 'telepath'
Point = require 'point'
Buffer = require 'text-buffer'
LanguageMode = require 'language-mode'
@@ -7,14 +11,13 @@ Selection = require 'selection'
EventEmitter = require 'event-emitter'
Subscriber = require 'subscriber'
Range = require 'range'
_ = require 'underscore'
fsUtils = require 'fs-utils'
path = require 'path'
TextMateScopeSelector = require 'text-mate-scope-selector'
# An `EditSession` manages the states between {Editor}s, {Buffer}s, and the project as a whole.
module.exports =
class EditSession
@acceptsDocuments: true
registerDeserializer(this)
### Internal ###
@@ -22,17 +25,8 @@ class EditSession
@version: 1
@deserialize: (state) ->
session = project.buildEditSessionForBuffer(Buffer.deserialize(state.buffer))
if !session?
console.warn "Could not build edit session for path '#{state.buffer}' because that file no longer exists" if state.buffer
session = project.open(null)
session.setScrollTop(state.scrollTop)
session.setScrollLeft(state.scrollLeft)
session.setCursorScreenPosition(state.cursorScreenPosition)
session
new EditSession(state)
scrollTop: 0
scrollLeft: 0
languageMode: null
displayBuffer: null
cursors: null
@@ -40,17 +34,34 @@ class EditSession
softTabs: true
softWrap: false
constructor: ({@project, @buffer, tabLength, softTabs, @softWrap}) ->
constructor: (optionsOrState) ->
if optionsOrState instanceof telepath.Document
project.editSessions.push(this)
@state = optionsOrState
{tabLength, softTabs, @softWrap} = @state.toObject()
@buffer = deserialize(@state.get('buffer'))
@setScrollTop(@state.get('scrollTop'))
@setScrollLeft(@state.get('scrollLeft'))
cursorScreenPosition = @state.getObject('cursorScreenPosition')
else
{@buffer, tabLength, softTabs, @softWrap} = optionsOrState
@state = telepath.Document.create
deserializer: 'EditSession'
version: @constructor.version
scrollTop: 0
scrollLeft: 0
cursorScreenPosition = [0, 0]
@softTabs = @buffer.usesSoftTabs() ? softTabs ? true
@languageMode = new LanguageMode(this, @buffer.getExtension())
@displayBuffer = new DisplayBuffer(@buffer, { @languageMode, tabLength })
@cursors = []
@selections = []
@addCursorAtScreenPosition([0, 0])
@addCursorAtScreenPosition(cursorScreenPosition)
@buffer.retain()
@subscribe @buffer, "path-changed", =>
@project.setPath(path.dirname(@getPath())) unless @project.getPath()?
project.setPath(path.dirname(@getPath())) unless project.getPath()?
@trigger "title-changed"
@trigger "path-changed"
@subscribe @buffer, "contents-conflicted", => @trigger "contents-conflicted"
@@ -64,6 +75,13 @@ class EditSession
@displayBuffer.on 'grammar-changed', => @handleGrammarChange()
@state.observe ({key, newValue}) =>
switch key
when 'scrollTop'
@trigger 'scroll-top-changed', newValue
when 'scrollLeft'
@trigger 'scroll-left-changed', newValue
getViewClass: ->
require 'editor'
@@ -75,21 +93,26 @@ class EditSession
selection.destroy() for selection in @getSelections()
@displayBuffer.destroy()
@languageMode.destroy()
@project?.removeEditSession(this)
project?.removeEditSession(this)
@trigger 'destroyed'
@off()
serialize: ->
deserializer: 'EditSession'
version: @constructor.version
buffer: @buffer.serialize()
scrollTop: @getScrollTop()
scrollLeft: @getScrollLeft()
cursorScreenPosition: @getCursorScreenPosition().serialize()
@state.set
buffer: @buffer.serialize()
scrollTop: @getScrollTop()
scrollLeft: @getScrollLeft()
tabLength: @getTabLength()
softTabs: @softTabs
softWrap: @softWrap
cursorScreenPosition: @getCursorScreenPosition().serialize()
@state
getState: -> @serialize()
# Creates a copy of the current {EditSession}.Returns an identical `EditSession`.
copy: ->
EditSession.deserialize(@serialize(), @project)
EditSession.deserialize(@serialize())
### Public ###
@@ -129,8 +152,8 @@ class EditSession
isEqual: (other) ->
return false unless other instanceof EditSession
@buffer == other.buffer and
@scrollTop == other.getScrollTop() and
@scrollLeft == other.getScrollLeft() and
@getScrollTop() == other.getScrollTop() and
@getScrollLeft() == other.getScrollLeft() and
@getCursorScreenPosition().isEqual(other.getCursorScreenPosition())
setVisible: (visible) -> @displayBuffer.setVisible(visible)
@@ -138,22 +161,23 @@ class EditSession
# Defines the value of the `EditSession`'s `scrollTop` property.
#
# scrollTop - A {Number} defining the `scrollTop`, in pixels.
setScrollTop: (@scrollTop) ->
setScrollTop: (scrollTop) -> @state.set('scrollTop', scrollTop)
# Gets the value of the `EditSession`'s `scrollTop` property.
#
# Returns a {Number} defining the `scrollTop`, in pixels.
getScrollTop: -> @scrollTop
getScrollTop: ->
@state.get('scrollTop') ? 0
# Defines the value of the `EditSession`'s `scrollLeft` property.
#
# scrollLeft - A {Number} defining the `scrollLeft`, in pixels.
setScrollLeft: (@scrollLeft) ->
setScrollLeft: (scrollLeft) -> @state.set('scrollLeft', scrollLeft)
# Gets the value of the `EditSession`'s `scrollLeft` property.
#
# Returns a {Number} defining the `scrollLeft`, in pixels.
getScrollLeft: -> @scrollLeft
getScrollLeft: -> @state.get('scrollLeft')
# Defines the limit at which the buffer begins to soft wrap text.
#
@@ -729,12 +753,12 @@ class EditSession
replaceSelectedText: (options={}, fn) ->
{selectWordIfEmpty} = options
@mutateSelectedText (selection) =>
@mutateSelectedText (selection) ->
range = selection.getBufferRange()
if selectWordIfEmpty and selection.isEmpty()
selection.selectWord()
text = selection.getText()
selection.delete()
selection.deleteSelectedText()
selection.insertText(fn(text))
selection.setBufferRange(range)
@@ -1274,7 +1298,7 @@ class EditSession
abort: -> @buffer.abort()
inspect: ->
JSON.stringify @serialize()
JSON.stringify @state.toObject()
logScreenLines: (start, end) -> @displayBuffer.logLines(start, end)
+8 -2
Ver Arquivo
@@ -728,6 +728,12 @@ class Editor extends View
@activeEditSession.on 'screen-lines-changed.editor', (e) =>
@handleScreenLinesChange(e)
@activeEditSession.on 'scroll-top-changed.editor', (scrollTop) =>
@scrollTop(scrollTop)
@activeEditSession.on 'scroll-left-changed.editor', (scrollLeft) =>
@scrollLeft(scrollLeft)
@trigger 'editor:path-changed'
@resetDisplay()
@@ -1089,8 +1095,8 @@ class Editor extends View
@clearRenderedLines()
@removeAllCursorAndSelectionViews()
editSessionScrollTop = @activeEditSession.scrollTop ? 0
editSessionScrollLeft = @activeEditSession.scrollLeft ? 0
editSessionScrollTop = @activeEditSession.getScrollTop() ? 0
editSessionScrollLeft = @activeEditSession.getScrollLeft() ? 0
@updateLayerDimensions()
@scrollTop(editSessionScrollTop)
@scrollLeft(editSessionScrollLeft)
+4
Ver Arquivo
@@ -150,6 +150,7 @@ class Keymap
if event.originalEvent.keyIdentifier.indexOf('U+') == 0
hexCharCode = event.originalEvent.keyIdentifier[2..]
charCode = parseInt(hexCharCode, 16)
charCode = event.which if !@isAscii(charCode) and @isAscii(event.which)
key = @keyFromCharCode(charCode)
else
key = event.originalEvent.keyIdentifier.toLowerCase()
@@ -170,6 +171,9 @@ class Keymap
[modifiers..., key].join('-')
isAscii: (charCode) ->
0 <= charCode <= 127
keyFromCharCode: (charCode) ->
switch charCode
when 8 then 'backspace'
+2
Ver Arquivo
@@ -52,6 +52,8 @@
'meta-8': 'pane:show-item-8'
'meta-9': 'pane:show-item-9'
'meta-T': 'pane:reopen-closed-item'
'alt-meta-w': 'pane:close-other-items'
'meta-P': 'pane:close'
'meta-n': 'new-window'
'meta-N': 'new-editor'
-2
Ver Arquivo
@@ -20,8 +20,6 @@
'meta-alt-p': 'editor:log-cursor-scope'
'meta-u': 'editor:upper-case'
'meta-U': 'editor:lower-case'
'alt-meta-w': 'editor:close-other-edit-sessions'
'meta-P': 'editor:close-all-edit-sessions'
'ctrl-C': 'editor:copy-path'
'ctrl-meta-up': 'editor:move-line-up'
'ctrl-meta-down': 'editor:move-line-down'
+79 -10
Ver Arquivo
@@ -1,23 +1,92 @@
$ = require 'jquery'
{View} = require 'space-pen'
telepath = require 'telepath'
# Internal:
### Internal ###
module.exports =
class PaneAxis extends View
@acceptsDocuments: true
@deserialize: ({children}) ->
childViews = children.map (child) -> deserialize(child)
new this(childViews)
@deserialize: (state) ->
new this(state)
initialize: (children=[]) ->
@append(children...)
initialize: (args...) ->
if args[0] instanceof telepath.Document
@state = args[0]
@state.get('children').each (child, index) => @addChild(deserialize(child), index, updateState: false)
else
@state = telepath.Document.create(deserializer: @className(), children: [])
@addChild(child) for child in args
@state.get('children').observe ({index, inserted, removed, site}) =>
return if site is @state.site.id
for childState in removed
@removeChild(@children(":eq(#{index})").view(), updateState: false)
for childState, i in inserted
@addChild(deserialize(childState), index + i, updateState: false)
addChild: (child, index=@children().length, options={}) ->
@insertAt(index, child)
@state.get('children').insert(index, child.serialize()) if options.updateState ? true
@getContainer()?.adjustPaneDimensions()
removeChild: (child, options={}) ->
options.updateState ?= true
parent = @parent().view()
container = @getContainer()
primitiveRemove = (child) =>
node = child[0]
$.cleanData(node.getElementsByTagName('*'))
$.cleanData([node])
this[0].removeChild(node)
# use primitive .removeChild() dom method instead of .remove() to avoid recursive loop
if @children().length == 2
primitiveRemove(child)
sibling = @children().view()
siblingFocused = sibling.is(':has(:focus)')
sibling.detach()
if parent.setRoot?
parent.setRoot(sibling, options)
else
parent.insertChildBefore(this, sibling, options)
parent.removeChild(this, options)
sibling.focus() if siblingFocused
else
@state.get('children').remove(@indexOf(child)) if options.updateState
primitiveRemove(child)
container.adjustPaneDimensions()
Pane = require 'pane'
container.trigger 'pane:removed', [child] if child instanceof Pane
detachChild: (child) ->
@state.get('children').remove(@indexOf(child))
child.detach()
getContainer: ->
@closest('#panes').view()
insertChildBefore: (child, newChild, options={}) ->
newChild.insertBefore(child)
if options.updateState ? true
children = @state.get('children')
childIndex = children.indexOf(child.getState())
children.insert(childIndex, newChild.getState())
insertChildAfter: (child, newChild) ->
newChild.insertAfter(child)
children = @state.get('children')
childIndex = children.indexOf(child.getState())
children.insert(childIndex + 1, newChild.getState())
serialize: ->
deserializer: @className()
children: @childViewStates()
child.serialize() for child in @children().views()
@state
childViewStates: ->
$(child).view().serialize() for child in @children()
getState: -> @state
horizontalChildUnits: ->
$(child).view().horizontalGridUnits() for child in @children()
+37 -22
Ver Arquivo
@@ -1,29 +1,42 @@
{View} = require 'space-pen'
Pane = require 'pane'
$ = require 'jquery'
telepath = require 'telepath'
module.exports =
class PaneContainer extends View
registerDeserializer(this)
### Internal ###
@acceptsDocuments: true
@deserialize: ({root}) ->
container = new PaneContainer
container.append(deserialize(root)) if root
@deserialize: (state) ->
container = new PaneContainer(state)
container.removeEmptyPanes()
container
@content: ->
@div id: 'panes'
initialize: ->
initialize: (@state) ->
if @state?
@setRoot(deserialize(@state.get('root')), updateState: false)
else
@state = telepath.Document.create(deserializer: 'PaneContainer')
@state.observe ({key, newValue, site}) =>
return if site is @state.site.id
if key is 'root'
@setRoot(deserialize(newValue), updateState: false)
@destroyedItemStates = []
serialize: ->
deserializer: 'PaneContainer'
root: @getRoot()?.serialize()
@getRoot()?.serialize()
@state
getState: -> @state
### Public ###
focusNextPane: ->
@@ -60,7 +73,7 @@ class PaneContainer extends View
true
else
newPane = new Pane(deserialize(lastItemState))
@append(newPane)
@setRoot(newPane)
newPane.focus()
itemDestroyed: (item) ->
@@ -76,25 +89,27 @@ class PaneContainer extends View
getRoot: ->
@children().first().view()
setRoot: (root, options={}) ->
@empty()
@append(root) if root?
@state.set(root: root?.getState()) if options.updateState ? true
removeChild: (child) ->
throw new Error("Removing non-existant child") unless @getRoot() is child
@setRoot(null)
@trigger 'pane:removed', [child] if child instanceof Pane
saveAll: ->
pane.saveItems() for pane in @getPanes()
confirmClose: ->
deferred = $.Deferred()
modifiedItems = []
saved = true
for pane in @getPanes()
modifiedItems.push(item) for item in pane.getItems() when item.isModified?()
cancel = => deferred.reject()
saveNextModifiedItem = =>
if modifiedItems.length == 0
deferred.resolve()
else
item = modifiedItems.pop()
@paneAtIndex(0).promptToSaveItem item, saveNextModifiedItem, cancel
saveNextModifiedItem()
deferred.promise()
for item in pane.getItems() when item.isModified?()
if not @paneAtIndex(0).promptToSaveItem item
saved = false
break
saved
getPanes: ->
@find('.pane').views()
+109 -62
Ver Arquivo
@@ -1,6 +1,7 @@
{View} = require 'space-pen'
$ = require 'jquery'
_ = require 'underscore'
telepath = require 'telepath'
PaneRow = require 'pane-row'
PaneColumn = require 'pane-column'
@@ -8,24 +9,49 @@ module.exports =
class Pane extends View
### Internal ###
@acceptsDocuments: true
@content: (wrappedView) ->
@div class: 'pane', =>
@div class: 'item-views', outlet: 'itemViews'
@deserialize: ({items, focused, activeItemUri}) ->
deserializedItems = _.compact(items.map((item) -> deserialize(item)))
pane = new Pane(deserializedItems...)
pane.showItemForUri(activeItemUri) if activeItemUri
pane.focusOnAttach = true if focused
@deserialize: (state) ->
pane = new Pane(state)
pane.focusOnAttach = true if state.get('focused')
pane
activeItem: null
items: null
viewsByClassName: null # Views with a setModel() method are stored here
viewsByItem: null # Views without a setModel() method are stored here
initialize: (args...) ->
if args[0] instanceof telepath.Document
@state = args[0]
@items = @state.get('items').map (item) -> deserialize(item)
else
@items = args
@state = telepath.Document.create
deserializer: 'Pane'
items: @items.map (item) -> item.getState?() ? item.serialize()
@state.get('items').observe ({index, removed, inserted, site}) =>
return if site is @state.site.id
for itemState in removed
@removeItemAtIndex(index, updateState: false)
for itemState, i in inserted
@addItem(deserialize(itemState), index + i, updateState: false)
@state.observe ({key, newValue, site}) =>
return if site is @state.site.id
@showItemForUri(newValue) if key is 'activeItemUri'
initialize: (@items...) ->
@viewsByClassName = {}
@showItem(@items[0]) if @items.length > 0
@viewsByItem = new WeakMap()
if activeItemUri = @state.get('activeItemUri')
@showItemForUri(activeItemUri)
else
@showItem(@items[0]) if @items.length > 0
@command 'core:close', @destroyActiveItem
@command 'core:save', @saveActiveItem
@@ -129,12 +155,15 @@ class Pane extends View
@activeView = view
@trigger 'pane:active-item-changed', [item]
@state.set('activeItemUri', item.getUri?())
activeItemTitleChanged: =>
@trigger 'pane:active-item-title-changed'
addItem: (item) ->
addItem: (item, index=@getActiveItemIndex()+1, options={}) ->
return if _.include(@items, item)
index = @getActiveItemIndex() + 1
@state.get('items').splice(index, 0, item.getState?() ? item.serialize()) if options.updateState ? true
@items.splice(index, 0, item)
@getContainer().itemAdded(item)
@trigger 'pane:item-added', [item, index]
@@ -154,7 +183,7 @@ class Pane extends View
@autosaveItem(item)
if item.shouldPromptToSave?()
@promptToSaveItem(item, reallyDestroyItem)
reallyDestroyItem() if @promptToSaveItem(item)
else
reallyDestroyItem()
@@ -164,15 +193,19 @@ class Pane extends View
destroyInactiveItems: ->
@destroyItem(item) for item in @getItems() when item isnt @activeItem
promptToSaveItem: (item, nextAction, cancelAction) ->
promptToSaveItem: (item) ->
uri = item.getUri()
atom.confirm(
currentWindow = require('remote').getCurrentWindow()
chosen = atom.confirmSync(
"'#{item.getTitle?() ? item.getUri()}' has changes, do you want to save them?"
"Your changes will be lost if you close this item without saving."
"Save", => @saveItem(item, nextAction)
"Cancel", cancelAction
"Don't Save", nextAction
["Save", "Cancel", "Don't Save"]
currentWindow
)
switch chosen
when 0 then @saveItem(item, -> true)
when 1 then false
when 2 then true
saveActiveItem: =>
@saveItem(@activeItem)
@@ -189,10 +222,10 @@ class Pane extends View
saveItemAs: (item, nextAction) ->
return unless item.saveAs?
atom.showSaveDialog (path) =>
if path
item.saveAs(path)
nextAction?()
path = atom.showSaveDialogSync()
if path
item.saveAs(path)
nextAction?()
saveItems: =>
@saveItem(item) for item in @getItems()
@@ -205,10 +238,13 @@ class Pane extends View
removeItem: (item) ->
index = @items.indexOf(item)
return if index == -1
@removeItemAtIndex(index) if index >= 0
removeItemAtIndex: (index, options={}) ->
item = @items[index]
@showNextItem() if item is @activeItem and @items.length > 1
_.remove(@items, item)
@state.get('items').remove(index) if options.updateState ? true
@cleanupItemView(item)
@trigger 'pane:item-removed', [item, index]
@@ -216,6 +252,8 @@ class Pane extends View
oldIndex = @items.indexOf(item)
@items.splice(oldIndex, 1)
@items.splice(newIndex, 0, item)
@state.get('items').splice(oldIndex, 1)
@state.get('items').splice(newIndex, 0, item.getState?() ? item.serialize())
@trigger 'pane:item-moved', [item, newIndex]
moveItemToPane: (item, pane, index) ->
@@ -234,12 +272,15 @@ class Pane extends View
if item instanceof $
viewToRemove = item
else
viewClass = item.getViewClass()
otherItemsForView = @items.filter (i) -> i.getViewClass?() is viewClass
unless otherItemsForView.length
viewToRemove = @viewsByClassName[viewClass.name]
viewToRemove?.setModel(null)
delete @viewsByClassName[viewClass.name]
if viewToRemove = @viewsByItem.get(item)
@viewsByItem.delete(item)
else
viewClass = item.getViewClass()
otherItemsForView = @items.filter (i) -> i.getViewClass?() is viewClass
unless otherItemsForView.length
viewToRemove = @viewsByClassName[viewClass.name]
viewToRemove?.setModel(null)
delete @viewsByClassName[viewClass.name]
if @items.length > 0
if @isMovingItem and item is viewToRemove
@@ -248,27 +289,34 @@ class Pane extends View
viewToRemove?.remove()
else
viewToRemove?.detach() if @isMovingItem and item is viewToRemove
@remove()
@parent().view().removeChild(this, updateState: false)
viewForItem: (item) ->
if item instanceof $
item
else if view = @viewsByItem.get(item)
view
else
viewClass = item.getViewClass()
if view = @viewsByClassName[viewClass.name]
view.setModel(item)
else
view = @viewsByClassName[viewClass.name] = new viewClass(item)
view = new viewClass(item)
if _.isFunction(view.setModel)
@viewsByClassName[viewClass.name] = view
else
@viewsByItem.set(item, view)
view
viewForActiveItem: ->
@viewForItem(@activeItem)
serialize: ->
deserializer: "Pane"
focused: @is(':has(:focus)')
activeItemUri: @activeItem.getUri?() if typeof @activeItem.serialize is 'function'
items: _.compact(@getItems().map (item) -> item.serialize?())
@state.get('items').set(index, item.serialize()) for item, index in @items
@state.set focused: @is(':has(:focus)')
@state
getState: -> @state
adjustDimensions: -> # do nothing
@@ -289,22 +337,35 @@ class Pane extends View
@split(items, 'row', 'after')
split: (items, axis, side) ->
unless @parent().hasClass(axis)
@buildPaneAxis(axis)
.insertBefore(this)
.append(@detach())
PaneContainer = require 'pane-container'
parent = @parent().view()
unless parent.hasClass(axis)
axis = @buildPaneAxis(axis)
if parent instanceof PaneContainer
@detach()
parent.setRoot(axis)
else
parent.insertChildBefore(this, axis)
parent.detachChild(this)
axis.addChild(this)
parent = axis
items = [@copyActiveItem()] unless items.length
pane = new Pane(items...)
this[side](pane)
newPane = new Pane(items...)
switch side
when 'before' then parent.insertChildBefore(this, newPane)
when 'after' then parent.insertChildAfter(this, newPane)
@getContainer().adjustPaneDimensions()
pane.focus()
pane
newPane.focus()
newPane
buildPaneAxis: (axis) ->
switch axis
when 'row' then new PaneRow
when 'column' then new PaneColumn
when 'row' then new PaneRow()
when 'column' then new PaneColumn()
getContainer: ->
@closest('#panes').view()
@@ -314,26 +375,12 @@ class Pane extends View
remove: (selector, keepData) ->
return super if keepData
# find parent elements before removing from dom
container = @getContainer()
parentAxis = @parent('.row, .column')
if @is(':has(:focus)')
container.focusNextPane() or rootView?.focus()
else if @isActive()
container.makeNextPaneActive()
super
if parentAxis.children().length == 1
sibling = parentAxis.children()
siblingFocused = sibling.is(':has(:focus)')
sibling.detach()
parentAxis.replaceWith(sibling)
sibling.focus() if siblingFocused
container.adjustPaneDimensions()
container.trigger 'pane:removed', [this]
@parent().view().removeChild(this)
beforeRemove: ->
if @is(':has(:focus)')
@getContainer().focusNextPane() or rootView?.focus()
else if @isActive()
@getContainer().makeNextPaneActive()
item.destroy?() for item in @getItems()
+10 -5
Ver Arquivo
@@ -15,6 +15,10 @@ BufferedProcess = require 'buffered-process'
# of directories and files that you can operate on.
module.exports =
class Project
registerDeserializer(this)
@deserialize: (state) -> new Project(state.path)
@openers: []
@registerOpener: (opener) ->
@@ -34,6 +38,7 @@ class Project
destroy: ->
editSession.destroy() for editSession in @getEditSessions()
buffer.release() for buffer in @getBuffers()
### Public ###
@@ -45,6 +50,10 @@ class Project
@editSessions = []
@buffers = []
serialize: ->
deserializer: 'Project'
path: @getPath()
# Retrieves the project path.
#
# Returns a {String}.
@@ -182,10 +191,7 @@ class Project
#
# Returns an {Array} of {Buffer}s.
getBuffers: ->
buffers = []
for editSession in @editSessions when not _.include(buffers, editSession.buffer)
buffers.push editSession.buffer
buffers
new Array(@buffers...)
# Given a file path, this retrieves or creates a new {Buffer}.
#
@@ -289,7 +295,6 @@ class Project
buildEditSessionForBuffer: (buffer, editSessionOptions) ->
options = _.extend(@defaultEditSessionOptions(), editSessionOptions)
options.project = this
options.buffer = buffer
editSession = new EditSession(options)
@editSessions.push editSession
+17 -13
Ver Arquivo
@@ -2,7 +2,7 @@ $ = require 'jquery'
{$$} = require 'space-pen'
fsUtils = require 'fs-utils'
_ = require 'underscore'
telepath = require 'telepath'
{View} = require 'space-pen'
Buffer = require 'text-buffer'
Editor = require 'editor'
@@ -26,18 +26,23 @@ class RootView extends View
themes: ['atom-dark-ui', 'atom-dark-syntax']
### Internal ###
@acceptsDocuments: true
@content: ({panes}={}) ->
@content: (state) ->
@div id: 'root-view', =>
@div id: 'horizontal', outlet: 'horizontal', =>
@div id: 'vertical', outlet: 'vertical', =>
@subview 'panes', panes ? new PaneContainer
@subview 'panes', deserialize(state?.get?('panes')) ? new PaneContainer
@deserialize: ({panes, fullScreen}) ->
panes = deserialize(panes) if panes?.deserializer is 'PaneContainer'
new RootView({panes, fullScreen})
@deserialize: (state) ->
new RootView(state)
initialize: (state={}) ->
if state instanceof telepath.Document
@state = state
else
@state = telepath.Document.create(_.extend({version: RootView.version, deserializer: 'RootView', panes: @panes.serialize()}, state))
initialize: ({fullScreen}={})->
@on 'focus', (e) => @handleFocus(e)
@subscribe $(window), 'focus', (e) =>
@handleFocus(e) if document.activeElement is document.body
@@ -75,13 +80,12 @@ class RootView extends View
@command 'new-editor', =>
@open()
_.nextTick -> atom.setFullScreen(fullScreen)
_.nextTick => atom.setFullScreen(@state.get('fullScreen'))
serialize: ->
version: RootView.version
deserializer: 'RootView'
panes: @panes.serialize()
fullScreen: atom.isFullScreen()
@panes.serialize()
@state.set('fullScreen', atom.isFullScreen())
@state
handleFocus: (e) ->
if @getActivePane()
@@ -117,7 +121,7 @@ class RootView extends View
else
editSession = project.open(path)
activePane = new Pane(editSession)
@panes.append(activePane)
@panes.setRoot(activePane)
activePane.focus() if changeFocus
editSession
+2 -2
Ver Arquivo
@@ -13,7 +13,7 @@ BufferMarker = require 'buffer-marker'
# The `Buffer` is often associated with a {File}. However, this is not always
# the case, as a `Buffer` could be an unsaved chunk of text.
module.exports =
class Buffer
class TextBuffer
@idCounter = 1
registerDeserializer(this)
stoppedChangingDelay: 300
@@ -695,4 +695,4 @@ class Buffer
lines.push "#{row}: #{@lineForRow(row)}"
lines.join('\n')
_.extend(Buffer.prototype, EventEmitter)
_.extend(TextBuffer.prototype, EventEmitter)
+2 -3
Ver Arquivo
@@ -74,11 +74,10 @@ class TextMateGrammar
getScore: (filePath, contents) ->
contents = fsUtils.read(filePath) if not contents? and fsUtils.isFileSync(filePath)
if syntax.grammarOverrideForPath(filePath) is @scopeName
2 + filePath.length
2 + (filePath?.length ? 0)
else if @matchesContents(contents)
1 + filePath.length
1 + (filePath?.length ? 0)
else
@getPathScore(filePath)
+2 -5
Ver Arquivo
@@ -14,13 +14,10 @@ class WindowEventHandler
@subscribe $(window), 'blur', -> $("body").addClass('is-blurred')
@subscribe $(window), 'window:open-path', (event, pathToOpen) ->
rootView?.open(pathToOpen) unless fsUtils.isDirectorySync(pathToOpen)
@subscribe $(window), 'beforeunload', -> rootView?.confirmClose()
@subscribeToCommand $(window), 'window:toggle-full-screen', => atom.toggleFullScreen()
@subscribeToCommand $(window), 'window:close', =>
if rootView?
rootView.confirmClose().done -> closeWithoutConfirm()
else
closeWithoutConfirm()
@subscribeToCommand $(window), 'window:close', => window.close()
@subscribeToCommand $(window), 'window:reload', => atom.reload()
@subscribeToCommand $(document), 'core:focus-next', @focusNext
+30 -22
Ver Arquivo
@@ -1,5 +1,6 @@
fsUtils = require 'fs-utils'
path = require 'path'
telepath = require 'telepath'
$ = require 'jquery'
less = require 'less'
ipc = require 'ipc'
@@ -18,7 +19,8 @@ defaultWindowDimensions = {width: 800, height: 600}
windowEventHandler = null
# This method is called in any window needing a general environment, including specs
window.setUpEnvironment = ->
window.setUpEnvironment = (windowMode) ->
atom.windowMode = windowMode
window.resourcePath = remote.getCurrentWindow().loadSettings.resourcePath
Config = require 'config'
@@ -44,7 +46,6 @@ window.startEditorWindow = ->
installAtomCommand()
installApmCommand()
atom.windowMode = 'editor'
windowEventHandler = new WindowEventHandler
restoreDimensions()
config.load()
@@ -60,7 +61,6 @@ window.startEditorWindow = ->
atom.focus()
window.startConfigWindow = ->
atom.windowMode = 'config'
restoreDimensions()
windowEventHandler = new WindowEventHandler
config.load()
@@ -76,10 +76,12 @@ window.startConfigWindow = ->
window.unloadEditorWindow = ->
return if not project and not rootView
atom.setWindowState('syntax', syntax.serialize())
atom.setWindowState('rootView', rootView.serialize())
windowState = atom.getWindowState()
windowState.set('syntax', syntax.serialize())
windowState.set('rootView', rootView.serialize())
atom.deactivatePackages()
atom.setWindowState('packageStates', atom.packageStates)
windowState.set('packageStates', atom.packageStates)
atom.saveWindowState()
rootView.remove()
project.destroy()
git?.destroy()
@@ -98,7 +100,7 @@ window.installApmCommand = (callback) ->
window.unloadConfigWindow = ->
return if not configView
atom.setWindowState('configView', configView.serialize())
atom.getWindowState().set('configView', configView.serialize())
configView.remove()
windowEventHandler?.unsubscribe()
window.configView = null
@@ -114,13 +116,19 @@ window.deserializeEditorWindow = ->
Project = require 'project'
Git = require 'git'
{initialPath} = atom.getLoadSettings()
windowState = atom.getWindowState()
atom.packageStates = windowState.packageStates ? {}
window.project = new Project(initialPath)
window.rootView = deserialize(windowState.rootView) ? new RootView
atom.packageStates = windowState.getObject('packageStates') ? {}
window.project = deserialize(windowState.get('project'))
unless window.project?
window.project = new Project(atom.getLoadSettings().initialPath)
windowState.set('project', window.project.serialize())
window.rootView = deserialize(windowState.get('rootView'))
unless window.rootView?
window.rootView = new RootView()
windowState.set('rootView', window.rootView.serialize())
$(rootViewParentSelector).append(rootView)
@@ -134,8 +142,7 @@ window.deserializeEditorWindow = ->
window.deserializeConfigWindow = ->
ConfigView = require 'config-view'
windowState = atom.getWindowState()
window.configView = deserialize(windowState.configView) ? new ConfigView()
window.configView = deserialize(atom.getWindowState('configView')) ? new ConfigView()
$(rootViewParentSelector).append(configView)
window.stylesheetElementForId = (id) ->
@@ -205,14 +212,10 @@ window.setDimensions = ({x, y, width, height}) ->
browserWindow.center()
window.restoreDimensions = ->
dimensions = atom.getWindowState('dimensions')
dimensions = atom.getWindowState().getObject('dimensions')
dimensions = defaultWindowDimensions unless dimensions?.width and dimensions?.height
window.setDimensions(dimensions)
$(window).on 'unload', -> atom.setWindowState('dimensions', window.getDimensions())
window.closeWithoutConfirm = ->
atom.hide()
ipc.sendChannel 'close-without-confirm'
$(window).on 'unload', -> atom.getWindowState().set('dimensions', window.getDimensions())
window.onerror = ->
atom.openDevTools()
@@ -231,11 +234,16 @@ window.unregisterDeserializer = (klass) ->
window.deserialize = (state) ->
if deserializer = getDeserializer(state)
return if deserializer.version? and deserializer.version isnt state.version
stateVersion = state.get?('version') ? state.version
return if deserializer.version? and deserializer.version isnt stateVersion
if (state instanceof telepath.Document) and not deserializer.acceptsDocuments
state = state.toObject()
deserializer.deserialize(state)
window.getDeserializer = (state) ->
name = state?.deserializer
return unless state?
name = state.get?('deserializer') ? state.deserializer
if deferredDeserializers[name]
deferredDeserializers[name]()
delete deferredDeserializers[name]
+7 -8
Ver Arquivo
@@ -50,9 +50,7 @@ class AtomApplication
@buildApplicationMenu()
@handleEvents()
# Don't check for updates if it's a custom build.
if @version.indexOf('.') isnt -1
@checkForUpdates()
@checkForUpdates()
if test
@runSpecs({exitWhenDone: true, @resourcePath})
@@ -82,6 +80,8 @@ class AtomApplication
app.commandLine.appendSwitch 'js-flags', '--harmony_collections'
checkForUpdates: ->
return if /\w{7}/.test @version # Don't check for updates if version is a short sha
autoUpdater.setAutomaticallyChecksForUpdates true
autoUpdater.checkForUpdatesInBackground()
@@ -124,6 +124,7 @@ class AtomApplication
menus.push
label: 'File'
submenu: [
{ label: 'New Window', accelerator: 'Command+N', click: => @openPath() }
{ label: 'Open...', accelerator: 'Command+O', click: => @promptForPath() }
{ label: 'Open In Dev Mode...', accelerator: 'Command+Shift+O', click: => @promptForPath(devMode: true) }
]
@@ -175,11 +176,6 @@ class AtomApplication
@installUpdate = quitAndUpdate
@buildApplicationMenu version, quitAndUpdate
ipc.on 'close-without-confirm', (processId, routingId) ->
window = BrowserWindow.fromProcessIdAndRoutingId processId, routingId
window.removeAllListeners 'close'
window.close()
ipc.on 'open-config', =>
@openConfig()
@@ -189,6 +185,9 @@ class AtomApplication
else
@promptForPath()
ipc.on 'open-window', (processId, routingId, windowSettings) ->
new AtomWindow(windowSettings)
ipc.on 'open-dev', (processId, routingId, pathsToOpen) =>
if pathsToOpen?.length > 0
@openPaths({pathsToOpen, devMode: true})
+12 -12
Ver Arquivo
@@ -4,23 +4,28 @@ dialog = require 'dialog'
ipc = require 'ipc'
path = require 'path'
fs = require 'fs'
_ = require 'underscore'
module.exports =
class AtomWindow
browserWindow: null
constructor: ({bootstrapScript, resourcePath, pathToOpen, exitWhenDone, @isSpec}) ->
constructor: (settings={}) ->
{resourcePath, pathToOpen, isSpec} = settings
global.atomApplication.addWindow(this)
@setupNodePath(resourcePath)
@browserWindow = new BrowserWindow show: false, title: 'Atom'
@handleEvents()
@handleEvents(isSpec)
initialPath = pathToOpen
loadSettings = _.extend({}, settings)
loadSettings.windowState ?= ''
loadSettings.initialPath = pathToOpen
try
initialPath = path.dirname(pathToOpen) if fs.statSync(pathToOpen).isFile()
if fs.statSync(pathToOpen).isFile()
loadSettings.initialPath = path.dirname(pathToOpen)
@browserWindow.loadSettings = {initialPath, bootstrapScript, resourcePath, exitWhenDone, windowState: ''}
@browserWindow.loadSettings = loadSettings
@browserWindow.once 'window:loaded', => @loaded = true
@browserWindow.loadUrl "file://#{resourcePath}/static/index.html"
@@ -62,7 +67,7 @@ class AtomWindow
else
false
handleEvents: ->
handleEvents: (isSpec)->
@browserWindow.on 'destroyed', =>
global.atomApplication.removeWindow(this)
@@ -85,15 +90,10 @@ class AtomWindow
when 0 then setImmediate => @browserWindow.destroy()
when 1 then @browserWindow.restart()
if @isSpec
if isSpec
# Spec window's web view should always have focus
@browserWindow.on 'blur', =>
@browserWindow.focusOnWebView()
else
@browserWindow.on 'close', (event) =>
unless @browserWindow.isCrashed()
event.preventDefault()
@sendCommand 'window:close'
openPath: (pathToOpen) ->
if @loaded
+1 -1
Ver Arquivo
@@ -2,6 +2,6 @@ date = new Date().getTime()
require 'atom'
require 'window'
window.setUpEnvironment()
window.setUpEnvironment('config')
window.startConfigWindow()
console.log "Load time: #{new Date().getTime() - date}"
+8
Ver Arquivo
@@ -7,6 +7,7 @@ fs = require 'fs'
path = require 'path'
optimist = require 'optimist'
nslog = require 'nslog'
dialog = require 'dialog'
_ = require 'underscore'
console.log = (args...) ->
@@ -21,6 +22,13 @@ delegate.browserMainParts.preMainMessageLoopRun = ->
event.preventDefault()
args.pathsToOpen.push(filePath)
app.on 'open-url', (event, url) =>
event.preventDefault()
dialog.showMessageBox
message: 'Atom opened with URL'
detail: url
buttons: ['OK']
app.on 'open-file', addPathToOpen
app.on 'will-finish-launching', ->
@@ -0,0 +1,3 @@
'.archive-view':
'k': 'core:move-up'
'j': 'core:move-down'
@@ -0,0 +1,4 @@
'body':
'meta-C': 'collaboration:copy-session-id'
'meta-H': 'collaboration:start-session'
'meta-K': 'collaboration:join-session'
@@ -0,0 +1,27 @@
require 'atom'
require 'window'
$ = require 'jquery'
{$$} = require 'space-pen'
{createPeer, connectDocument} = require './session-utils'
{createSite, Document} = require 'telepath'
window.setDimensions(width: 350, height: 100)
window.setUpEnvironment('editor')
{sessionId} = atom.getLoadSettings()
loadingView = $$ ->
@div style: 'margin: 10px; text-align: center', =>
@div "Joining session #{sessionId}"
$(window.rootViewParentSelector).append(loadingView)
atom.show()
peer = createPeer()
connection = peer.connect(sessionId, reliable: true)
connection.on 'open', ->
console.log 'connection opened'
connection.once 'data', (data) ->
loadingView.remove()
console.log 'received document'
atom.windowState = Document.deserialize(createSite(peer.id), data)
connectDocument(atom.windowState, connection)
window.startEditorWindow()
@@ -0,0 +1,32 @@
JoinPromptView = require './join-prompt-view'
{createSite, Document} = require 'telepath'
{createPeer, connectDocument} = require './session-utils'
startSession = ->
peer = createPeer()
peer.on 'connection', (connection) ->
connection.on 'open', ->
console.log 'sending document'
windowState = atom.getWindowState()
connection.send(windowState.serialize())
connectDocument(windowState, connection)
peer.id
module.exports =
activate: ->
sessionId = null
rootView.command 'collaboration:copy-session-id', ->
pasteboard.write(sessionId) if sessionId
rootView.command 'collaboration:start-session', ->
if sessionId = startSession()
pasteboard.write(sessionId)
rootView.command 'collaboration:join-session', ->
new JoinPromptView (id) ->
windowSettings =
bootstrapScript: require.resolve('collaboration/lib/bootstrap')
resourcePath: window.resourcePath
sessionId: id
atom.openWindow(windowSettings)
@@ -0,0 +1,39 @@
{View} = require 'space-pen'
Editor = require 'editor'
$ = require 'jquery'
Point = require 'point'
_ = require 'underscore'
Guid = require 'guid'
module.exports =
class JoinPromptView extends View
@activate: -> new Prompt
@content: ->
@div class: 'overlay from-top', =>
@subview 'miniEditor', new Editor(mini: true)
@div class: 'message', outlet: 'message', 'Enter a session id to join'
initialize: (@confirmed) ->
@miniEditor.on 'focusout', => @remove()
@on 'core:confirm', => @confirm()
@on 'core:cancel', => @remove()
clipboard = pasteboard.read()[0]
if Guid.isGuid(clipboard)
@miniEditor.setText(clipboard)
@attach()
beforeRemove: ->
@previouslyFocusedElement?.focus()
@miniEditor.setText('')
confirm: ->
@confirmed(@miniEditor.getText())
@remove()
attach: ->
@previouslyFocusedElement = $(':focus')
rootView.append(this)
@miniEditor.focus()
Diferenças do arquivo suprimidas por serem muito extensas Carregar Diff
@@ -0,0 +1,45 @@
Peer = require './peer'
Guid = require 'guid'
module.exports =
createPeer: ->
id = Guid.create().toString()
new Peer(id, host: 'ec2-54-218-51-127.us-west-2.compute.amazonaws.com', port: 8080)
connectDocument: (doc, connection) ->
nextOutputEventId = 1
outputListener = (event) ->
event.id = nextOutputEventId++
console.log 'sending event', event.id, event
connection.send(event)
doc.outputEvents.on('changed', outputListener)
queuedEvents = []
nextInputEventId = 1
handleInputEvent = (event) ->
console.log 'received event', event.id, event
doc.handleInputEvent(event)
nextInputEventId = event.id + 1
flushQueuedEvents = ->
loop
eventHandled = false
for event, index in queuedEvents when event.id is nextInputEventId
handleInputEvent(event)
queuedEvents.splice(index, 1)
eventHandled = true
break
break unless eventHandled
connection.on 'data', (event) ->
if event.id is nextInputEventId
handleInputEvent(event)
flushQueuedEvents()
else
console.log 'enqueing event', event.id, event
queuedEvents.push(event)
connection.on 'close', ->
doc.outputEvents.removeListener('changed', outputListener)
connection.on 'error', (error) ->
console.error 'connection error', error.stack ? error
+1
Ver Arquivo
@@ -0,0 +1 @@
'main': './lib/collaboration'
@@ -12,6 +12,8 @@
'a': 'tree-view:add'
'delete': 'tree-view:remove'
'backspace': 'tree-view:remove'
'k': 'core:move-up'
'j': 'core:move-down'
'.tree-view-dialog .mini.editor':
'enter': 'core:confirm'
+1 -1
Ver Arquivo
@@ -278,7 +278,7 @@ class TreeView extends ScrollView
try
if fsUtils.exists(pathToCreate)
pathType = if fsUtils.isFileSync(pathToCreate) then "file" else "directory"
dialog.showError("Error: A #{pathType} already exists at path '#{path}'. Try a different path.")
dialog.showError("Error: A #{pathType} already exists at path '#{pathToCreate}'. Try a different path.")
else if endsWithDirectorySeparator
fsUtils.makeTree(pathToCreate)
dialog.cancel()
+5 -6
Ver Arquivo
@@ -12,12 +12,11 @@ module.exports =
absolute: (relativePath) ->
return null unless relativePath?
if relativePath.indexOf('~/') is 0
if process.platform is 'win32'
home = process.env.USERPROFILE
else
home = process.env.HOME
relativePath = "#{home}#{relativePath.substring(1)}"
if relativePath is '~'
relativePath = process.env.HOME
else if relativePath.indexOf('~/') is 0
relativePath = "#{process.env.HOME}#{relativePath.substring(1)}"
try
fs.realpathSync(relativePath)
catch e
+13
Ver Arquivo
@@ -46,6 +46,19 @@ $.fn.enable = ->
$.fn.disable = ->
@attr('disabled', 'disabled')
$.fn.insertAt = (index, element) ->
target = @children(":eq(#{index})")
if target.length
$(element).insertBefore(target)
else
@append(element)
$.fn.removeAt = (index) ->
@children(":eq(#{index})").remove()
$.fn.indexOf = (child) ->
@children().toArray().indexOf($(child)[0])
$.fn.containsElement = (element) ->
(element[0].compareDocumentPosition(this[0]) & 8) == 8
+1 -49
Ver Arquivo
@@ -180,52 +180,4 @@ _.mixin
newObject[key] = value if value?
newObject
originalIsEqual = _.isEqual
extendedIsEqual = (a, b, aStack=[], bStack=[]) ->
return originalIsEqual(a, b) if a is b
return originalIsEqual(a, b) if _.isFunction(a) or _.isFunction(b)
return a.isEqual(b) if _.isFunction(a?.isEqual)
return b.isEqual(a) if _.isFunction(b?.isEqual)
stackIndex = aStack.length
while stackIndex--
return bStack[stackIndex] is b if aStack[stackIndex] is a
aStack.push(a)
bStack.push(b)
equal = false
if _.isArray(a) and _.isArray(b) and a.length is b.length
equal = true
for aElement, i in a
unless extendedIsEqual(aElement, b[i], aStack, bStack)
equal = false
break
else if _.isObject(a) and _.isObject(b)
aCtor = a.constructor
bCtor = b.constructor
aCtorValid = _.isFunction(aCtor) and aCtor instanceof aCtor
bCtorValid = _.isFunction(bCtor) and bCtor instanceof bCtor
if aCtor isnt bCtor and not (aCtorValid and bCtorValid)
equal = false
else
aKeyCount = 0
equal = true
for key, aValue of a
continue unless _.has(a, key)
aKeyCount++
unless _.has(b, key) and extendedIsEqual(aValue, b[key], aStack, bStack)
equal = false
break
if equal
bKeyCount = 0
for key, bValue of b
bKeyCount++ if _.has(b, key)
equal = aKeyCount is bKeyCount
else
equal = originalIsEqual(a, b)
aStack.pop()
bStack.pop()
equal
_.isEqual = (a, b) -> extendedIsEqual(a, b)
_.isEqual = require 'tantamount'
+1 -1
Ver Arquivo
@@ -3,6 +3,6 @@ date = new Date().getTime()
require 'atom'
require 'window'
window.setUpEnvironment()
window.setUpEnvironment('editor')
window.startEditorWindow()
console.log "Load time: #{new Date().getTime() - date}"
+1
Ver Arquivo
@@ -13,6 +13,7 @@
currentWindow.emit('window:loaded');
}
catch (error) {
currentWindow.show();
currentWindow.openDevTools();
console.error(error.stack || error);
}
+1
Ver Arquivo
@@ -158,4 +158,5 @@ body {
border: 1px solid #ddd;
background: white;
white-space: pre;
overflow: auto;
}
+57
Ver Arquivo
@@ -0,0 +1,57 @@
fs = require 'fs'
path = require 'path'
module.exports = (grunt) ->
{cp, mkdir, rm} = require('./task-helpers')(grunt)
grunt.registerTask 'build', 'Build the application', ->
shellAppDir = grunt.config.get('atom.shellAppDir')
buildDir = grunt.config.get('atom.buildDir')
appDir = grunt.config.get('atom.appDir')
rm shellAppDir
mkdir path.dirname(buildDir)
cp 'atom-shell/Atom.app', shellAppDir
mkdir appDir
cp 'atom.sh', path.join(appDir, 'atom.sh')
cp 'package.json', path.join(appDir, 'package.json')
directories = [
'benchmark'
'dot-atom'
'spec'
'vendor'
]
{devDependencies, dependencies} = grunt.file.readJSON('package.json')
for child in fs.readdirSync('node_modules')
directory = path.join('node_modules', child)
try
{name} = grunt.file.readJSON(path.join(directory, 'package.json'))
if not devDependencies[name]? or dependencies[name]?
directories.push(directory)
catch e
directories.push(directory)
ignoredPaths = [
path.join('git-utils', 'deps')
path.join('oniguruma', 'deps')
path.join('vendor', 'apm')
path.join('vendor', 'bootstrap', 'docs')
]
ignoredPaths = ignoredPaths.map (ignoredPath) -> "(#{ignoredPath})"
nodeModulesFilter = new RegExp(ignoredPaths.join('|'))
for directory in directories
cp directory, path.join(appDir, directory), filter: nodeModulesFilter
cp 'src', path.join(appDir, 'src'), filter: /.+\.(cson|coffee|less)$/
cp 'static', path.join(appDir, 'static'), filter: /.+\.less$/
cp 'themes', path.join(appDir, 'themes'), filter: /.+\.(cson|less)$/
grunt.file.recurse path.join('resources', 'mac'), (sourcePath, rootDirectory, subDirectory='', filename) ->
unless /.+\.plist/.test(sourcePath)
grunt.file.copy(sourcePath, path.resolve(appDir, '..', subDirectory, filename))
grunt.task.run('compile', 'copy-info-plist')
+16
Ver Arquivo
@@ -0,0 +1,16 @@
path = require 'path'
module.exports = (grunt) ->
{rm} = require('./task-helpers')(grunt)
grunt.registerTask 'partial-clean', 'Delete some of the build files', ->
rm grunt.config.get('atom.buildDir')
rm '/tmp/atom-coffee-cache'
rm '/tmp/atom-cached-atom-shells'
rm 'node'
rm 'atom-shell'
grunt.registerTask 'clean', 'Delete all the build files', ->
rm 'node_modules'
rm path.join(process.env.HOME, '.atom', '.node-gyp')
grunt.task.run('partial-clean')
+8
Ver Arquivo
@@ -0,0 +1,8 @@
module.exports = (grunt) ->
{spawn} = require('./task-helpers')(grunt)
grunt.registerTask 'codesign', 'Codesign the app', ->
done = @async()
cmd = 'codesign'
args = ['-f', '-v', '-s', 'Developer ID Application: GitHub', grunt.config.get('atom.shellAppDir')]
spawn {cmd, args}, (error) -> done(error)
+13
Ver Arquivo
@@ -0,0 +1,13 @@
path = require 'path'
module.exports = (grunt) ->
{cp} = require('./task-helpers')(grunt)
grunt.registerTask 'copy-info-plist', 'Copy plist', ->
contentsDir = grunt.config.get('atom.contentsDir')
plistPath = path.join(contentsDir, 'Info.plist')
helperPlistPath = path.join(contentsDir, 'Frameworks/Atom Helper.app/Contents/Info.plist')
# Copy custom plist files
cp 'resources/mac/atom-Info.plist', plistPath
cp 'resources/mac/helper-Info.plist', helperPlistPath
+22
Ver Arquivo
@@ -0,0 +1,22 @@
path = require 'path'
module.exports = (grunt) ->
cmd = path.join('node_modules', '.bin', 'coffee')
commonArgs = [path.join('node_modules', '.bin', 'biscotto'), '--']
opts =
stdio: 'inherit'
grunt.registerTask 'build-docs', 'Builds the API docs in src/app', ->
done = @async()
args = [commonArgs..., '-o', 'docs/api', 'src/app/']
grunt.util.spawn({cmd, args, opts}, done)
grunt.registerTask 'lint-docs', 'Generate stats about the doc coverage', ->
done = @async()
args = [commonArgs..., '--noOutput', 'src/app/']
grunt.util.spawn({cmd, args, opts}, done)
grunt.registerTask 'missing-docs', 'Generate stats about the doc coverage', ->
done = @async()
args = [commonArgs..., '--noOutput', '--missing', 'src/app/']
grunt.util.spawn({cmd, args, opts}, done)
+11
Ver Arquivo
@@ -0,0 +1,11 @@
path = require 'path'
module.exports = (grunt) ->
{cp, mkdir, rm} = require('./task-helpers')(grunt)
grunt.registerTask 'install', 'Install the built application', ->
installDir = grunt.config.get('atom.installDir')
shellAppDir = grunt.config.get('atom.shellAppDir')
rm installDir
mkdir path.dirname(installDir)
cp shellAppDir, installDir
+6
Ver Arquivo
@@ -0,0 +1,6 @@
module.exports = (grunt) ->
{spawn} = require('./task-helpers')(grunt)
grunt.registerTask 'nof', 'Un-focus all specs', ->
nof = require.resolve('.bin/nof')
spawn({cmd: nof, args: ['spec', 'src']}, @async())
+8
Ver Arquivo
@@ -0,0 +1,8 @@
module.exports = (grunt) ->
{spawn} = require('./task-helpers')(grunt)
grunt.registerTask 'set-development-version', 'Sets version to current SHA-1', ->
done = @async()
cmd = 'script/set-version'
args = [grunt.config.get('atom.buildDir')]
spawn {cmd, args}, (error, result, code) -> done(error)
+31
Ver Arquivo
@@ -0,0 +1,31 @@
fs = require 'fs'
path = require 'path'
walkdir = require 'walkdir'
module.exports = (grunt) ->
cp: (source, destination, {filter}={}) ->
walkdir.sync source, (sourcePath, stats) ->
return if filter?.test(sourcePath)
destinationPath = path.join(destination, path.relative(source, sourcePath))
if stats.isSymbolicLink()
grunt.file.mkdir(path.dirname(destinationPath))
fs.symlinkSync(fs.readlinkSync(sourcePath), destinationPath)
else if stats.isFile()
grunt.file.copy(sourcePath, destinationPath)
if grunt.file.exists(destinationPath)
fs.chmodSync(destinationPath, fs.statSync(sourcePath).mode)
grunt.log.writeln("Copied #{source.cyan} to #{destination.cyan}.")
mkdir: (args...) ->
grunt.file.mkdir(args...)
rm: (args...) ->
grunt.file.delete(args..., force: true) if grunt.file.exists(args...)
spawn: (options, callback) ->
grunt.util.spawn options, (error, results, code) ->
grunt.log.errorlns results.stderr if results.stderr
callback(error, results, code)
+15
Ver Arquivo
@@ -0,0 +1,15 @@
path = require 'path'
module.exports = (grunt) ->
{spawn} = require('./task-helpers')(grunt)
grunt.registerTask 'test', 'Run the specs', ->
done = @async()
commands = []
commands.push (callback) ->
spawn cmd: 'pkill', args: ['Atom'], -> callback()
commands.push (callback) ->
atomBinary = path.join(grunt.config.get('atom.contentsDir'), 'MacOS', 'Atom')
resourcePath = path.resolve(__dirname, '..')
spawn cmd: atomBinary, args: ['--test', "--resource-path=#{resourcePath}"], (error) -> callback(error)
grunt.util.async.waterfall commands, (error) -> done(error)
+26
Ver Arquivo
@@ -0,0 +1,26 @@
path = require 'path'
module.exports = (grunt) ->
{spawn} = require('./task-helpers')(grunt)
getAtomShellVersion = ->
versionPath = path.join('atom-shell', 'version')
if grunt.file.isFile(versionPath)
grunt.file.read(versionPath).trim()
else
null
grunt.registerTask 'update-atom-shell', 'Update atom-shell', ->
done = @async()
currentVersion = getAtomShellVersion()
spawn cmd: 'script/update-atom-shell', (error) ->
if error?
done(error)
else
newVersion = getAtomShellVersion()
if newVersion and currentVersion isnt newVersion
grunt.log.writeln("Rebuilding native modules for new atom-shell version #{newVersion.cyan}.")
cmd = path.join('node_modules', '.bin', 'apm')
spawn {cmd, args: ['rebuild']}, (error) -> done(error)
else
done()
+3
Ver Arquivo
@@ -1,5 +1,8 @@
.tree-view {
background: #dde3e8;
}
.tree-view-resizer {
border-right: 1px solid #989898;
}
externo
+1 -1
Submodule vendor/apm updated: 0945ca14da...ac0e54801b
+29 -1
Ver Arquivo
@@ -1,3 +1,31 @@
var _ = require('underscore');
var convertStackTrace = require('coffeestack').convertStackTrace;
var sourceMaps = {};
var formatStackTrace = function(stackTrace) {
if (!stackTrace)
return stackTrace;
// Remove all lines containing jasmine.js path
var jasminePath = require.resolve('jasmine');
var jasminePattern = new RegExp("\\(" + _.escapeRegExp(jasminePath) + ":\\d+:\\d+\\)\\s*$");
var convertedLines = [];
var lines = stackTrace.split('\n');
for (var i = 0; i < lines.length; i++)
if (!jasminePattern.test(lines[i]))
convertedLines.push(lines[i]);
//Remove last util.spawn.callDone line and all lines after it
var gruntSpawnPattern = /^\s*at util\.spawn\.callDone\s*\(.*\/grunt\/util\.js:\d+:\d+\)\s*$/
for (var i = convertedLines.length - 1; i > 0; i--)
if (gruntSpawnPattern.test(convertedLines[i])) {
convertedLines = convertedLines.slice(0, i);
break;
}
return convertStackTrace(convertedLines.join('\n'), sourceMaps);
}
jasmine.ConsoleReporter = function(doc, logErrors) {
this.logErrors = logErrors == false ? false : true
};
@@ -35,7 +63,7 @@ jasmine.ConsoleReporter.prototype.reportSpecResults = function(spec) {
console.log("\n\n" + message)
console.log((new Array(message.length + 1)).join('-'))
if (result.trace.stack) {
console.log(result.trace.stack)
console.log(formatStackTrace(result.trace.stack));
}
else {
console.log(result.message)
externo Submódulo
+1
Submodule vendor/telepath added at 3b465ef7e0