Comparar commits

...

193 Commits

Autor SHA1 Mensagem Data
Nathan Sobo 8f9f422406 📝 Update return value docs 2014-09-30 14:03:03 -06:00
Nathan Sobo 211a1c75e2 Return a disposable from ThemeManager::requireStylesheet 2014-09-30 14:02:04 -06:00
Nathan Sobo fd3cb1a232 💄 theme-manager-spec 2014-09-30 14:01:41 -06:00
Nathan Sobo f205fe81ce Actually update first-mate. Previous (51475fe231) updated atom-keymap.
Both were needed to introduce disposables, but I mixed up the commit
message in the previous commit.
2014-09-30 13:58:01 -06:00
Ben Ogle c74b1b971d Use isPlainObject() 2014-09-30 12:44:44 -07:00
Ben Ogle 54af7eced1 Handle empty config files + reset settings before applying user config
Closes #3664
2014-09-30 12:39:07 -07:00
Nathan Sobo 10f7a671c8 Merge pull request #3667 from atom/ns-deserializer-manager-disposables
Return disposables from DeserializerManager::add
2014-09-30 13:10:35 -06:00
Nathan Sobo 51475fe231 Upgrade first-mate to return Disposable from GrammarRegistry::addGrammar 2014-09-30 13:09:40 -06:00
Nathan Sobo 33a5ca30dc Use DeserializerManager::add disposable instead of ::remove in specs 2014-09-30 12:58:10 -06:00
Nathan Sobo df1ae64f62 Deprecate DeserializerManager::remove 2014-09-30 12:58:10 -06:00
Nathan Sobo 83710ed254 📝 Rename classes param to deserializers and update docs 2014-09-30 12:58:10 -06:00
Nathan Sobo 8cb8f09803 Return a Disposable instance from DeserializerManager::add 2014-09-30 12:58:10 -06:00
Kevin Sawicki ff0a7be48a Upgrade to settings-view@0.148 2014-09-30 11:18:50 -07:00
Nathan Sobo 5e6e3c8d72 Merge pull request #3655 from atom/ns-menu-disposables
Return disposables from MenuManager::add and add specs
2014-09-30 12:05:11 -06:00
Nathan Sobo dfc502b9a0 Merge pull request #3663 from atom/bo-subscribe-editor-commands
Subscribe to commands in TextEditorComponent so they are unsubscribed!
2014-09-30 10:56:05 -06:00
Ben Ogle a8d93f9cf4 Spec for unsubscribing from commands 2014-09-30 09:45:55 -07:00
Ben Ogle 50cf5f3e95 Subscribe to editor commands
We need to unsubscribe when the editor is removed!

Closes #3651
2014-09-30 09:33:50 -07:00
Kevin Sawicki 5a9b34b31a ! -> ~ 2014-09-30 09:32:03 -07:00
Kevin Sawicki 3efaeff669 🍎 Install via move instead of copy
This fixes the issue with the icon not showing up on OS X Mavericks
when building.

It seems that copying it to /Application file by file causes the icon to not
show up while moving it atomically there does.
2014-09-30 09:15:55 -07:00
Ben Ogle 443df29236 Upgrade find and replace to have cmd-d undo and skip 2014-09-29 17:26:51 -07:00
Ben Ogle 05b3f16eb2 Merge pull request #3613 from atom/bo-config-types
Support JSON Schema in Config
2014-09-29 17:23:54 -07:00
Ben Ogle b54deccfae String type must be strict.
It makes sense to coerce from more general -> more specific data types.
eg. string -> int, etc. But coercing the other way is problematic
in the case of chaining because the more general type will swallow the
specific type. eg. Setting `false` on type: [‘string’, ‘boolean’] will 
coerce the boolean to a string, and will never allow the value to be
a boolean.
2014-09-29 16:09:49 -07:00
Ben Ogle 9808264b7f Fix onDidChange usage 2014-09-29 16:09:49 -07:00
Ben Ogle f3ed3dc357 Fix doc to match implementation 2014-09-29 16:09:49 -07:00
Ben Ogle 33b25c7312 Use new config callback arguments 2014-09-29 16:09:49 -07:00
Ben Ogle 454f9c4c65 Rename config-defaults -> config-schema 2014-09-29 16:09:49 -07:00
Ben Ogle 1b506673bb 📝 update 2014-09-29 16:09:49 -07:00
Ben Ogle 5651ebbb48 always set, only emit when values differ 2014-09-29 16:09:49 -07:00
Ben Ogle a7185a894f Fix specs 2014-09-29 16:09:49 -07:00
Ben Ogle 16c7fd3d70 Add spec for update event on load 2014-09-29 16:09:49 -07:00
Ben Ogle 98290b31ab Rework defaults and user loading to notify per path 2014-09-29 16:09:48 -07:00
Ben Ogle 08b138997d Change the onDidChange / observe arguments
Support passing no keypath
2014-09-29 16:09:48 -07:00
Ben Ogle 1f7aee00ac function names to the imperative mood
http://en.wikipedia.org/wiki/Imperative_mood
2014-09-29 16:09:48 -07:00
Ben Ogle 3977596084 Validators -> enforcers 2014-09-29 16:09:48 -07:00
Ben Ogle 804d0d9911 Doc 💄 2014-09-29 16:09:48 -07:00
Ben Ogle 04d045227a rename to config-defaults 2014-09-29 16:09:48 -07:00
Ben Ogle 4e1d13ceea is plain object 2014-09-29 16:09:48 -07:00
Ben Ogle ef19e925e9 Strings accept numbers too 2014-09-29 16:09:48 -07:00
Ben Ogle 2c1fa19e27 Update spec strings 2014-09-29 16:09:48 -07:00
Ben Ogle 11fad1bd12 Moar 📝 2014-09-29 16:09:48 -07:00
Ben Ogle 1408d69641 Fix up message strings 2014-09-29 16:09:48 -07:00
Ben Ogle 38d2303857 Clean up docs in creating a package 2014-09-29 16:09:48 -07:00
Ben Ogle 96207ffbdb Update error messages to read good 2014-09-29 16:09:47 -07:00
Ben Ogle fcf2143e70 isPlainObject 2014-09-29 16:09:47 -07:00
Ben Ogle 3a8f842de3 Remove uses of toggle 2014-09-29 16:09:47 -07:00
Ben Ogle 452e34db90 Remove deprecations for push / remove / unshift at keypath 2014-09-29 16:09:47 -07:00
Ben Ogle 8b39ce77b1 We’ll always have validators for a type. No check 2014-09-29 16:09:47 -07:00
Ben Ogle 604158647a line height can be a string or a number 2014-09-29 16:09:47 -07:00
Ben Ogle 22fb5adda9 Remove deprecated calls for config.observe .. callNow: false in core 2014-09-29 16:09:47 -07:00
Ben Ogle e607d45f0d Remove instances of getPositiveInt() 2014-09-29 16:09:47 -07:00
Ben Ogle 94d470002b Update doc strings 2014-09-29 16:09:47 -07:00
Ben Ogle 33d4ace8e9 📝 more docs for Config 2014-09-29 16:09:47 -07:00
Ben Ogle 800dee09ba Make boolean schema validator a little tighter 2014-09-29 16:09:47 -07:00
Ben Ogle 6b4ce902ba Undefined in Config::set always unsets the value 2014-09-29 16:09:46 -07:00
Ben Ogle c6f7c75c8a Update method doc strings for clarity 2014-09-29 16:09:46 -07:00
Ben Ogle cb1f8e02aa Return the value from restoreDefault 2014-09-29 16:09:46 -07:00
Ben Ogle 885a19492c Rearrange managing settings section 2014-09-29 16:09:46 -07:00
Ben Ogle 8f738aae53 Fix up Config doc string 2014-09-29 16:09:46 -07:00
Ben Ogle f09e58b434 Update config docs 2014-09-29 16:09:46 -07:00
Ben Ogle 98e828b337 Move default schema into config-default-schema.coffee 2014-09-29 16:09:46 -07:00
Ben Ogle 03a9a67ba8 Move spec 2014-09-29 16:08:04 -07:00
Ben Ogle beb96cc025 💄 2014-09-29 16:08:04 -07:00
Ben Ogle ae76bd6c96 Do not allow infinity in number types 2014-09-29 16:08:04 -07:00
Ben Ogle 694dd05e7b Make warn messages way better. 2014-09-29 16:08:04 -07:00
Ben Ogle 662fc443dc Fix specs 2014-09-29 16:08:04 -07:00
Ben Ogle 0fc773c1fc Warn when loading bogus values from the user's config 2014-09-29 16:08:03 -07:00
Ben Ogle aa5b0ce41f Remove linter errors, warn when bad value 2014-09-29 16:08:03 -07:00
Ben Ogle 832b4ae4d8 Fix specs 2014-09-29 16:08:03 -07:00
Ben Ogle af1bdaf901 Dont fail when there are thigns to set with array and object types 2014-09-29 16:08:03 -07:00
Ben Ogle 969ca048e8 Fix specs 2014-09-29 16:08:03 -07:00
Ben Ogle 0d2fdec326 Fix specs in config 2014-09-29 16:08:03 -07:00
Ben Ogle f57dbfd9f5 Deprecate configDefaults in packages. 2014-09-29 16:08:03 -07:00
Ben Ogle fc3ba775c8 Support schemas in packages 2014-09-29 16:08:03 -07:00
Ben Ogle 9b07158337 Add items schemas to arrays in workspaceView 2014-09-29 16:08:03 -07:00
Ben Ogle 0bb8821644 Editor config uses a schema 2014-09-29 16:08:03 -07:00
Ben Ogle 5fdf3f894c Load the config from Atom class so as not to duplicate 2014-09-29 16:07:02 -07:00
Ben Ogle 5bf09716ef convert the workspace config to use a schema 2014-09-29 16:06:27 -07:00
Ben Ogle 9fff544955 Fix specs 2014-09-29 16:05:24 -07:00
Ben Ogle 6a29630c82 Deprecate the getInt and getPositiveInt methods 2014-09-29 16:05:24 -07:00
Ben Ogle 74ba3c6a49 Add config section to creating a package 2014-09-29 16:05:24 -07:00
Ben Ogle 601c603bbe 📝 2014-09-29 16:05:24 -07:00
Ben Ogle 9fbbd1e59b Back to getSchema 2014-09-29 16:05:24 -07:00
Ben Ogle ba4df1b002 Pass a message to the errors thrown by validators 2014-09-29 16:05:24 -07:00
Ben Ogle 2c1190b552 Validate enum keywords 2014-09-29 16:05:24 -07:00
Ben Ogle 9ff976021e Rename typeFilters to schemaValidators; add typeless validators 2014-09-29 16:05:24 -07:00
Ben Ogle 5e9a269278 getSchema -> schemaForKeyPath 2014-09-29 16:05:24 -07:00
Ben Ogle 18e0adbfa8 Fix linter error 2014-09-29 16:05:24 -07:00
Ben Ogle f7f28e7995 Handle minimum and maximum keywords on number types 2014-09-29 16:05:24 -07:00
Ben Ogle ac67430926 Handle bad values in number type 2014-09-29 16:05:23 -07:00
Ben Ogle 409b5536e1 Support arrays 2014-09-29 16:05:23 -07:00
Ben Ogle 2526ba0efb Add an object filter 2014-09-29 16:05:23 -07:00
Ben Ogle 1a8c5ba551 Handle validation of schema types 2014-09-29 16:05:23 -07:00
Ben Ogle f909d32826 Support more types 2014-09-29 16:05:23 -07:00
Ben Ogle d0bb49dea0 Add type filter system to config 2014-09-29 16:05:23 -07:00
Ben Ogle 02e87555f4 Handle schema loading 2014-09-29 16:05:23 -07:00
Ben Ogle a84dd69f55 Deprecate unused / unnecessary methods 2014-09-29 16:05:23 -07:00
Ben Ogle a79c015774 Update ::observe and add ::onDidChange 2014-09-29 16:05:23 -07:00
Ben Ogle 9e46ab1b48 Reorder config methods for easier digestion 2014-09-29 16:05:23 -07:00
Kevin Sawicki 69f24a157a Upgrade to language-coffee-script@0.35 2014-09-29 13:41:00 -07:00
Kevin Sawicki ea75636e44 Use long options 2014-09-29 13:26:36 -07:00
Kevin Sawicki e7ad9ae15a Add --deep codesign option for 10.9.5 2014-09-29 13:22:55 -07:00
Kevin Sawicki 0499ee65a4 Upgrade to tabs@0.54 2014-09-29 11:07:40 -07:00
Kevin Sawicki c56babec8d Add split commands to editor context menu
Refs atom/tabs#85
2014-09-29 11:07:19 -07:00
Nathan Sobo f6f891fa14 Construct test instance of MenuManager in spec 2014-09-29 11:45:01 -06:00
Nathan Sobo 2f93032a37 Don’t add duplicate items to the same menu 2014-09-29 11:11:36 -06:00
Nathan Sobo c058b44a1b 💄 spec description 2014-09-29 11:11:10 -06:00
Nathan Sobo 81a7f65832 📝 Update docs 2014-09-29 10:37:19 -06:00
Nathan Sobo bbeb0b5919 Return disposables from MenuManager which can be used to remove menus 2014-09-29 10:34:50 -06:00
Kevin Sawicki 60d34576d5 Upgrade to bracket-matcher@0.61 2014-09-29 09:20:35 -07:00
Ben Ogle 1539a90ee7 📝 2014-09-26 17:31:47 -07:00
Ben Ogle b958286d22 Click to expand stack traces 2014-09-26 17:31:09 -07:00
Kevin Sawicki 6ce13a9c3e Prepare 0.133 2014-09-26 15:30:40 -07:00
Kevin Sawicki d1ba8b0140 Only test on Mac OS X for now 2014-09-26 15:17:35 -07:00
Kevin Sawicki f4b23b801d Only sign setup.exe when present 2014-09-26 14:53:20 -07:00
Kevin Sawicki 14c8c463fb Don't build installers yet 2014-09-26 14:39:16 -07:00
Nathan Sobo b5fc4aec84 Re-render component when EditorView is reattached
Fixes #3640
2014-09-26 15:15:23 -06:00
Ben Ogle 1f2fc4bf00 Merge pull request #3619 from lee-dohm/scroll-past-end
Add ability to scroll past the end of the file
2014-09-26 11:47:58 -07:00
Ben Ogle 3601d113ad Deactivate and unload all packages 2014-09-26 11:21:42 -07:00
Kevin Sawicki 6a81f3c6ce Upgrade to language-sass@0.22 2014-09-26 08:34:46 -07:00
Lee Dohm 00baedbdf9 Add specs for editor.scrollPastEnd behavior 2014-09-25 23:05:47 -07:00
Lee Dohm 2c3bec7468 Add ability to scroll past the end of the file
Fixes #3592
2014-09-25 23:04:54 -07:00
Kevin Sawicki 409816ef07 Upgrade to settings-view@0.147 2014-09-25 16:26:11 -07:00
Ben Ogle 8871d45227 Merge pull request #3603 from atom/bo-rename-editor
Rename Editor -> TextEditor
2014-09-25 15:27:13 -07:00
Ben Ogle c5fa8fdf11 Fix spec 2014-09-25 15:15:50 -07:00
Ben Ogle e060e08f93 Deactivate and unload lang packages after use 2014-09-25 15:14:30 -07:00
Ben Ogle 039afff1de Unload the coffee grammar after using 2014-09-25 15:14:29 -07:00
Ben Ogle d33bd291dd Deactivate / unload packages after use
This was messing with other specs!
2014-09-25 15:14:29 -07:00
Ben Ogle b422c7a678 Recommend GitRepository. Ugh 2014-09-25 15:14:29 -07:00
Ben Ogle 55d243215a Deprecate requiring EditorView 2014-09-25 15:14:29 -07:00
Ben Ogle 0bc2b45200 Rename spec files 2014-09-25 15:14:29 -07:00
Ben Ogle 683d0d1b16 Editor -> TextEditor 2014-09-25 15:14:29 -07:00
Ben Ogle 82c53b539a editor.coffee -> text-editor.coffee 2014-09-25 15:14:29 -07:00
Ben Ogle c2f44efe31 editor-view -> text-editor-view 2014-09-25 15:14:29 -07:00
Ben Ogle b3038eb968 editor-component -> text-editor-component 2014-09-25 15:14:29 -07:00
Kevin Sawicki 3694111211 Upgrade to bracket-matcher@0.60 2014-09-25 15:09:34 -07:00
Paul Betts bf2d307cbe Merge pull request #3635 from atom/edit-accelerators
Fix Copy / Cut's accelerators on Win32
2014-09-25 13:47:33 -07:00
Paul Betts 38016b205c Fix Copy / Cut's accelerators
Copy/Cut/Paste always have the same accelerator in every app
2014-09-25 13:40:09 -07:00
Kevin Sawicki b4dcd019c1 Merge pull request #3631 from atom/ks-set-default-path-to-open-on-linux
Set default path to open on linux
2014-09-25 10:57:52 -07:00
Kevin Sawicki 13a5bfd1dd Set default path on both files and folders 2014-09-25 09:45:54 -07:00
Kevin Sawicki 9e0c4d1fb6 Only set default path when opening files 2014-09-25 09:35:25 -07:00
Kevin Sawicki cabcf19297 🐧 Default to project path in open dialog 2014-09-25 09:33:17 -07:00
Kevin Sawicki 9aa7331e6e Upgrade to tabs@0.53 2014-09-25 09:10:27 -07:00
Kevin Sawicki 3daf505f3e Upgrade to settings-view@0.146 2014-09-24 16:03:05 -07:00
Paul Betts cd92f882bf Merge pull request #3447 from atom/squirrel-installer
Build a Squirrel installer as part of CI build
2014-09-24 15:50:30 -07:00
Kevin Sawicki 707ac0b043 Upgrade to metrics@0.36 2014-09-24 15:45:19 -07:00
Paul Betts 4a812707d8 Merge remote-tracking branch 'origin/master' into squirrel-installer 2014-09-24 15:31:52 -07:00
Paul Betts f2ef7beae6 Include all PAK files 2014-09-24 15:07:41 -07:00
Kevin Sawicki c64a4dd70f Upgrade to tree-view@0.127 2014-09-24 14:58:57 -07:00
Paul Betts 3ab0b16923 Add a loading GIF that will display during initial install 2014-09-24 14:51:25 -07:00
Paul Betts fac72fbf10 Update to Squirrel 0.4.95 2014-09-24 14:51:24 -07:00
Nathan Sobo 7d71eeedf4 Break command dispatch as soon as currentTarget is null 2014-09-24 15:28:02 -06:00
Nathan Sobo 6d55bab4c8 Fix CommandRegistry::get/restoreSnapshot
I didn’t realize that deepClone was not handling functions correctly.
I’ve implemented clone manually to the exact depth needed instead.
2014-09-24 15:26:38 -06:00
Nathan Sobo d506ccbaad Merge pull request #3611 from atom/ns-activation-commands
Activation commands
2014-09-24 15:06:52 -06:00
Kevin Sawicki 8275ddd882 Catch errors thrown watching config file
Closes #3617
2014-09-24 13:54:27 -07:00
Nathan Sobo b7765d9416 Process commands invoked with jQuery trigger in CommandRegistry
Especially in specs, trigger has been used to invoke events. jQuery does
not invoke native listeners in this situation, so we use ::on to listen
for them instead. If we didn’t handle the event with a native capture
handler, we’ll still support invoking via trigger.
2014-09-24 14:34:29 -06:00
Nathan Sobo 47f8f7eb11 Switch specs to use activationCommands instead of activationEvents
The activationEvents are converted to the same format as
activationCommands, and that property will be deprecated.
2014-09-24 14:34:29 -06:00
Nathan Sobo 63181a17c8 Support activationCommands field in package.json
This field mandates selectors in its structure and closely matches the
API of `atom.commands.add`. It will supplant `activationEvents` moving
forward.
2014-09-24 14:34:28 -06:00
Nathan Sobo c71457e9d4 Default selector to .workspace when subscribing to activation events 2014-09-24 14:34:28 -06:00
Nathan Sobo 7d31b17273 Use the CommandRegistry to register activation event listeners
Commands registered with the command registry will always be handled
first, so as long as we disable any listeners in the registry that were
already invoked for the current command, we don’t need to disable jQuery
methods before replaying the command after activating the package.

This commit adds the ability to call .disableInvokedListeners on the
event passed to the command listeners. This returns a function which
can be called to reenable them.
2014-09-24 14:34:28 -06:00
Nathan Sobo 066f6bf03c Forward stop[Immediate]Propagation to original event in CommandRegistry
Previously, stopping propagation would work on the synthetic bubbling
phase of the command registry itself, but the original event would
continue to propagate which is counterintuitive.
2014-09-24 14:34:28 -06:00
Nathan Sobo 40f8b990d0 Handle dispatching non-existent commands 2014-09-24 14:34:28 -06:00
Nathan Sobo a492596f7f Allow atom.commands to participate in activationEvents
* Activation events can be handled via atom.commands
* Pre-existing listeners registered via atom.commands are disabled when
  replaying events for the activated package.
2014-09-24 14:34:28 -06:00
Nathan Sobo 2df5957f9b Restore commands after each spec
This commit adds the ability to get and restore snapshots of command
listeners. Whatever commands are installed before specs begin are
preserved, but commands added during specs are always cleared away.
2014-09-24 14:34:28 -06:00
Nathan Sobo a7196ec906 Dispatch activation commands with native DOM apis in specs 2014-09-24 14:34:28 -06:00
Nathan Sobo c094b7a0ef Extract package-manager-specs from atom-specs 2014-09-24 14:34:28 -06:00
Nathan Sobo 09b5ac887a Return whether a dispatched command matched a listener 2014-09-24 14:34:28 -06:00
Nathan Sobo 67ff8f4382 Don’t clear commands after specs
Commands are typically registered once at eval time. Clearing them
means that commands aren’t available except in the first spec.
2014-09-24 14:34:27 -06:00
Nathan Sobo 0c9fd46030 Add CommandRegistry::dispatch for tests 2014-09-24 14:34:27 -06:00
Nathan Sobo cf4a7c22ee Upgrade command-palette for spec fixes 2014-09-24 14:33:37 -06:00
Kevin Sawicki 30f04360dd Prepare 0.132 2014-09-24 11:03:20 -07:00
Kevin Sawicki 02d34b3ba9 Use .ico file from repo 2014-09-22 17:25:17 -07:00
Kevin Sawicki 69217b2d8f Use .ico file from tag 2014-09-22 17:24:17 -07:00
Kevin Sawicki 1dc5593380 📝 Single # in comments 2014-09-22 17:20:38 -07:00
Kevin Sawicki 42e0f83259 Add missing space 2014-09-22 17:18:15 -07:00
Kevin Sawicki 428532cd24 Remove stray if 2014-09-22 17:17:15 -07:00
Kevin Sawicki 7581832658 💄 2014-09-22 17:13:05 -07:00
Kevin Sawicki c61c07f07d Use path.extname 2014-09-22 17:09:55 -07:00
Kevin Sawicki abe7dde205 Use grunt.file.readJSON 2014-09-22 17:07:52 -07:00
Kevin Sawicki 4bc49b82ef 💄 2014-09-22 17:07:00 -07:00
Kevin Sawicki de1fd977e0 Use grunt APIs for read, write, and delete 2014-09-22 17:06:23 -07:00
Paul Betts afce21f37d Merge remote-tracking branch 'origin/master' into squirrel-installer 2014-09-22 11:19:54 -07:00
Paul Betts 5230d040eb Clear the releases dir for now 2014-09-22 10:47:27 -07:00
Paul Betts 1080eb2d11 CI version numbers are Magical(tm) 2014-09-16 16:00:57 -07:00
Paul Betts 246575390a Use ERB templates from Underscore-Plus 2014-09-16 15:41:57 -07:00
Paul Betts bc6c85ceca Sign the installer too 2014-09-16 15:21:44 -07:00
Paul Betts a0b405fe6f Populate atom.nuspec with the current Atom version 2014-09-16 15:16:42 -07:00
Paul Betts 54b89cebcc Merge remote-tracking branch 'origin/master' into squirrel-installer
Conflicts:
	build/Gruntfile.coffee
2014-09-16 14:50:29 -07:00
Paul Betts 7b9b044394 Let's not create an installer unless asked, it takes foreeeeevvvverr 2014-09-03 20:30:15 -07:00
Paul Betts 23cb0eda2f How embarassing 2014-09-03 20:15:28 -07:00
Paul Betts a354d9f880 Add create-installer to default tasks 2014-09-03 20:01:16 -07:00
Paul Betts 7526038f9a Create a task which builds an installer 2014-09-03 20:01:16 -07:00
Paul Betts c0973f8c0f Create the first hack at an installer spec 2014-09-03 19:01:08 -07:00
Paul Betts dededd80dd Add Squirrel.Windows 0.4.92 2014-09-03 16:57:22 -07:00
76 arquivos alterados com 2694 adições e 1207 exclusões
+3 -2
Ver Arquivo
@@ -234,8 +234,9 @@ module.exports = (grunt) ->
ciTasks.push('dump-symbols') if process.platform isnt 'win32'
ciTasks.push('set-version', 'check-licenses', 'lint')
ciTasks.push('mkdeb') if process.platform is 'linux'
ciTasks.push('test') if process.platform isnt 'linux'
ciTasks.push('codesign', 'publish-build')
ciTasks.push('test') if process.platform is 'darwin'
ciTasks.push('codesign')
ciTasks.push('publish-build')
grunt.registerTask('ci', ciTasks)
defaultTasks = ['download-atom-shell', 'build', 'set-version']
+2 -1
Ver Arquivo
@@ -8,7 +8,6 @@
"dependencies": {
"async": "~0.2.9",
"donna": "1.0.1",
"tello": "1.0.3",
"formidable": "~1.0.14",
"fs-plus": "2.x",
"github-releases": "~0.2.0",
@@ -35,6 +34,8 @@
"request": "~2.27.0",
"rimraf": "~2.2.2",
"runas": "~1.0.1",
"tello": "1.0.3",
"temp": "~0.8.1",
"underscore-plus": "1.x",
"unzip": "~0.1.9",
"vm-compatibility-layer": "~0.1.0"
+12 -2
Ver Arquivo
@@ -1,4 +1,5 @@
path = require 'path'
fs = require 'fs-plus'
module.exports = (grunt) ->
{spawn} = require('./task-helpers')(grunt)
@@ -25,12 +26,21 @@ module.exports = (grunt) ->
switch process.platform
when 'darwin'
cmd = 'codesign'
args = ['-f', '-v', '-s', 'Developer ID Application: GitHub', grunt.config.get('atom.shellAppDir')]
args = ['--deep', '--force', '--verbose', '--sign', 'Developer ID Application: GitHub', grunt.config.get('atom.shellAppDir')]
spawn {cmd, args}, (error) -> callback(error)
when 'win32'
spawn {cmd: 'taskkill', args: ['/F', '/IM', 'atom.exe']}, ->
cmd = process.env.JANKY_SIGNTOOL ? 'signtool'
args = [path.join(grunt.config.get('atom.shellAppDir'), 'atom.exe')]
spawn {cmd, args}, (error) -> callback(error)
spawn {cmd, args}, (error) ->
return callback(error) if error?
setupExePath = path.join(grunt.config.get('atom.shellAppDir'), '..', 'Releases', 'setup.exe')
if fs.isFileSync(setupExePath)
args = [setupExePath]
spawn {cmd, args}, (error) -> callback(error)
else
callback()
else
callback()
+41
Ver Arquivo
@@ -0,0 +1,41 @@
fs = require 'fs'
path = require 'path'
_ = require 'underscore-plus'
module.exports = (grunt) ->
{spawn, rm} = require('./task-helpers')(grunt)
grunt.registerTask 'create-installer', 'Create the Windows installer', ->
return unless process.platform is 'win32'
done = @async()
buildDir = grunt.config.get('atom.buildDir')
atomDir = path.join(buildDir, 'Atom')
packageInfo = grunt.file.readJSON(path.join(atomDir, 'resources', 'app', 'package.json'))
inputTemplate = grunt.file.read(path.join('build', 'windows', 'atom.nuspec.erb'))
# NB: Build server has some sort of stamp on the version number
packageInfo.version = packageInfo.version.replace(/-.*$/, '')
targetNuspecPath = path.join(buildDir, 'atom.nuspec')
grunt.file.write(targetNuspecPath, _.template(inputTemplate, packageInfo))
cmd = 'build/windows/nuget.exe'
args = ['pack', targetNuspecPath, '-BasePath', atomDir, '-OutputDirectory', buildDir]
spawn {cmd, args}, (error, result, code) ->
return done(error) if error?
pkgs = pkg for pkg in fs.readdirSync(buildDir) when path.extname(pkg) is '.nupkg'
releasesDir = path.join(buildDir, 'Releases')
# NB: Gonna clear Releases for now, in the future we need to pull down
# the existing version
rm(releasesDir)
cmd = 'build/windows/update.com'
args = ['--releasify', path.join(buildDir, pkgs), '-r', releasesDir, '-g', 'build/windows/install-spinner.gif']
spawn {cmd, args}, (error, result, code) -> done(error)
+6 -1
Ver Arquivo
@@ -3,6 +3,7 @@ path = require 'path'
_ = require 'underscore-plus'
fs = require 'fs-plus'
runas = null
temp = require 'temp'
module.exports = (grunt) ->
{cp, mkdir, rm} = require('./task-helpers')(grunt)
@@ -22,7 +23,11 @@ module.exports = (grunt) ->
else if process.platform is 'darwin'
rm installDir
mkdir path.dirname(installDir)
cp shellAppDir, installDir
tempFolder = temp.path()
mkdir tempFolder
cp shellAppDir, tempFolder
fs.renameSync(tempFolder, installDir)
else
binDir = path.join(installDir, 'bin')
shareDir = path.join(installDir, 'share', 'atom')
Arquivo binário não exibido.
Arquivo binário não exibido.
Arquivo binário não exibido.
Arquivo binário não exibido.
Arquivo binário não exibido.
Arquivo binário não exibido.
+32
Ver Arquivo
@@ -0,0 +1,32 @@
<?xml version="1.0" encoding="utf-8"?>
<package xmlns="http://schemas.microsoft.com/packaging/2010/07/nuspec.xsd">
<metadata>
<id><%= name %></id>
<version><%= version %></version>
<authors>The Atom Community</authors>
<owners>The Atom Community</owners>
<iconUrl>https://raw.githubusercontent.com/atom/atom/master/resources/win/atom.ico</iconUrl>
<requireLicenseAcceptance>false</requireLicenseAcceptance>
<description><%= description %></description>
</metadata>
<files>
<file src="locales\**" target="lib\net45\locales" />
<file src="resources\**" target="lib\net45\resources" />
<file src="*.pak" target="lib\net45" />
<file src="atom.exe" target="lib\net45\atom.exe" />
<file src="atom.exe.gui" target="lib\net45\atom.exe.gui" />
<file src="chromiumcontent.dll" target="lib\net45\chromiumcontent.dll" />
<file src="d3dcompiler_43.dll" target="lib\net45\d3dcompiler_43.dll" />
<file src="ffmpegsumo.dll" target="lib\net45\ffmpegsumo.dll" />
<file src="icudtl.dat" target="lib\net45\icudtl.dat" />
<file src="libEGL.dll" target="lib\net45\libEGL.dll" />
<file src="libGLESv2.dll" target="lib\net45\libGLESv2.dll" />
<file src="LICENSE" target="lib\net45\LICENSE" />
<file src="msvcp120.dll" target="lib\net45\msvcp120.dll" />
<file src="msvcr120.dll" target="lib\net45\msvcr120.dll" />
<file src="vccorlib120.dll" target="lib\net45\vccorlib120.dll" />
<file src="version" target="lib\net45\version" />
<file src="xinput1_3.dll" target="lib\net45\xinput1_3.dll" />
</files>
</package>
Arquivo binário não exibido.

Depois

Largura:  |  Altura:  |  Tamanho: 43 KiB

-9
Ver Arquivo
@@ -48,15 +48,6 @@ but you can programmatically write to it with `atom.config.set`:
atom.config.set("core.showInvisibles", true)
```
You should never mutate the value of a config key, because that would circumvent
the notification of observers. You can however use methods like `pushAtKeyPath`,
`unshiftAtKeyPath`, and `removeAtKeyPath` to manipulate mutable config values.
```coffeescript
atom.config.pushAtKeyPath("core.disabledPackages", "wrap-guide")
atom.config.removeAtKeyPath("core.disabledPackages", "terminal")
```
You can also use `setDefaults`, which will assign default values for keys that
are always overridden by values assigned with `set`. Defaults are not written
out to the the `config.json` file to prevent it from becoming cluttered.
+24
Ver Arquivo
@@ -321,6 +321,29 @@ extensions your grammar supports:
]
```
## Adding Configuration Settings
You can support config settings in your package that are editable in the
settings view. Specify a `config` key in your package main:
```coffeescript
module.exports =
# Your config schema!
config:
someInt:
type: 'integer'
default: 23
minimum: 1
activate: (state) -> # ...
# ...
```
To define the configuration, we use [json schema][json-schema] which allows you
to indicate the type your value should be, its default, etc.
See the [Config API Docs](https://atom.io/docs/api/latest/Config) for more
details specifying your configuration.
## Bundle External Resources
It's common to ship external resources like images and fonts in the package, to
@@ -392,3 +415,4 @@ all the other available commands.
[first-package]: your-first-package.html
[convert-bundle]: converting-a-text-mate-bundle.html
[convert-theme]: converting-a-text-mate-theme.html
[json-schema]: http://json-schema.org/
+9 -5
Ver Arquivo
@@ -8,10 +8,6 @@ module.exports =
Point: Point
Range: Range
Object.defineProperty module.exports, 'Git', get: ->
deprecate "Please require `GitRepository` instead of `Git`: `{GitRepository} = require 'atom'`"
module.exports.GitRepository
# The following classes can't be used from a Task handler and should therefore
# only be exported when not running as a child node process
unless process.env.ATOM_SHELL_INTERNAL_RUN_AS_NODE
@@ -20,7 +16,7 @@ unless process.env.ATOM_SHELL_INTERNAL_RUN_AS_NODE
module.exports.$ = $
module.exports.$$ = $$
module.exports.$$$ = $$$
module.exports.EditorView = require '../src/editor-view'
module.exports.TextEditorView = require '../src/text-editor-view'
module.exports.ScrollView = require '../src/scroll-view'
module.exports.SelectListView = require '../src/select-list-view'
module.exports.Task = require '../src/task'
@@ -29,3 +25,11 @@ unless process.env.ATOM_SHELL_INTERNAL_RUN_AS_NODE
module.exports.Workspace = require '../src/workspace'
module.exports.React = require 'react-atom-fork'
module.exports.Reactionary = require 'reactionary-atom-fork'
Object.defineProperty module.exports, 'Git', get: ->
deprecate "Please require `GitRepository` instead of `Git`: `{GitRepository} = require 'atom'`"
module.exports.GitRepository
Object.defineProperty module.exports, 'EditorView', get: ->
deprecate "Please require `TextEditorView` instead of `EditorView`: `{TextEditorView} = require 'atom'`"
module.exports.TextEditorView
+7
Ver Arquivo
@@ -199,8 +199,15 @@
'.overlayer':
'Undo': 'core:undo'
'Redo': 'core:redo'
'separator1': '-'
'Cut': 'core:cut'
'Copy': 'core:copy'
'Paste': 'core:paste'
'Delete': 'core:delete'
'Select All': 'core:select-all'
'separator2': '-'
'Split Up': 'pane:split-up'
'Split Down': 'pane:split-down'
'Split Left': 'pane:split-left'
'Split Right': 'pane:split-right'
'separator3': '-'
+7
Ver Arquivo
@@ -156,8 +156,15 @@
'.overlayer':
'Undo': 'core:undo'
'Redo': 'core:redo'
'separator1': '-'
'Cut': 'core:cut'
'Copy': 'core:copy'
'Paste': 'core:paste'
'Delete': 'core:delete'
'Select All': 'core:select-all'
'separator2': '-'
'Split Up': 'pane:split-up'
'Split Down': 'pane:split-down'
'Split Left': 'pane:split-left'
'Split Right': 'pane:split-right'
'separator3': '-'
+9 -2
Ver Arquivo
@@ -33,8 +33,8 @@
{ label: '&Undo', command: 'core:undo' }
{ label: '&Redo', command: 'core:redo' }
{ type: 'separator' }
{ label: '&Cut', command: 'core:cut' }
{ label: 'C&opy', command: 'core:copy' }
{ label: 'Cu&t', command: 'core:cut' }
{ label: '&Copy', command: 'core:copy' }
{ label: 'Copy Pat&h', command: 'editor:copy-path' }
{ label: '&Paste', command: 'core:paste' }
{ label: 'Select &All', command: 'core:select-all' }
@@ -174,8 +174,15 @@
'.overlayer':
'Undo': 'core:undo'
'Redo': 'core:redo'
'separator1': '-'
'Cut': 'core:cut'
'Copy': 'core:copy'
'Paste': 'core:paste'
'Delete': 'core:delete'
'Select All': 'core:select-all'
'separator2': '-'
'Split Up': 'pane:split-up'
'Split Down': 'pane:split-down'
'Split Left': 'pane:split-left'
'Split Right': 'pane:split-right'
'separator3': '-'
+12 -12
Ver Arquivo
@@ -1,7 +1,7 @@
{
"name": "atom",
"productName": "Atom",
"version": "0.131.0",
"version": "0.133.0",
"description": "A hackable text editor for the 21st Century.",
"main": "./src/browser/main.js",
"repository": {
@@ -20,7 +20,7 @@
"atomShellVersion": "0.16.2",
"dependencies": {
"async": "0.2.6",
"atom-keymap": "^2.1.3",
"atom-keymap": "^2.2.0",
"bootstrap": "git+https://github.com/atom/bootstrap.git#6af81906189f1747fd6c93479e3d998ebe041372",
"clear-cut": "0.4.0",
"coffee-script": "1.7.0",
@@ -28,7 +28,7 @@
"delegato": "^1",
"emissary": "^1.3.1",
"event-kit": "0.7.2",
"first-mate": "^2.1.2",
"first-mate": "^2.2.0",
"fs-plus": "^2.2.6",
"fstream": "0.1.24",
"fuzzaldrin": "^2.1",
@@ -77,13 +77,13 @@
"autosave": "0.17.0",
"background-tips": "0.17.0",
"bookmarks": "0.28.0",
"bracket-matcher": "0.59.0",
"command-palette": "0.25.0",
"bracket-matcher": "0.61.0",
"command-palette": "0.26.0",
"deprecation-cop": "0.10.0",
"dev-live-reload": "0.34.0",
"exception-reporting": "0.20.0",
"feedback": "0.33.0",
"find-and-replace": "0.138.0",
"find-and-replace": "0.139.0",
"fuzzy-finder": "0.58.0",
"git-diff": "0.39.0",
"go-to-line": "0.25.0",
@@ -93,25 +93,25 @@
"keybinding-resolver": "0.20.0",
"link": "0.25.0",
"markdown-preview": "0.103.0",
"metrics": "0.34.0",
"metrics": "0.36.0",
"open-on-github": "0.30.0",
"package-generator": "0.31.0",
"release-notes": "0.36.0",
"settings-view": "0.145.0",
"settings-view": "0.148.0",
"snippets": "0.53.0",
"spell-check": "0.42.0",
"status-bar": "0.45.0",
"styleguide": "0.30.0",
"symbols-view": "0.66.0",
"tabs": "0.52.0",
"tabs": "0.54.0",
"timecop": "0.22.0",
"tree-view": "0.126.0",
"tree-view": "0.127.0",
"update-package-dependencies": "0.6.0",
"welcome": "0.18.0",
"whitespace": "0.25.0",
"wrap-guide": "0.22.0",
"language-c": "0.28.0",
"language-coffee-script": "0.34.0",
"language-coffee-script": "0.35.0",
"language-css": "0.17.0",
"language-gfm": "0.50.0",
"language-git": "0.9.0",
@@ -131,7 +131,7 @@
"language-python": "0.19.0",
"language-ruby": "0.38.0",
"language-ruby-on-rails": "0.18.0",
"language-sass": "0.21.0",
"language-sass": "0.22.0",
"language-shellscript": "0.8.0",
"language-source": "0.8.0",
"language-sql": "0.11.0",
+3
Ver Arquivo
@@ -76,6 +76,9 @@ class AtomReporter extends View
@addSpecs(specs)
$(document.body).append this
@on 'click', '.stack-trace', ->
$(this).toggleClass('expanded')
reportRunnerResults: (runner) ->
@updateSpecCounts()
@status.addClass('alert-success').removeClass('alert-info') if @failedCount is 0
+5 -535
Ver Arquivo
@@ -25,541 +25,6 @@ describe "the `atom` global", ->
atom.setSize(100, 400)
expect(atom.getSize()).toEqual width: 100, height: 400
describe "package lifecycle methods", ->
describe ".loadPackage(name)", ->
it "continues if the package has an invalid package.json", ->
spyOn(console, 'warn')
atom.config.set("core.disabledPackages", [])
expect(-> atom.packages.loadPackage("package-with-broken-package-json")).not.toThrow()
it "continues if the package has an invalid keymap", ->
atom.config.set("core.disabledPackages", [])
expect(-> atom.packages.loadPackage("package-with-broken-keymap")).not.toThrow()
describe ".unloadPackage(name)", ->
describe "when the package is active", ->
it "throws an error", ->
pack = null
waitsForPromise ->
atom.packages.activatePackage('package-with-main').then (p) -> pack = p
runs ->
expect(atom.packages.isPackageLoaded(pack.name)).toBeTruthy()
expect(atom.packages.isPackageActive(pack.name)).toBeTruthy()
expect( -> atom.packages.unloadPackage(pack.name)).toThrow()
expect(atom.packages.isPackageLoaded(pack.name)).toBeTruthy()
expect(atom.packages.isPackageActive(pack.name)).toBeTruthy()
describe "when the package is not loaded", ->
it "throws an error", ->
expect(atom.packages.isPackageLoaded('unloaded')).toBeFalsy()
expect( -> atom.packages.unloadPackage('unloaded')).toThrow()
expect(atom.packages.isPackageLoaded('unloaded')).toBeFalsy()
describe "when the package is loaded", ->
it "no longers reports it as being loaded", ->
pack = atom.packages.loadPackage('package-with-main')
expect(atom.packages.isPackageLoaded(pack.name)).toBeTruthy()
atom.packages.unloadPackage(pack.name)
expect(atom.packages.isPackageLoaded(pack.name)).toBeFalsy()
describe ".activatePackage(id)", ->
describe "atom packages", ->
describe "when called multiple times", ->
it "it only calls activate on the package once", ->
spyOn(Package.prototype, 'activateNow').andCallThrough()
atom.packages.activatePackage('package-with-index')
atom.packages.activatePackage('package-with-index')
waitsForPromise ->
atom.packages.activatePackage('package-with-index')
runs ->
expect(Package.prototype.activateNow.callCount).toBe 1
describe "when the package has a main module", ->
describe "when the metadata specifies a main module path˜", ->
it "requires the module at the specified path", ->
mainModule = require('./fixtures/packages/package-with-main/main-module')
spyOn(mainModule, 'activate')
pack = null
waitsForPromise ->
atom.packages.activatePackage('package-with-main').then (p) -> pack = p
runs ->
expect(mainModule.activate).toHaveBeenCalled()
expect(pack.mainModule).toBe mainModule
describe "when the metadata does not specify a main module", ->
it "requires index.coffee", ->
indexModule = require('./fixtures/packages/package-with-index/index')
spyOn(indexModule, 'activate')
pack = null
waitsForPromise ->
atom.packages.activatePackage('package-with-index').then (p) -> pack = p
runs ->
expect(indexModule.activate).toHaveBeenCalled()
expect(pack.mainModule).toBe indexModule
it "assigns config defaults from the module", ->
expect(atom.config.get('package-with-config-defaults.numbers.one')).toBeUndefined()
waitsForPromise ->
atom.packages.activatePackage('package-with-config-defaults')
runs ->
expect(atom.config.get('package-with-config-defaults.numbers.one')).toBe 1
expect(atom.config.get('package-with-config-defaults.numbers.two')).toBe 2
describe "when the package metadata includes activation events", ->
[mainModule, promise] = []
beforeEach ->
mainModule = require './fixtures/packages/package-with-activation-events/index'
spyOn(mainModule, 'activate').andCallThrough()
spyOn(Package.prototype, 'requireMainModule').andCallThrough()
promise = atom.packages.activatePackage('package-with-activation-events')
it "defers requiring/activating the main module until an activation event bubbles to the root view", ->
expect(promise.isFulfilled()).not.toBeTruthy()
atom.workspaceView.trigger 'activation-event'
waitsForPromise ->
promise
it "triggers the activation event on all handlers registered during activation", ->
waitsForPromise ->
atom.workspaceView.open()
runs ->
editorView = atom.workspaceView.getActiveView()
eventHandler = jasmine.createSpy("activation-event")
editorView.command 'activation-event', eventHandler
editorView.trigger 'activation-event'
expect(mainModule.activate.callCount).toBe 1
expect(mainModule.activationEventCallCount).toBe 1
expect(eventHandler.callCount).toBe 1
editorView.trigger 'activation-event'
expect(mainModule.activationEventCallCount).toBe 2
expect(eventHandler.callCount).toBe 2
expect(mainModule.activate.callCount).toBe 1
it "activates the package immediately when the events are empty", ->
mainModule = require './fixtures/packages/package-with-empty-activation-events/index'
spyOn(mainModule, 'activate').andCallThrough()
waitsForPromise ->
atom.packages.activatePackage('package-with-empty-activation-events')
runs ->
expect(mainModule.activate.callCount).toBe 1
describe "when the package has no main module", ->
it "does not throw an exception", ->
spyOn(console, "error")
spyOn(console, "warn").andCallThrough()
expect(-> atom.packages.activatePackage('package-without-module')).not.toThrow()
expect(console.error).not.toHaveBeenCalled()
expect(console.warn).not.toHaveBeenCalled()
it "passes the activate method the package's previously serialized state if it exists", ->
pack = null
waitsForPromise ->
atom.packages.activatePackage("package-with-serialization").then (p) -> pack = p
runs ->
expect(pack.mainModule.someNumber).not.toBe 77
pack.mainModule.someNumber = 77
atom.packages.deactivatePackage("package-with-serialization")
spyOn(pack.mainModule, 'activate').andCallThrough()
atom.packages.activatePackage("package-with-serialization")
expect(pack.mainModule.activate).toHaveBeenCalledWith({someNumber: 77})
it "logs warning instead of throwing an exception if the package fails to load", ->
atom.config.set("core.disabledPackages", [])
spyOn(console, "warn")
expect(-> atom.packages.activatePackage("package-that-throws-an-exception")).not.toThrow()
expect(console.warn).toHaveBeenCalled()
describe "keymap loading", ->
describe "when the metadata does not contain a 'keymaps' manifest", ->
it "loads all the .cson/.json files in the keymaps directory", ->
element1 = $$ -> @div class: 'test-1'
element2 = $$ -> @div class: 'test-2'
element3 = $$ -> @div class: 'test-3'
expect(atom.keymaps.findKeyBindings(keystrokes:'ctrl-z', target:element1[0])).toHaveLength 0
expect(atom.keymaps.findKeyBindings(keystrokes:'ctrl-z', target:element2[0])).toHaveLength 0
expect(atom.keymaps.findKeyBindings(keystrokes:'ctrl-z', target:element3[0])).toHaveLength 0
atom.packages.activatePackage("package-with-keymaps")
expect(atom.keymaps.findKeyBindings(keystrokes:'ctrl-z', target:element1[0])[0].command).toBe "test-1"
expect(atom.keymaps.findKeyBindings(keystrokes:'ctrl-z', target:element2[0])[0].command).toBe "test-2"
expect(atom.keymaps.findKeyBindings(keystrokes:'ctrl-z', target:element3[0])).toHaveLength 0
describe "when the metadata contains a 'keymaps' manifest", ->
it "loads only the keymaps specified by the manifest, in the specified order", ->
element1 = $$ -> @div class: 'test-1'
element3 = $$ -> @div class: 'test-3'
expect(atom.keymaps.findKeyBindings(keystrokes:'ctrl-z', target:element1[0])).toHaveLength 0
atom.packages.activatePackage("package-with-keymaps-manifest")
expect(atom.keymaps.findKeyBindings(keystrokes:'ctrl-z', target:element1[0])[0].command).toBe 'keymap-1'
expect(atom.keymaps.findKeyBindings(keystrokes:'ctrl-n', target:element1[0])[0].command).toBe 'keymap-2'
expect(atom.keymaps.findKeyBindings(keystrokes:'ctrl-y', target:element3[0])).toHaveLength 0
describe "menu loading", ->
beforeEach ->
atom.contextMenu.definitions = []
atom.menu.template = []
describe "when the metadata does not contain a 'menus' manifest", ->
it "loads all the .cson/.json files in the menus directory", ->
element = ($$ -> @div class: 'test-1')[0]
expect(atom.contextMenu.definitionsForElement(element)).toEqual []
atom.packages.activatePackage("package-with-menus")
expect(atom.menu.template.length).toBe 2
expect(atom.menu.template[0].label).toBe "Second to Last"
expect(atom.menu.template[1].label).toBe "Last"
expect(atom.contextMenu.definitionsForElement(element)[0].label).toBe "Menu item 1"
expect(atom.contextMenu.definitionsForElement(element)[1].label).toBe "Menu item 2"
expect(atom.contextMenu.definitionsForElement(element)[2].label).toBe "Menu item 3"
describe "when the metadata contains a 'menus' manifest", ->
it "loads only the menus specified by the manifest, in the specified order", ->
element = ($$ -> @div class: 'test-1')[0]
expect(atom.contextMenu.definitionsForElement(element)).toEqual []
atom.packages.activatePackage("package-with-menus-manifest")
expect(atom.menu.template[0].label).toBe "Second to Last"
expect(atom.menu.template[1].label).toBe "Last"
expect(atom.contextMenu.definitionsForElement(element)[0].label).toBe "Menu item 2"
expect(atom.contextMenu.definitionsForElement(element)[1].label).toBe "Menu item 1"
expect(atom.contextMenu.definitionsForElement(element)[2]).toBeUndefined()
describe "stylesheet loading", ->
describe "when the metadata contains a 'stylesheets' manifest", ->
it "loads stylesheets from the stylesheets directory as specified by the manifest", ->
one = require.resolve("./fixtures/packages/package-with-stylesheets-manifest/stylesheets/1.css")
two = require.resolve("./fixtures/packages/package-with-stylesheets-manifest/stylesheets/2.less")
three = require.resolve("./fixtures/packages/package-with-stylesheets-manifest/stylesheets/3.css")
one = atom.themes.stringToId(one)
two = atom.themes.stringToId(two)
three = atom.themes.stringToId(three)
expect(atom.themes.stylesheetElementForId(one)).toBeNull()
expect(atom.themes.stylesheetElementForId(two)).toBeNull()
expect(atom.themes.stylesheetElementForId(three)).toBeNull()
atom.packages.activatePackage("package-with-stylesheets-manifest")
expect(atom.themes.stylesheetElementForId(one)).not.toBeNull()
expect(atom.themes.stylesheetElementForId(two)).not.toBeNull()
expect(atom.themes.stylesheetElementForId(three)).toBeNull()
expect($('#jasmine-content').css('font-size')).toBe '1px'
describe "when the metadata does not contain a 'stylesheets' manifest", ->
it "loads all stylesheets from the stylesheets directory", ->
one = require.resolve("./fixtures/packages/package-with-stylesheets/stylesheets/1.css")
two = require.resolve("./fixtures/packages/package-with-stylesheets/stylesheets/2.less")
three = require.resolve("./fixtures/packages/package-with-stylesheets/stylesheets/3.css")
one = atom.themes.stringToId(one)
two = atom.themes.stringToId(two)
three = atom.themes.stringToId(three)
expect(atom.themes.stylesheetElementForId(one)).toBeNull()
expect(atom.themes.stylesheetElementForId(two)).toBeNull()
expect(atom.themes.stylesheetElementForId(three)).toBeNull()
atom.packages.activatePackage("package-with-stylesheets")
expect(atom.themes.stylesheetElementForId(one)).not.toBeNull()
expect(atom.themes.stylesheetElementForId(two)).not.toBeNull()
expect(atom.themes.stylesheetElementForId(three)).not.toBeNull()
expect($('#jasmine-content').css('font-size')).toBe '3px'
describe "grammar loading", ->
it "loads the package's grammars", ->
waitsForPromise ->
atom.packages.activatePackage('package-with-grammars')
runs ->
expect(atom.syntax.selectGrammar('a.alot').name).toBe 'Alot'
expect(atom.syntax.selectGrammar('a.alittle').name).toBe 'Alittle'
describe "scoped-property loading", ->
it "loads the scoped properties", ->
waitsForPromise ->
atom.packages.activatePackage("package-with-scoped-properties")
runs ->
expect(atom.syntax.getProperty ['.source.omg'], 'editor.increaseIndentPattern').toBe '^a'
describe "converted textmate packages", ->
it "loads the package's grammars", ->
expect(atom.syntax.selectGrammar("file.rb").name).toBe "Null Grammar"
waitsForPromise ->
atom.packages.activatePackage('language-ruby')
runs ->
expect(atom.syntax.selectGrammar("file.rb").name).toBe "Ruby"
it "loads the translated scoped properties", ->
expect(atom.syntax.getProperty(['.source.ruby'], 'editor.commentStart')).toBeUndefined()
waitsForPromise ->
atom.packages.activatePackage('language-ruby')
runs ->
expect(atom.syntax.getProperty(['.source.ruby'], 'editor.commentStart')).toBe '# '
describe ".deactivatePackage(id)", ->
describe "atom packages", ->
it "calls `deactivate` on the package's main module if activate was successful", ->
pack = null
waitsForPromise ->
atom.packages.activatePackage("package-with-deactivate").then (p) -> pack = p
runs ->
expect(atom.packages.isPackageActive("package-with-deactivate")).toBeTruthy()
spyOn(pack.mainModule, 'deactivate').andCallThrough()
atom.packages.deactivatePackage("package-with-deactivate")
expect(pack.mainModule.deactivate).toHaveBeenCalled()
expect(atom.packages.isPackageActive("package-with-module")).toBeFalsy()
spyOn(console, 'warn')
badPack = null
waitsForPromise ->
atom.packages.activatePackage("package-that-throws-on-activate").then (p) -> badPack = p
runs ->
expect(atom.packages.isPackageActive("package-that-throws-on-activate")).toBeTruthy()
spyOn(badPack.mainModule, 'deactivate').andCallThrough()
atom.packages.deactivatePackage("package-that-throws-on-activate")
expect(badPack.mainModule.deactivate).not.toHaveBeenCalled()
expect(atom.packages.isPackageActive("package-that-throws-on-activate")).toBeFalsy()
it "does not serialize packages that have not been activated called on their main module", ->
spyOn(console, 'warn')
badPack = null
waitsForPromise ->
atom.packages.activatePackage("package-that-throws-on-activate").then (p) -> badPack = p
runs ->
spyOn(badPack.mainModule, 'serialize').andCallThrough()
atom.packages.deactivatePackage("package-that-throws-on-activate")
expect(badPack.mainModule.serialize).not.toHaveBeenCalled()
it "absorbs exceptions that are thrown by the package module's serialize method", ->
spyOn(console, 'error')
waitsForPromise ->
atom.packages.activatePackage('package-with-serialize-error')
waitsForPromise ->
atom.packages.activatePackage('package-with-serialization')
runs ->
atom.packages.deactivatePackages()
expect(atom.packages.packageStates['package-with-serialize-error']).toBeUndefined()
expect(atom.packages.packageStates['package-with-serialization']).toEqual someNumber: 1
expect(console.error).toHaveBeenCalled()
it "absorbs exceptions that are thrown by the package module's deactivate method", ->
spyOn(console, 'error')
waitsForPromise ->
atom.packages.activatePackage("package-that-throws-on-deactivate")
runs ->
expect(-> atom.packages.deactivatePackage("package-that-throws-on-deactivate")).not.toThrow()
expect(console.error).toHaveBeenCalled()
it "removes the package's grammars", ->
waitsForPromise ->
atom.packages.activatePackage('package-with-grammars')
runs ->
atom.packages.deactivatePackage('package-with-grammars')
expect(atom.syntax.selectGrammar('a.alot').name).toBe 'Null Grammar'
expect(atom.syntax.selectGrammar('a.alittle').name).toBe 'Null Grammar'
it "removes the package's keymaps", ->
waitsForPromise ->
atom.packages.activatePackage('package-with-keymaps')
runs ->
atom.packages.deactivatePackage('package-with-keymaps')
expect(atom.keymaps.findKeyBindings(keystrokes:'ctrl-z', target: ($$ -> @div class: 'test-1')[0])).toHaveLength 0
expect(atom.keymaps.findKeyBindings(keystrokes:'ctrl-z', target: ($$ -> @div class: 'test-2')[0])).toHaveLength 0
it "removes the package's stylesheets", ->
waitsForPromise ->
atom.packages.activatePackage('package-with-stylesheets')
runs ->
atom.packages.deactivatePackage('package-with-stylesheets')
one = require.resolve("./fixtures/packages/package-with-stylesheets-manifest/stylesheets/1.css")
two = require.resolve("./fixtures/packages/package-with-stylesheets-manifest/stylesheets/2.less")
three = require.resolve("./fixtures/packages/package-with-stylesheets-manifest/stylesheets/3.css")
expect(atom.themes.stylesheetElementForId(one)).not.toExist()
expect(atom.themes.stylesheetElementForId(two)).not.toExist()
expect(atom.themes.stylesheetElementForId(three)).not.toExist()
it "removes the package's scoped-properties", ->
waitsForPromise ->
atom.packages.activatePackage("package-with-scoped-properties")
runs ->
expect(atom.syntax.getProperty ['.source.omg'], 'editor.increaseIndentPattern').toBe '^a'
atom.packages.deactivatePackage("package-with-scoped-properties")
expect(atom.syntax.getProperty ['.source.omg'], 'editor.increaseIndentPattern').toBeUndefined()
describe "textmate packages", ->
it "removes the package's grammars", ->
expect(atom.syntax.selectGrammar("file.rb").name).toBe "Null Grammar"
waitsForPromise ->
atom.packages.activatePackage('language-ruby')
runs ->
expect(atom.syntax.selectGrammar("file.rb").name).toBe "Ruby"
atom.packages.deactivatePackage('language-ruby')
expect(atom.syntax.selectGrammar("file.rb").name).toBe "Null Grammar"
it "removes the package's scoped properties", ->
waitsForPromise ->
atom.packages.activatePackage('language-ruby')
runs ->
atom.packages.deactivatePackage('language-ruby')
expect(atom.syntax.getProperty(['.source.ruby'], 'editor.commentStart')).toBeUndefined()
describe ".activate()", ->
packageActivator = null
themeActivator = null
beforeEach ->
spyOn(console, 'warn')
atom.packages.loadPackages()
loadedPackages = atom.packages.getLoadedPackages()
expect(loadedPackages.length).toBeGreaterThan 0
packageActivator = spyOn(atom.packages, 'activatePackages')
themeActivator = spyOn(atom.themes, 'activatePackages')
afterEach ->
atom.packages.unloadPackages()
Syntax = require '../src/syntax'
atom.syntax = window.syntax = new Syntax()
it "activates all the packages, and none of the themes", ->
atom.packages.activate()
expect(packageActivator).toHaveBeenCalled()
expect(themeActivator).toHaveBeenCalled()
packages = packageActivator.mostRecentCall.args[0]
expect(['atom', 'textmate']).toContain(pack.getType()) for pack in packages
themes = themeActivator.mostRecentCall.args[0]
expect(['theme']).toContain(theme.getType()) for theme in themes
describe ".enablePackage() and disablePackage()", ->
describe "with packages", ->
it ".enablePackage() enables a disabled package", ->
packageName = 'package-with-main'
atom.config.pushAtKeyPath('core.disabledPackages', packageName)
atom.packages.observeDisabledPackages()
expect(atom.config.get('core.disabledPackages')).toContain packageName
pack = atom.packages.enablePackage(packageName)
loadedPackages = atom.packages.getLoadedPackages()
activatedPackages = null
waitsFor ->
activatedPackages = atom.packages.getActivePackages()
activatedPackages.length > 0
runs ->
expect(loadedPackages).toContain(pack)
expect(activatedPackages).toContain(pack)
expect(atom.config.get('core.disabledPackages')).not.toContain packageName
it ".disablePackage() disables an enabled package", ->
packageName = 'package-with-main'
waitsForPromise ->
atom.packages.activatePackage(packageName)
runs ->
atom.packages.observeDisabledPackages()
expect(atom.config.get('core.disabledPackages')).not.toContain packageName
pack = atom.packages.disablePackage(packageName)
activatedPackages = atom.packages.getActivePackages()
expect(activatedPackages).not.toContain(pack)
expect(atom.config.get('core.disabledPackages')).toContain packageName
describe "with themes", ->
reloadedHandler = null
beforeEach ->
waitsForPromise ->
atom.themes.activateThemes()
afterEach ->
atom.themes.deactivateThemes()
it ".enablePackage() and .disablePackage() enables and disables a theme", ->
packageName = 'theme-with-package-file'
expect(atom.config.get('core.themes')).not.toContain packageName
expect(atom.config.get('core.disabledPackages')).not.toContain packageName
# enabling of theme
pack = atom.packages.enablePackage(packageName)
waitsFor ->
pack in atom.packages.getActivePackages()
runs ->
expect(atom.config.get('core.themes')).toContain packageName
expect(atom.config.get('core.disabledPackages')).not.toContain packageName
reloadedHandler = jasmine.createSpy('reloadedHandler')
reloadedHandler.reset()
atom.themes.onDidReloadAll reloadedHandler
pack = atom.packages.disablePackage(packageName)
waitsFor ->
reloadedHandler.callCount is 1
runs ->
expect(atom.packages.getActivePackages()).not.toContain pack
expect(atom.config.get('core.themes')).not.toContain packageName
expect(atom.config.get('core.themes')).not.toContain packageName
expect(atom.config.get('core.disabledPackages')).not.toContain packageName
describe ".isReleasedVersion()", ->
it "returns false if the version is a SHA and true otherwise", ->
version = '0.1.0'
@@ -582,3 +47,8 @@ describe "the `atom` global", ->
[event, version, notes] = updateAvailableHandler.mostRecentCall.args
expect(notes).toBe 'notes'
expect(version).toBe 'version'
describe "loading default config", ->
it 'loads the default core config', ->
expect(atom.config.get('core.excludeVcsIgnoredPaths')).toBe true
expect(atom.config.get('editor.showInvisibles')).toBe false
+67 -2
Ver Arquivo
@@ -66,8 +66,11 @@ describe "CommandRegistry", ->
registry.add '.child', 'command', -> calls.push('child-2')
registry.add '.child', 'command', (event) -> calls.push('child-1'); event.stopPropagation()
grandchild.dispatchEvent(new CustomEvent('command', bubbles: true))
dispatchedEvent = new CustomEvent('command', bubbles: true)
spyOn(dispatchedEvent, 'stopPropagation')
grandchild.dispatchEvent(dispatchedEvent)
expect(calls).toEqual ['child-1', 'child-2']
expect(dispatchedEvent.stopPropagation).toHaveBeenCalled()
it "stops invoking callbacks when .stopImmediatePropagation() is called on the event", ->
calls = []
@@ -76,8 +79,21 @@ describe "CommandRegistry", ->
registry.add '.child', 'command', -> calls.push('child-2')
registry.add '.child', 'command', (event) -> calls.push('child-1'); event.stopImmediatePropagation()
grandchild.dispatchEvent(new CustomEvent('command', bubbles: true))
dispatchedEvent = new CustomEvent('command', bubbles: true)
spyOn(dispatchedEvent, 'stopImmediatePropagation')
grandchild.dispatchEvent(dispatchedEvent)
expect(calls).toEqual ['child-1']
expect(dispatchedEvent.stopImmediatePropagation).toHaveBeenCalled()
it "forwards .preventDefault() calls from the synthetic event to the original", ->
calls = []
registry.add '.child', 'command', (event) -> event.preventDefault()
dispatchedEvent = new CustomEvent('command', bubbles: true)
spyOn(dispatchedEvent, 'preventDefault')
grandchild.dispatchEvent(dispatchedEvent)
expect(dispatchedEvent.preventDefault).toHaveBeenCalled()
it "allows listeners to be removed via a disposable returned by ::add", ->
calls = []
@@ -124,3 +140,52 @@ describe "CommandRegistry", ->
{name: 'namespace:command-2', displayName: 'Namespace: Command 2'}
{name: 'namespace:command-1', displayName: 'Namespace: Command 1'}
]
describe "::dispatch(target, commandName)", ->
it "simulates invocation of the given command ", ->
called = false
registry.add '.grandchild', 'command', (event) ->
expect(this).toBe grandchild
expect(event.type).toBe 'command'
expect(event.eventPhase).toBe Event.BUBBLING_PHASE
expect(event.target).toBe grandchild
expect(event.currentTarget).toBe grandchild
called = true
registry.dispatch(grandchild, 'command')
expect(called).toBe true
it "returns a boolean indicating whether any listeners matched the command", ->
registry.add '.grandchild', 'command', ->
expect(registry.dispatch(grandchild, 'command')).toBe true
expect(registry.dispatch(grandchild, 'bogus')).toBe false
expect(registry.dispatch(parent, 'command')).toBe false
describe "::getSnapshot and ::restoreSnapshot", ->
it "removes all command handlers except for those in the snapshot", ->
registry.add '.parent', 'namespace:command-1', ->
registry.add '.child', 'namespace:command-2', ->
snapshot = registry.getSnapshot()
registry.add '.grandchild', 'namespace:command-3', ->
expect(registry.findCommands(target: grandchild)[0..2]).toEqual [
{name: 'namespace:command-3', displayName: 'Namespace: Command 3'}
{name: 'namespace:command-2', displayName: 'Namespace: Command 2'}
{name: 'namespace:command-1', displayName: 'Namespace: Command 1'}
]
registry.restoreSnapshot(snapshot)
expect(registry.findCommands(target: grandchild)[0..1]).toEqual [
{name: 'namespace:command-2', displayName: 'Namespace: Command 2'}
{name: 'namespace:command-1', displayName: 'Namespace: Command 1'}
]
registry.add '.grandchild', 'namespace:command-3', ->
registry.restoreSnapshot(snapshot)
expect(registry.findCommands(target: grandchild)[0..1]).toEqual [
{name: 'namespace:command-2', displayName: 'Namespace: Command 2'}
{name: 'namespace:command-1', displayName: 'Namespace: Command 1'}
]
+476 -19
Ver Arquivo
@@ -12,7 +12,7 @@ describe "Config", ->
describe ".get(keyPath)", ->
it "allows a key path's value to be read", ->
expect(atom.config.set("foo.bar.baz", 42)).toBe 42
expect(atom.config.set("foo.bar.baz", 42)).toBe true
expect(atom.config.get("foo.bar.baz")).toBe 42
expect(atom.config.get("bogus.key.path")).toBeUndefined()
@@ -37,7 +37,7 @@ describe "Config", ->
describe ".set(keyPath, value)", ->
it "allows a key path's value to be written", ->
expect(atom.config.set("foo.bar.baz", 42)).toBe 42
expect(atom.config.set("foo.bar.baz", 42)).toBe true
expect(atom.config.get("foo.bar.baz")).toBe 42
it "updates observers and saves when a key path is set", ->
@@ -48,7 +48,7 @@ describe "Config", ->
atom.config.set("foo.bar.baz", 42)
expect(atom.config.save).toHaveBeenCalled()
expect(observeHandler).toHaveBeenCalledWith 42, {previous: undefined}
expect(observeHandler).toHaveBeenCalledWith 42
describe "when the value equals the default value", ->
it "does not store the value", ->
@@ -139,7 +139,7 @@ describe "Config", ->
expect(atom.config.pushAtKeyPath("foo.bar.baz", "b")).toBe 2
expect(atom.config.get("foo.bar.baz")).toEqual ["a", "b"]
expect(observeHandler).toHaveBeenCalledWith atom.config.get("foo.bar.baz"), {previous: ['a']}
expect(observeHandler).toHaveBeenCalledWith atom.config.get("foo.bar.baz")
describe ".unshiftAtKeyPath(keyPath, value)", ->
it "unshifts the given value to the array at the key path and updates observers", ->
@@ -150,7 +150,7 @@ describe "Config", ->
expect(atom.config.unshiftAtKeyPath("foo.bar.baz", "a")).toBe 2
expect(atom.config.get("foo.bar.baz")).toEqual ["a", "b"]
expect(observeHandler).toHaveBeenCalledWith atom.config.get("foo.bar.baz"), {previous: ['b']}
expect(observeHandler).toHaveBeenCalledWith atom.config.get("foo.bar.baz")
describe ".removeAtKeyPath(keyPath, value)", ->
it "removes the given value from the array at the key path and updates observers", ->
@@ -161,16 +161,22 @@ describe "Config", ->
expect(atom.config.removeAtKeyPath("foo.bar.baz", "b")).toEqual ["a", "c"]
expect(atom.config.get("foo.bar.baz")).toEqual ["a", "c"]
expect(observeHandler).toHaveBeenCalledWith atom.config.get("foo.bar.baz"), {previous: ['a', 'b', 'c']}
expect(observeHandler).toHaveBeenCalledWith atom.config.get("foo.bar.baz")
describe ".getPositiveInt(keyPath, defaultValue)", ->
it "returns the proper current or default value", ->
it "returns the proper coerced value", ->
atom.config.set('editor.preferredLineLength', 0)
expect(atom.config.getPositiveInt('editor.preferredLineLength', 80)).toBe 80
expect(atom.config.getPositiveInt('editor.preferredLineLength', 80)).toBe 1
it "returns the proper coerced value", ->
atom.config.set('editor.preferredLineLength', -1234)
expect(atom.config.getPositiveInt('editor.preferredLineLength', 80)).toBe 80
expect(atom.config.getPositiveInt('editor.preferredLineLength', 80)).toBe 1
it "returns the default value when a string is passed in", ->
atom.config.set('editor.preferredLineLength', 'abcd')
expect(atom.config.getPositiveInt('editor.preferredLineLength', 80)).toBe 80
it "returns the default value when null is passed in", ->
atom.config.set('editor.preferredLineLength', null)
expect(atom.config.getPositiveInt('editor.preferredLineLength', 80)).toBe 80
@@ -226,11 +232,54 @@ describe "Config", ->
it "emits an updated event", ->
updatedCallback = jasmine.createSpy('updated')
atom.config.observe('foo.bar.baz.a', callNow: false, updatedCallback)
atom.config.onDidChange('foo.bar.baz.a', updatedCallback)
expect(updatedCallback.callCount).toBe 0
atom.config.setDefaults("foo.bar.baz", a: 2)
expect(updatedCallback.callCount).toBe 1
describe ".onDidChange(keyPath)", ->
[observeHandler, observeSubscription] = []
describe 'when a keyPath is specified', ->
beforeEach ->
observeHandler = jasmine.createSpy("observeHandler")
atom.config.set("foo.bar.baz", "value 1")
observeSubscription = atom.config.onDidChange "foo.bar.baz", observeHandler
it "does not fire the given callback with the current value at the keypath", ->
expect(observeHandler).not.toHaveBeenCalled()
it "fires the callback every time the observed value changes", ->
observeHandler.reset() # clear the initial call
atom.config.set('foo.bar.baz', "value 2")
expect(observeHandler).toHaveBeenCalledWith({newValue: 'value 2', oldValue: 'value 1', keyPath: 'foo.bar.baz'})
observeHandler.reset()
atom.config.set('foo.bar.baz', "value 1")
expect(observeHandler).toHaveBeenCalledWith({newValue: 'value 1', oldValue: 'value 2', keyPath: 'foo.bar.baz'})
describe 'when a keyPath is not specified', ->
beforeEach ->
observeHandler = jasmine.createSpy("observeHandler")
atom.config.set("foo.bar.baz", "value 1")
observeSubscription = atom.config.onDidChange observeHandler
it "does not fire the given callback initially", ->
expect(observeHandler).not.toHaveBeenCalled()
it "fires the callback every time any value changes", ->
observeHandler.reset() # clear the initial call
atom.config.set('foo.bar.baz', "value 2")
expect(observeHandler).toHaveBeenCalledWith({newValue: 'value 2', oldValue: 'value 1', keyPath: 'foo.bar.baz'})
observeHandler.reset()
atom.config.set('foo.bar.baz', "value 1")
expect(observeHandler).toHaveBeenCalledWith({newValue: 'value 1', oldValue: 'value 2', keyPath: 'foo.bar.baz'})
observeHandler.reset()
atom.config.set('foo.bar.int', 1)
expect(observeHandler).toHaveBeenCalledWith({newValue: 1, oldValue: undefined, keyPath: 'foo.bar.int'})
describe ".observe(keyPath)", ->
[observeHandler, observeSubscription] = []
@@ -245,26 +294,25 @@ describe "Config", ->
it "fires the callback every time the observed value changes", ->
observeHandler.reset() # clear the initial call
atom.config.set('foo.bar.baz', "value 2")
expect(observeHandler).toHaveBeenCalledWith("value 2", {previous: 'value 1'})
expect(observeHandler).toHaveBeenCalledWith("value 2")
observeHandler.reset()
atom.config.set('foo.bar.baz', "value 1")
expect(observeHandler).toHaveBeenCalledWith("value 1", {previous: 'value 2'})
expect(observeHandler).toHaveBeenCalledWith("value 1")
it "fires the callback when the observed value is deleted", ->
observeHandler.reset() # clear the initial call
atom.config.set('foo.bar.baz', undefined)
expect(observeHandler).toHaveBeenCalledWith(undefined, {previous: 'value 1'})
expect(observeHandler).toHaveBeenCalledWith(undefined)
it "fires the callback when the full key path goes into and out of existence", ->
observeHandler.reset() # clear the initial call
atom.config.set("foo.bar", undefined)
expect(observeHandler).toHaveBeenCalledWith(undefined)
expect(observeHandler).toHaveBeenCalledWith(undefined, {previous: 'value 1'})
observeHandler.reset()
atom.config.set("foo.bar.baz", "i'm back")
expect(observeHandler).toHaveBeenCalledWith("i'm back", {previous: undefined})
expect(observeHandler).toHaveBeenCalledWith("i'm back")
it "does not fire the callback once the observe subscription is off'ed", ->
observeHandler.reset() # clear the initial call
@@ -311,11 +359,19 @@ describe "Config", ->
describe "when the config file contains valid cson", ->
beforeEach ->
fs.writeFileSync(atom.config.configFilePath, "foo: bar: 'baz'")
atom.config.loadUserConfig()
it "updates the config data based on the file contents", ->
atom.config.loadUserConfig()
expect(atom.config.get("foo.bar")).toBe 'baz'
it "notifies observers for updated keypaths on load", ->
observeHandler = jasmine.createSpy("observeHandler")
observeSubscription = atom.config.observe "foo.bar", observeHandler
atom.config.loadUserConfig()
expect(observeHandler).toHaveBeenCalledWith 'baz'
describe "when the config file contains invalid cson", ->
beforeEach ->
spyOn(console, 'error')
@@ -334,10 +390,43 @@ describe "Config", ->
expect(fs.existsSync(atom.config.configFilePath)).toBe true
expect(CSON.readFileSync(atom.config.configFilePath)).toEqual {}
describe "when a schema is specified", ->
beforeEach ->
schema =
type: 'object'
properties:
bar:
type: 'string'
default: 'def'
int:
type: 'integer'
default: 12
atom.config.setSchema('foo', schema)
describe "when the config file contains values that do not adhere to the schema", ->
warnSpy = null
beforeEach ->
warnSpy = spyOn console, 'warn'
fs.writeFileSync atom.config.configFilePath, """
foo:
bar: 'baz'
int: 'bad value'
"""
atom.config.loadUserConfig()
it "updates the only the settings that have values matching the schema", ->
expect(atom.config.get("foo.bar")).toBe 'baz'
expect(atom.config.get("foo.int")).toBe 12
expect(warnSpy).toHaveBeenCalled()
expect(warnSpy.mostRecentCall.args[0]).toContain "'foo.int' could not be set"
describe ".observeUserConfig()", ->
updatedHandler = null
beforeEach ->
atom.config.setDefaults('foo', bar: 'def')
atom.config.configDirPath = dotAtomPath
atom.config.configFilePath = path.join(atom.config.configDirPath, "atom.config.cson")
expect(fs.existsSync(atom.config.configDirPath)).toBeFalsy()
@@ -345,7 +434,7 @@ describe "Config", ->
atom.config.loadUserConfig()
atom.config.observeUserConfig()
updatedHandler = jasmine.createSpy("updatedHandler")
atom.config.on 'updated', updatedHandler
atom.config.onDidChange updatedHandler
afterEach ->
atom.config.unobserveUserConfig()
@@ -359,6 +448,34 @@ describe "Config", ->
expect(atom.config.get('foo.bar')).toBe 'quux'
expect(atom.config.get('foo.baz')).toBe 'bar'
describe "when the config file changes to omit a setting with a default", ->
it "resets the setting back to the default", ->
fs.writeFileSync(atom.config.configFilePath, "foo: { baz: 'new'}")
waitsFor 'update event', -> updatedHandler.callCount > 0
runs ->
expect(atom.config.get('foo.bar')).toBe 'def'
expect(atom.config.get('foo.baz')).toBe 'new'
describe "when the config file changes to be empty", ->
beforeEach ->
fs.writeFileSync(atom.config.configFilePath, "")
waitsFor 'update event', -> updatedHandler.callCount > 0
it "resets all settings back to the defaults", ->
expect(updatedHandler.callCount).toBe 1
expect(atom.config.get('foo.bar')).toBe 'def'
atom.config.set("hair", "blonde") # trigger a save
expect(atom.config.save).toHaveBeenCalled()
describe "when the config file subsequently changes again to contain configuration", ->
beforeEach ->
updatedHandler.reset()
fs.writeFileSync(atom.config.configFilePath, "foo: bar: 'newVal'")
waitsFor 'update event', -> updatedHandler.callCount > 0
it "sets the setting to the value specified in the config file", ->
expect(atom.config.get('foo.bar')).toBe 'newVal'
describe "when the config file changes to contain invalid cson", ->
beforeEach ->
spyOn(console, 'error')
@@ -373,9 +490,349 @@ describe "Config", ->
describe "when the config file subsequently changes again to contain valid cson", ->
beforeEach ->
fs.writeFileSync(atom.config.configFilePath, "foo: bar: 'baz'")
fs.writeFileSync(atom.config.configFilePath, "foo: bar: 'newVal'")
waitsFor 'update event', -> updatedHandler.callCount > 0
it "updates the config data and resumes saving", ->
atom.config.set("hair", "blonde")
expect(atom.config.save).toHaveBeenCalled()
describe "when a schema is specified", ->
schema = null
describe '.setSchema(keyPath, schema)', ->
it 'creates a properly nested schema', ->
schema =
type: 'object'
properties:
anInt:
type: 'integer'
default: 12
atom.config.setSchema('foo.bar', schema)
expect(atom.config.getSchema('foo')).toEqual
type: 'object'
properties:
bar:
type: 'object'
properties:
anInt:
type: 'integer'
default: 12
it 'sets defaults specified by the schema', ->
schema =
type: 'object'
properties:
anInt:
type: 'integer'
default: 12
anObject:
type: 'object'
properties:
nestedInt:
type: 'integer'
default: 24
nestedObject:
type: 'object'
properties:
superNestedInt:
type: 'integer'
default: 36
atom.config.setSchema('foo.bar', schema)
expect(atom.config.get("foo.bar.anInt")).toBe 12
expect(atom.config.get("foo.bar.anObject")).toEqual
nestedInt: 24
nestedObject:
superNestedInt: 36
it 'can set a non-object schema', ->
schema =
type: 'integer'
default: 12
atom.config.setSchema('foo.bar.anInt', schema)
expect(atom.config.get("foo.bar.anInt")).toBe 12
expect(atom.config.getSchema('foo.bar.anInt')).toEqual
type: 'integer'
default: 12
describe '.getSchema(keyPath)', ->
schema =
type: 'object'
properties:
anInt:
type: 'integer'
default: 12
atom.config.setSchema('foo.bar', schema)
expect(atom.config.getSchema('foo.bar')).toEqual
type: 'object'
properties:
anInt:
type: 'integer'
default: 12
expect(atom.config.getSchema('foo.bar.anInt')).toEqual
type: 'integer'
default: 12
describe 'when the value has an "integer" type', ->
beforeEach ->
schema =
type: 'integer'
default: 12
atom.config.setSchema('foo.bar.anInt', schema)
it 'coerces a string to an int', ->
atom.config.set('foo.bar.anInt', '123')
expect(atom.config.get('foo.bar.anInt')).toBe 123
it 'does not allow infinity', ->
atom.config.set('foo.bar.anInt', Infinity)
expect(atom.config.get('foo.bar.anInt')).toBe 12
it 'coerces a float to an int', ->
atom.config.set('foo.bar.anInt', 12.3)
expect(atom.config.get('foo.bar.anInt')).toBe 12
it 'will not set non-integers', ->
atom.config.set('foo.bar.anInt', null)
expect(atom.config.get('foo.bar.anInt')).toBe 12
atom.config.set('foo.bar.anInt', 'nope')
expect(atom.config.get('foo.bar.anInt')).toBe 12
describe 'when the minimum and maximum keys are used', ->
beforeEach ->
schema =
type: 'integer'
minimum: 10
maximum: 20
default: 12
atom.config.setSchema('foo.bar.anInt', schema)
it 'keeps the specified value within the specified range', ->
atom.config.set('foo.bar.anInt', '123')
expect(atom.config.get('foo.bar.anInt')).toBe 20
atom.config.set('foo.bar.anInt', '1')
expect(atom.config.get('foo.bar.anInt')).toBe 10
describe 'when the value has an "integer" and "string" type', ->
beforeEach ->
schema =
type: ['integer', 'string']
default: 12
atom.config.setSchema('foo.bar.anInt', schema)
it 'can coerce an int, and fallback to a string', ->
atom.config.set('foo.bar.anInt', '123')
expect(atom.config.get('foo.bar.anInt')).toBe 123
atom.config.set('foo.bar.anInt', 'cats')
expect(atom.config.get('foo.bar.anInt')).toBe 'cats'
describe 'when the value has an "string" and "boolean" type', ->
beforeEach ->
schema =
type: ['string', 'boolean']
default: 'def'
atom.config.setSchema('foo.bar', schema)
it 'can set a string, a boolean, and revert back to the default', ->
atom.config.set('foo.bar', 'ok')
expect(atom.config.get('foo.bar')).toBe 'ok'
atom.config.set('foo.bar', false)
expect(atom.config.get('foo.bar')).toBe false
atom.config.set('foo.bar', undefined)
expect(atom.config.get('foo.bar')).toBe 'def'
describe 'when the value has a "number" type', ->
beforeEach ->
schema =
type: 'number'
default: 12.1
atom.config.setSchema('foo.bar.aFloat', schema)
it 'coerces a string to a float', ->
atom.config.set('foo.bar.aFloat', '12.23')
expect(atom.config.get('foo.bar.aFloat')).toBe 12.23
it 'will not set non-numbers', ->
atom.config.set('foo.bar.aFloat', null)
expect(atom.config.get('foo.bar.aFloat')).toBe 12.1
atom.config.set('foo.bar.aFloat', 'nope')
expect(atom.config.get('foo.bar.aFloat')).toBe 12.1
describe 'when the minimum and maximum keys are used', ->
beforeEach ->
schema =
type: 'number'
minimum: 11.2
maximum: 25.4
default: 12.1
atom.config.setSchema('foo.bar.aFloat', schema)
it 'keeps the specified value within the specified range', ->
atom.config.set('foo.bar.aFloat', '123.2')
expect(atom.config.get('foo.bar.aFloat')).toBe 25.4
atom.config.set('foo.bar.aFloat', '1.0')
expect(atom.config.get('foo.bar.aFloat')).toBe 11.2
describe 'when the value has a "boolean" type', ->
beforeEach ->
schema =
type: 'boolean'
default: true
atom.config.setSchema('foo.bar.aBool', schema)
it 'coerces various types to a boolean', ->
atom.config.set('foo.bar.aBool', 'true')
expect(atom.config.get('foo.bar.aBool')).toBe true
atom.config.set('foo.bar.aBool', 'false')
expect(atom.config.get('foo.bar.aBool')).toBe false
atom.config.set('foo.bar.aBool', 'TRUE')
expect(atom.config.get('foo.bar.aBool')).toBe true
atom.config.set('foo.bar.aBool', 'FALSE')
expect(atom.config.get('foo.bar.aBool')).toBe false
atom.config.set('foo.bar.aBool', 1)
expect(atom.config.get('foo.bar.aBool')).toBe false
atom.config.set('foo.bar.aBool', 0)
expect(atom.config.get('foo.bar.aBool')).toBe false
atom.config.set('foo.bar.aBool', {})
expect(atom.config.get('foo.bar.aBool')).toBe false
atom.config.set('foo.bar.aBool', null)
expect(atom.config.get('foo.bar.aBool')).toBe false
it 'reverts back to the default value when undefined is passed to set', ->
atom.config.set('foo.bar.aBool', 'false')
expect(atom.config.get('foo.bar.aBool')).toBe false
atom.config.set('foo.bar.aBool', undefined)
expect(atom.config.get('foo.bar.aBool')).toBe true
describe 'when the value has an "string" type', ->
beforeEach ->
schema =
type: 'string'
default: 'ok'
atom.config.setSchema('foo.bar.aString', schema)
it 'allows strings', ->
atom.config.set('foo.bar.aString', 'yep')
expect(atom.config.get('foo.bar.aString')).toBe 'yep'
it 'will only set strings', ->
expect(atom.config.set('foo.bar.aString', 123)).toBe false
expect(atom.config.get('foo.bar.aString')).toBe 'ok'
expect(atom.config.set('foo.bar.aString', true)).toBe false
expect(atom.config.get('foo.bar.aString')).toBe 'ok'
expect(atom.config.set('foo.bar.aString', null)).toBe false
expect(atom.config.get('foo.bar.aString')).toBe 'ok'
expect(atom.config.set('foo.bar.aString', [])).toBe false
expect(atom.config.get('foo.bar.aString')).toBe 'ok'
expect(atom.config.set('foo.bar.aString', nope: 'nope')).toBe false
expect(atom.config.get('foo.bar.aString')).toBe 'ok'
describe 'when the value has an "object" type', ->
beforeEach ->
schema =
type: 'object'
properties:
anInt:
type: 'integer'
default: 12
nestedObject:
type: 'object'
properties:
nestedBool:
type: 'boolean'
default: false
atom.config.setSchema('foo.bar', schema)
it 'converts and validates all the children', ->
atom.config.set 'foo.bar',
anInt: '23'
nestedObject:
nestedBool: 'true'
expect(atom.config.get('foo.bar')).toEqual
anInt: 23
nestedObject:
nestedBool: true
it 'will set only the values that adhere to the schema', ->
expect(atom.config.set 'foo.bar',
anInt: 'nope'
nestedObject:
nestedBool: true
).toBe true
expect(atom.config.get('foo.bar.anInt')).toEqual 12
expect(atom.config.get('foo.bar.nestedObject.nestedBool')).toEqual true
describe 'when the value has an "array" type', ->
beforeEach ->
schema =
type: 'array'
default: [1, 2, 3]
items:
type: 'integer'
atom.config.setSchema('foo.bar', schema)
it 'converts an array of strings to an array of ints', ->
atom.config.set 'foo.bar', ['2', '3', '4']
expect(atom.config.get('foo.bar')).toEqual [2, 3, 4]
describe 'when the `enum` key is used', ->
beforeEach ->
schema =
type: 'object'
properties:
str:
type: 'string'
default: 'ok'
enum: ['ok', 'one', 'two']
int:
type: 'integer'
default: 2
enum: [2, 3, 5]
arr:
type: 'array'
default: ['one', 'two']
items:
type: 'string'
enum: ['one', 'two', 'three']
atom.config.setSchema('foo.bar', schema)
it 'will only set a string when the string is in the enum values', ->
expect(atom.config.set('foo.bar.str', 'nope')).toBe false
expect(atom.config.get('foo.bar.str')).toBe 'ok'
expect(atom.config.set('foo.bar.str', 'one')).toBe true
expect(atom.config.get('foo.bar.str')).toBe 'one'
it 'will only set an integer when the integer is in the enum values', ->
expect(atom.config.set('foo.bar.int', '400')).toBe false
expect(atom.config.get('foo.bar.int')).toBe 2
expect(atom.config.set('foo.bar.int', '3')).toBe true
expect(atom.config.get('foo.bar.int')).toBe 3
it 'will only set an array when the array values are in the enum values', ->
expect(atom.config.set('foo.bar.arr', ['one', 'five'])).toBe true
expect(atom.config.get('foo.bar.arr')).toEqual ['one']
expect(atom.config.set('foo.bar.arr', ['two', 'three'])).toBe true
expect(atom.config.get('foo.bar.arr')).toEqual ['two', 'three']
+31 -20
Ver Arquivo
@@ -1,33 +1,44 @@
DeserializerManager = require '../src/deserializer-manager'
describe ".deserialize(state)", ->
deserializer = null
describe "DeserializerManager", ->
manager = null
class Foo
@deserialize: ({name}) -> new Foo(name)
constructor: (@name) ->
beforeEach ->
deserializer = new DeserializerManager()
deserializer.add(Foo)
manager = new DeserializerManager
it "calls deserialize on the deserializer for the given state object, or returns undefined if one can't be found", ->
spyOn(console, 'warn')
object = deserializer.deserialize({ deserializer: 'Foo', name: 'Bar' })
expect(object.name).toBe 'Bar'
expect(deserializer.deserialize({ deserializer: 'Bogus' })).toBeUndefined()
describe "::add(deserializer)", ->
it "returns a disposable that can be used to remove the manager", ->
disposable = manager.add(Foo)
expect(manager.deserialize({deserializer: 'Foo', name: 'Bar'})).toBeDefined()
disposable.dispose()
spyOn(console, 'warn')
expect(manager.deserialize({deserializer: 'Foo', name: 'Bar'})).toBeUndefined()
describe "when the deserializer has a version", ->
describe "::deserialize(state)", ->
beforeEach ->
Foo.version = 2
manager.add(Foo)
describe "when the deserialized state has a matching version", ->
it "attempts to deserialize the state", ->
object = deserializer.deserialize({ deserializer: 'Foo', version: 2, name: 'Bar' })
expect(object.name).toBe 'Bar'
it "calls deserialize on the manager for the given state object, or returns undefined if one can't be found", ->
spyOn(console, 'warn')
object = manager.deserialize({deserializer: 'Foo', name: 'Bar'})
expect(object.name).toBe 'Bar'
expect(manager.deserialize({deserializer: 'Bogus'})).toBeUndefined()
describe "when the deserialized state has a non-matching version", ->
it "returns undefined", ->
expect(deserializer.deserialize({ deserializer: 'Foo', version: 3, name: 'Bar' })).toBeUndefined()
expect(deserializer.deserialize({ deserializer: 'Foo', version: 1, name: 'Bar' })).toBeUndefined()
expect(deserializer.deserialize({ deserializer: 'Foo', name: 'Bar' })).toBeUndefined()
describe "when the manager has a version", ->
beforeEach ->
Foo.version = 2
describe "when the deserialized state has a matching version", ->
it "attempts to deserialize the state", ->
object = manager.deserialize({deserializer: 'Foo', version: 2, name: 'Bar'})
expect(object.name).toBe 'Bar'
describe "when the deserialized state has a non-matching version", ->
it "returns undefined", ->
expect(manager.deserialize({deserializer: 'Foo', version: 3, name: 'Bar'})).toBeUndefined()
expect(manager.deserialize({deserializer: 'Foo', version: 1, name: 'Bar'})).toBeUndefined()
expect(manager.deserialize({deserializer: 'Foo', name: 'Bar'})).toBeUndefined()
+27
Ver Arquivo
@@ -1100,6 +1100,33 @@ describe "DisplayBuffer", ->
expect(displayBuffer.setScrollTop(maxScrollTop + 50)).toBe maxScrollTop
expect(displayBuffer.getScrollTop()).toBe maxScrollTop
describe "editor.scrollPastEnd", ->
describe "when editor.scrollPastEnd is false", ->
beforeEach ->
atom.config.set("editor.scrollPastEnd", false)
displayBuffer.manageScrollPosition = true
displayBuffer.setLineHeightInPixels(10)
it "does not add the height of the view to the scroll height", ->
lineHeight = displayBuffer.getLineHeightInPixels()
originalScrollHeight = displayBuffer.getScrollHeight()
displayBuffer.setHeight(50)
expect(displayBuffer.getScrollHeight()).toBe originalScrollHeight
describe "when editor.scrollPastEnd is true", ->
beforeEach ->
atom.config.set("editor.scrollPastEnd", true)
displayBuffer.manageScrollPosition = true
displayBuffer.setLineHeightInPixels(10)
it "adds the height of the view to the scroll height", ->
lineHeight = displayBuffer.getLineHeightInPixels()
originalScrollHeight = displayBuffer.getScrollHeight()
displayBuffer.setHeight(50)
expect(displayBuffer.getScrollHeight()).toEqual(originalScrollHeight + displayBuffer.height - (lineHeight * 3))
describe "::setScrollLeft", ->
beforeEach ->
displayBuffer.manageScrollPosition = true
@@ -0,0 +1,13 @@
module.exports =
activateCallCount: 0
activationCommandCallCount: 0
legacyActivationCommandCallCount: 0
activate: ->
@activateCallCount++
atom.commands.add '.workspace', 'activation-command', =>
@activationCommandCallCount++
atom.workspaceView.getActiveView()?.command 'activation-command', =>
@legacyActivationCommandCallCount++
@@ -0,0 +1,2 @@
'activationCommands':
'.workspace': 'activation-command'
@@ -1,13 +0,0 @@
class Foo
atom.deserializers.add(this)
@deserialize: ({data}) -> new Foo(data)
constructor: (@data) ->
module.exports =
activateCallCount: 0
activationEventCallCount: 0
activate: ->
@activateCallCount++
atom.workspaceView.getActiveView()?.command 'activation-event', =>
@activationEventCallCount++
@@ -1 +0,0 @@
'activationEvents': ['activation-event']
@@ -0,0 +1,13 @@
module.exports =
config:
numbers:
type: 'object'
properties:
one:
type: 'integer'
default: 1
two:
type: 'integer'
default: 2
activate: -> # no-op
@@ -1,5 +1,5 @@
{
"name": "no events",
"version": "0.1.0",
"activationEvents": []
"activationCommands": {".workspace": []}
}
+32
Ver Arquivo
@@ -14,6 +14,10 @@ describe "LanguageMode", ->
waitsForPromise ->
atom.packages.activatePackage('language-javascript')
afterEach ->
atom.packages.deactivatePackages()
atom.packages.unloadPackages()
describe ".minIndentLevelForRowRange(startRow, endRow)", ->
it "returns the minimum indent level for the given row range", ->
expect(languageMode.minIndentLevelForRowRange(4, 7)).toBe 2
@@ -149,6 +153,10 @@ describe "LanguageMode", ->
waitsForPromise ->
atom.packages.activatePackage('language-coffee-script')
afterEach ->
atom.packages.deactivatePackages()
atom.packages.unloadPackages()
describe ".toggleLineCommentsForBufferRows(start, end)", ->
it "comments/uncomments lines in the given range", ->
languageMode.toggleLineCommentsForBufferRows(4, 6)
@@ -200,6 +208,10 @@ describe "LanguageMode", ->
waitsForPromise ->
atom.packages.activatePackage('language-css')
afterEach ->
atom.packages.deactivatePackages()
atom.packages.unloadPackages()
describe ".toggleLineCommentsForBufferRows(start, end)", ->
it "comments/uncomments lines in the given range", ->
languageMode.toggleLineCommentsForBufferRows(0, 1)
@@ -248,6 +260,10 @@ describe "LanguageMode", ->
waitsForPromise ->
atom.packages.activatePackage('language-css')
afterEach ->
atom.packages.deactivatePackages()
atom.packages.unloadPackages()
describe "when commenting lines", ->
it "only uses the `commentEnd` pattern if it comes from the same grammar as the `commentStart`", ->
languageMode.toggleLineCommentsForBufferRows(0, 0)
@@ -264,6 +280,10 @@ describe "LanguageMode", ->
waitsForPromise ->
atom.packages.activatePackage('language-xml')
afterEach ->
atom.packages.deactivatePackages()
atom.packages.unloadPackages()
describe "when uncommenting lines", ->
it "removes the leading whitespace from the comment end pattern match", ->
languageMode.toggleLineCommentsForBufferRows(0, 0)
@@ -279,6 +299,10 @@ describe "LanguageMode", ->
waitsForPromise ->
atom.packages.activatePackage('language-javascript')
afterEach ->
atom.packages.deactivatePackages()
atom.packages.unloadPackages()
it "maintains cursor buffer position when a folding/unfolding", ->
editor.setCursorBufferPosition([5,5])
languageMode.foldAll()
@@ -366,6 +390,10 @@ describe "LanguageMode", ->
waitsForPromise ->
atom.packages.activatePackage('language-javascript')
afterEach ->
atom.packages.deactivatePackages()
atom.packages.unloadPackages()
describe ".unfoldAll()", ->
it "unfolds every folded line", ->
initialScreenLineCount = editor.getScreenLineCount()
@@ -435,6 +463,10 @@ describe "LanguageMode", ->
atom.packages.activatePackage('language-source')
atom.packages.activatePackage('language-css')
afterEach ->
atom.packages.deactivatePackages()
atom.packages.unloadPackages()
describe "suggestedIndentForBufferRow", ->
it "does not return negative values (regression)", ->
editor.setText('.test {\npadding: 0;\n}')
+48
Ver Arquivo
@@ -0,0 +1,48 @@
MenuManager = require '../src/menu-manager'
describe "MenuManager", ->
menu = null
beforeEach ->
menu = new MenuManager(resourcePath: atom.getLoadSettings().resourcePath)
describe "::add(items)", ->
it "can add new menus that can be removed with the returned disposable", ->
disposable = menu.add [{label: "A", submenu: [{label: "B", command: "b"}]}]
expect(menu.template).toEqual [{label: "A", submenu: [{label: "B", command: "b"}]}]
disposable.dispose()
expect(menu.template).toEqual []
it "can add submenu items to existing menus that can be removed with the returned disposable", ->
disposable1 = menu.add [{label: "A", submenu: [{label: "B", command: "b"}]}]
disposable2 = menu.add [{label: "A", submenu: [{label: "C", submenu: [{label: "D", command: 'd'}]}]}]
disposable3 = menu.add [{label: "A", submenu: [{label: "C", submenu: [{label: "E", command: 'e'}]}]}]
expect(menu.template).toEqual [{
label: "A",
submenu: [
{label: "B", command: "b"},
{label: "C", submenu: [{label: 'D', command: 'd'}, {label: 'E', command: 'e'}]}
]
}]
disposable3.dispose()
expect(menu.template).toEqual [{
label: "A",
submenu: [
{label: "B", command: "b"},
{label: "C", submenu: [{label: 'D', command: 'd'}]}
]
}]
disposable2.dispose()
expect(menu.template).toEqual [{label: "A", submenu: [{label: "B", command: "b"}]}]
disposable1.dispose()
expect(menu.template).toEqual []
it "does not add duplicate labels to the same menu", ->
originalItemCount = menu.template.length
menu.add [{label: "A", submenu: [{label: "B", command: "b"}]}]
menu.add [{label: "A", submenu: [{label: "B", command: "b"}]}]
expect(menu.template[originalItemCount]).toEqual {label: "A", submenu: [{label: "B", command: "b"}]}
+570
Ver Arquivo
@@ -0,0 +1,570 @@
{$, $$, WorkspaceView} = require 'atom'
Package = require '../src/package'
describe "PackageManager", ->
beforeEach ->
atom.workspaceView = new WorkspaceView
describe "::loadPackage(name)", ->
it "continues if the package has an invalid package.json", ->
spyOn(console, 'warn')
atom.config.set("core.disabledPackages", [])
expect(-> atom.packages.loadPackage("package-with-broken-package-json")).not.toThrow()
it "continues if the package has an invalid keymap", ->
spyOn(console, 'warn')
atom.config.set("core.disabledPackages", [])
expect(-> atom.packages.loadPackage("package-with-broken-keymap")).not.toThrow()
describe "::unloadPackage(name)", ->
describe "when the package is active", ->
it "throws an error", ->
pack = null
waitsForPromise ->
atom.packages.activatePackage('package-with-main').then (p) -> pack = p
runs ->
expect(atom.packages.isPackageLoaded(pack.name)).toBeTruthy()
expect(atom.packages.isPackageActive(pack.name)).toBeTruthy()
expect( -> atom.packages.unloadPackage(pack.name)).toThrow()
expect(atom.packages.isPackageLoaded(pack.name)).toBeTruthy()
expect(atom.packages.isPackageActive(pack.name)).toBeTruthy()
describe "when the package is not loaded", ->
it "throws an error", ->
expect(atom.packages.isPackageLoaded('unloaded')).toBeFalsy()
expect( -> atom.packages.unloadPackage('unloaded')).toThrow()
expect(atom.packages.isPackageLoaded('unloaded')).toBeFalsy()
describe "when the package is loaded", ->
it "no longers reports it as being loaded", ->
pack = atom.packages.loadPackage('package-with-main')
expect(atom.packages.isPackageLoaded(pack.name)).toBeTruthy()
atom.packages.unloadPackage(pack.name)
expect(atom.packages.isPackageLoaded(pack.name)).toBeFalsy()
describe "::activatePackage(id)", ->
describe "atom packages", ->
describe "when called multiple times", ->
it "it only calls activate on the package once", ->
spyOn(Package.prototype, 'activateNow').andCallThrough()
atom.packages.activatePackage('package-with-index')
atom.packages.activatePackage('package-with-index')
waitsForPromise ->
atom.packages.activatePackage('package-with-index')
runs ->
expect(Package.prototype.activateNow.callCount).toBe 1
describe "when the package has a main module", ->
describe "when the metadata specifies a main module path˜", ->
it "requires the module at the specified path", ->
mainModule = require('./fixtures/packages/package-with-main/main-module')
spyOn(mainModule, 'activate')
pack = null
waitsForPromise ->
atom.packages.activatePackage('package-with-main').then (p) -> pack = p
runs ->
expect(mainModule.activate).toHaveBeenCalled()
expect(pack.mainModule).toBe mainModule
describe "when the metadata does not specify a main module", ->
it "requires index.coffee", ->
indexModule = require('./fixtures/packages/package-with-index/index')
spyOn(indexModule, 'activate')
pack = null
waitsForPromise ->
atom.packages.activatePackage('package-with-index').then (p) -> pack = p
runs ->
expect(indexModule.activate).toHaveBeenCalled()
expect(pack.mainModule).toBe indexModule
it "assigns config schema, including defaults when package contains a schema", ->
expect(atom.config.get('package-with-config-schema.numbers.one')).toBeUndefined()
waitsForPromise ->
atom.packages.activatePackage('package-with-config-schema')
runs ->
expect(atom.config.get('package-with-config-schema.numbers.one')).toBe 1
expect(atom.config.get('package-with-config-schema.numbers.two')).toBe 2
expect(atom.config.set('package-with-config-schema.numbers.one', 'nope')).toBe false
expect(atom.config.set('package-with-config-schema.numbers.one', '10')).toBe true
expect(atom.config.get('package-with-config-schema.numbers.one')).toBe 10
it "still assigns configDefaults from the module though deprecated", ->
expect(atom.config.get('package-with-config-defaults.numbers.one')).toBeUndefined()
waitsForPromise ->
atom.packages.activatePackage('package-with-config-defaults')
runs ->
expect(atom.config.get('package-with-config-defaults.numbers.one')).toBe 1
expect(atom.config.get('package-with-config-defaults.numbers.two')).toBe 2
describe "when the package metadata includes `activationCommands`", ->
[mainModule, promise, workspaceCommandListener] = []
beforeEach ->
atom.workspaceView.attachToDom()
mainModule = require './fixtures/packages/package-with-activation-commands/index'
mainModule.legacyActivationCommandCallCount = 0
mainModule.activationCommandCallCount = 0
spyOn(mainModule, 'activate').andCallThrough()
spyOn(Package.prototype, 'requireMainModule').andCallThrough()
workspaceCommandListener = jasmine.createSpy('workspaceCommandListener')
atom.commands.add '.workspace', 'activation-command', workspaceCommandListener
promise = atom.packages.activatePackage('package-with-activation-commands')
it "defers requiring/activating the main module until an activation event bubbles to the root view", ->
expect(promise.isFulfilled()).not.toBeTruthy()
atom.workspaceView[0].dispatchEvent(new CustomEvent('activation-command', bubbles: true))
waitsForPromise ->
promise
it "triggers the activation event on all handlers registered during activation", ->
waitsForPromise ->
atom.workspaceView.open()
runs ->
editorView = atom.workspaceView.getActiveView()
legacyCommandListener = jasmine.createSpy("legacyCommandListener")
editorView.command 'activation-command', legacyCommandListener
editorCommandListener = jasmine.createSpy("editorCommandListener")
atom.commands.add '.editor', 'activation-command', editorCommandListener
editorView[0].dispatchEvent(new CustomEvent('activation-command', bubbles: true))
expect(mainModule.activate.callCount).toBe 1
expect(mainModule.legacyActivationCommandCallCount).toBe 1
expect(mainModule.activationCommandCallCount).toBe 1
expect(legacyCommandListener.callCount).toBe 1
expect(editorCommandListener.callCount).toBe 1
expect(workspaceCommandListener.callCount).toBe 1
editorView[0].dispatchEvent(new CustomEvent('activation-command', bubbles: true))
expect(mainModule.legacyActivationCommandCallCount).toBe 2
expect(mainModule.activationCommandCallCount).toBe 2
expect(legacyCommandListener.callCount).toBe 2
expect(editorCommandListener.callCount).toBe 2
expect(workspaceCommandListener.callCount).toBe 2
expect(mainModule.activate.callCount).toBe 1
it "activates the package immediately when the events are empty", ->
mainModule = require './fixtures/packages/package-with-empty-activation-commands/index'
spyOn(mainModule, 'activate').andCallThrough()
waitsForPromise ->
atom.packages.activatePackage('package-with-empty-activation-commands')
runs ->
expect(mainModule.activate.callCount).toBe 1
describe "when the package has no main module", ->
it "does not throw an exception", ->
spyOn(console, "error")
spyOn(console, "warn").andCallThrough()
expect(-> atom.packages.activatePackage('package-without-module')).not.toThrow()
expect(console.error).not.toHaveBeenCalled()
expect(console.warn).not.toHaveBeenCalled()
it "passes the activate method the package's previously serialized state if it exists", ->
pack = null
waitsForPromise ->
atom.packages.activatePackage("package-with-serialization").then (p) -> pack = p
runs ->
expect(pack.mainModule.someNumber).not.toBe 77
pack.mainModule.someNumber = 77
atom.packages.deactivatePackage("package-with-serialization")
spyOn(pack.mainModule, 'activate').andCallThrough()
atom.packages.activatePackage("package-with-serialization")
expect(pack.mainModule.activate).toHaveBeenCalledWith({someNumber: 77})
it "logs warning instead of throwing an exception if the package fails to load", ->
atom.config.set("core.disabledPackages", [])
spyOn(console, "warn")
expect(-> atom.packages.activatePackage("package-that-throws-an-exception")).not.toThrow()
expect(console.warn).toHaveBeenCalled()
describe "keymap loading", ->
describe "when the metadata does not contain a 'keymaps' manifest", ->
it "loads all the .cson/.json files in the keymaps directory", ->
element1 = $$ -> @div class: 'test-1'
element2 = $$ -> @div class: 'test-2'
element3 = $$ -> @div class: 'test-3'
expect(atom.keymaps.findKeyBindings(keystrokes:'ctrl-z', target:element1[0])).toHaveLength 0
expect(atom.keymaps.findKeyBindings(keystrokes:'ctrl-z', target:element2[0])).toHaveLength 0
expect(atom.keymaps.findKeyBindings(keystrokes:'ctrl-z', target:element3[0])).toHaveLength 0
atom.packages.activatePackage("package-with-keymaps")
expect(atom.keymaps.findKeyBindings(keystrokes:'ctrl-z', target:element1[0])[0].command).toBe "test-1"
expect(atom.keymaps.findKeyBindings(keystrokes:'ctrl-z', target:element2[0])[0].command).toBe "test-2"
expect(atom.keymaps.findKeyBindings(keystrokes:'ctrl-z', target:element3[0])).toHaveLength 0
describe "when the metadata contains a 'keymaps' manifest", ->
it "loads only the keymaps specified by the manifest, in the specified order", ->
element1 = $$ -> @div class: 'test-1'
element3 = $$ -> @div class: 'test-3'
expect(atom.keymaps.findKeyBindings(keystrokes:'ctrl-z', target:element1[0])).toHaveLength 0
atom.packages.activatePackage("package-with-keymaps-manifest")
expect(atom.keymaps.findKeyBindings(keystrokes:'ctrl-z', target:element1[0])[0].command).toBe 'keymap-1'
expect(atom.keymaps.findKeyBindings(keystrokes:'ctrl-n', target:element1[0])[0].command).toBe 'keymap-2'
expect(atom.keymaps.findKeyBindings(keystrokes:'ctrl-y', target:element3[0])).toHaveLength 0
describe "menu loading", ->
beforeEach ->
atom.contextMenu.definitions = []
atom.menu.template = []
describe "when the metadata does not contain a 'menus' manifest", ->
it "loads all the .cson/.json files in the menus directory", ->
element = ($$ -> @div class: 'test-1')[0]
expect(atom.contextMenu.definitionsForElement(element)).toEqual []
atom.packages.activatePackage("package-with-menus")
expect(atom.menu.template.length).toBe 2
expect(atom.menu.template[0].label).toBe "Second to Last"
expect(atom.menu.template[1].label).toBe "Last"
expect(atom.contextMenu.definitionsForElement(element)[0].label).toBe "Menu item 1"
expect(atom.contextMenu.definitionsForElement(element)[1].label).toBe "Menu item 2"
expect(atom.contextMenu.definitionsForElement(element)[2].label).toBe "Menu item 3"
describe "when the metadata contains a 'menus' manifest", ->
it "loads only the menus specified by the manifest, in the specified order", ->
element = ($$ -> @div class: 'test-1')[0]
expect(atom.contextMenu.definitionsForElement(element)).toEqual []
atom.packages.activatePackage("package-with-menus-manifest")
expect(atom.menu.template[0].label).toBe "Second to Last"
expect(atom.menu.template[1].label).toBe "Last"
expect(atom.contextMenu.definitionsForElement(element)[0].label).toBe "Menu item 2"
expect(atom.contextMenu.definitionsForElement(element)[1].label).toBe "Menu item 1"
expect(atom.contextMenu.definitionsForElement(element)[2]).toBeUndefined()
describe "stylesheet loading", ->
describe "when the metadata contains a 'stylesheets' manifest", ->
it "loads stylesheets from the stylesheets directory as specified by the manifest", ->
one = require.resolve("./fixtures/packages/package-with-stylesheets-manifest/stylesheets/1.css")
two = require.resolve("./fixtures/packages/package-with-stylesheets-manifest/stylesheets/2.less")
three = require.resolve("./fixtures/packages/package-with-stylesheets-manifest/stylesheets/3.css")
one = atom.themes.stringToId(one)
two = atom.themes.stringToId(two)
three = atom.themes.stringToId(three)
expect(atom.themes.stylesheetElementForId(one)).toBeNull()
expect(atom.themes.stylesheetElementForId(two)).toBeNull()
expect(atom.themes.stylesheetElementForId(three)).toBeNull()
atom.packages.activatePackage("package-with-stylesheets-manifest")
expect(atom.themes.stylesheetElementForId(one)).not.toBeNull()
expect(atom.themes.stylesheetElementForId(two)).not.toBeNull()
expect(atom.themes.stylesheetElementForId(three)).toBeNull()
expect($('#jasmine-content').css('font-size')).toBe '1px'
describe "when the metadata does not contain a 'stylesheets' manifest", ->
it "loads all stylesheets from the stylesheets directory", ->
one = require.resolve("./fixtures/packages/package-with-stylesheets/stylesheets/1.css")
two = require.resolve("./fixtures/packages/package-with-stylesheets/stylesheets/2.less")
three = require.resolve("./fixtures/packages/package-with-stylesheets/stylesheets/3.css")
one = atom.themes.stringToId(one)
two = atom.themes.stringToId(two)
three = atom.themes.stringToId(three)
expect(atom.themes.stylesheetElementForId(one)).toBeNull()
expect(atom.themes.stylesheetElementForId(two)).toBeNull()
expect(atom.themes.stylesheetElementForId(three)).toBeNull()
atom.packages.activatePackage("package-with-stylesheets")
expect(atom.themes.stylesheetElementForId(one)).not.toBeNull()
expect(atom.themes.stylesheetElementForId(two)).not.toBeNull()
expect(atom.themes.stylesheetElementForId(three)).not.toBeNull()
expect($('#jasmine-content').css('font-size')).toBe '3px'
describe "grammar loading", ->
it "loads the package's grammars", ->
waitsForPromise ->
atom.packages.activatePackage('package-with-grammars')
runs ->
expect(atom.syntax.selectGrammar('a.alot').name).toBe 'Alot'
expect(atom.syntax.selectGrammar('a.alittle').name).toBe 'Alittle'
describe "scoped-property loading", ->
it "loads the scoped properties", ->
waitsForPromise ->
atom.packages.activatePackage("package-with-scoped-properties")
runs ->
expect(atom.syntax.getProperty ['.source.omg'], 'editor.increaseIndentPattern').toBe '^a'
describe "converted textmate packages", ->
it "loads the package's grammars", ->
expect(atom.syntax.selectGrammar("file.rb").name).toBe "Null Grammar"
waitsForPromise ->
atom.packages.activatePackage('language-ruby')
runs ->
expect(atom.syntax.selectGrammar("file.rb").name).toBe "Ruby"
it "loads the translated scoped properties", ->
expect(atom.syntax.getProperty(['.source.ruby'], 'editor.commentStart')).toBeUndefined()
waitsForPromise ->
atom.packages.activatePackage('language-ruby')
runs ->
expect(atom.syntax.getProperty(['.source.ruby'], 'editor.commentStart')).toBe '# '
describe "::deactivatePackage(id)", ->
describe "atom packages", ->
it "calls `deactivate` on the package's main module if activate was successful", ->
pack = null
waitsForPromise ->
atom.packages.activatePackage("package-with-deactivate").then (p) -> pack = p
runs ->
expect(atom.packages.isPackageActive("package-with-deactivate")).toBeTruthy()
spyOn(pack.mainModule, 'deactivate').andCallThrough()
atom.packages.deactivatePackage("package-with-deactivate")
expect(pack.mainModule.deactivate).toHaveBeenCalled()
expect(atom.packages.isPackageActive("package-with-module")).toBeFalsy()
spyOn(console, 'warn')
badPack = null
waitsForPromise ->
atom.packages.activatePackage("package-that-throws-on-activate").then (p) -> badPack = p
runs ->
expect(atom.packages.isPackageActive("package-that-throws-on-activate")).toBeTruthy()
spyOn(badPack.mainModule, 'deactivate').andCallThrough()
atom.packages.deactivatePackage("package-that-throws-on-activate")
expect(badPack.mainModule.deactivate).not.toHaveBeenCalled()
expect(atom.packages.isPackageActive("package-that-throws-on-activate")).toBeFalsy()
it "does not serialize packages that have not been activated called on their main module", ->
spyOn(console, 'warn')
badPack = null
waitsForPromise ->
atom.packages.activatePackage("package-that-throws-on-activate").then (p) -> badPack = p
runs ->
spyOn(badPack.mainModule, 'serialize').andCallThrough()
atom.packages.deactivatePackage("package-that-throws-on-activate")
expect(badPack.mainModule.serialize).not.toHaveBeenCalled()
it "absorbs exceptions that are thrown by the package module's serialize method", ->
spyOn(console, 'error')
waitsForPromise ->
atom.packages.activatePackage('package-with-serialize-error')
waitsForPromise ->
atom.packages.activatePackage('package-with-serialization')
runs ->
atom.packages.deactivatePackages()
expect(atom.packages.packageStates['package-with-serialize-error']).toBeUndefined()
expect(atom.packages.packageStates['package-with-serialization']).toEqual someNumber: 1
expect(console.error).toHaveBeenCalled()
it "absorbs exceptions that are thrown by the package module's deactivate method", ->
spyOn(console, 'error')
waitsForPromise ->
atom.packages.activatePackage("package-that-throws-on-deactivate")
runs ->
expect(-> atom.packages.deactivatePackage("package-that-throws-on-deactivate")).not.toThrow()
expect(console.error).toHaveBeenCalled()
it "removes the package's grammars", ->
waitsForPromise ->
atom.packages.activatePackage('package-with-grammars')
runs ->
atom.packages.deactivatePackage('package-with-grammars')
expect(atom.syntax.selectGrammar('a.alot').name).toBe 'Null Grammar'
expect(atom.syntax.selectGrammar('a.alittle').name).toBe 'Null Grammar'
it "removes the package's keymaps", ->
waitsForPromise ->
atom.packages.activatePackage('package-with-keymaps')
runs ->
atom.packages.deactivatePackage('package-with-keymaps')
expect(atom.keymaps.findKeyBindings(keystrokes:'ctrl-z', target: ($$ -> @div class: 'test-1')[0])).toHaveLength 0
expect(atom.keymaps.findKeyBindings(keystrokes:'ctrl-z', target: ($$ -> @div class: 'test-2')[0])).toHaveLength 0
it "removes the package's stylesheets", ->
waitsForPromise ->
atom.packages.activatePackage('package-with-stylesheets')
runs ->
atom.packages.deactivatePackage('package-with-stylesheets')
one = require.resolve("./fixtures/packages/package-with-stylesheets-manifest/stylesheets/1.css")
two = require.resolve("./fixtures/packages/package-with-stylesheets-manifest/stylesheets/2.less")
three = require.resolve("./fixtures/packages/package-with-stylesheets-manifest/stylesheets/3.css")
expect(atom.themes.stylesheetElementForId(one)).not.toExist()
expect(atom.themes.stylesheetElementForId(two)).not.toExist()
expect(atom.themes.stylesheetElementForId(three)).not.toExist()
it "removes the package's scoped-properties", ->
waitsForPromise ->
atom.packages.activatePackage("package-with-scoped-properties")
runs ->
expect(atom.syntax.getProperty ['.source.omg'], 'editor.increaseIndentPattern').toBe '^a'
atom.packages.deactivatePackage("package-with-scoped-properties")
expect(atom.syntax.getProperty ['.source.omg'], 'editor.increaseIndentPattern').toBeUndefined()
describe "textmate packages", ->
it "removes the package's grammars", ->
expect(atom.syntax.selectGrammar("file.rb").name).toBe "Null Grammar"
waitsForPromise ->
atom.packages.activatePackage('language-ruby')
runs ->
expect(atom.syntax.selectGrammar("file.rb").name).toBe "Ruby"
atom.packages.deactivatePackage('language-ruby')
expect(atom.syntax.selectGrammar("file.rb").name).toBe "Null Grammar"
it "removes the package's scoped properties", ->
waitsForPromise ->
atom.packages.activatePackage('language-ruby')
runs ->
atom.packages.deactivatePackage('language-ruby')
expect(atom.syntax.getProperty(['.source.ruby'], 'editor.commentStart')).toBeUndefined()
describe "::activate()", ->
packageActivator = null
themeActivator = null
beforeEach ->
spyOn(console, 'warn')
atom.packages.loadPackages()
loadedPackages = atom.packages.getLoadedPackages()
expect(loadedPackages.length).toBeGreaterThan 0
packageActivator = spyOn(atom.packages, 'activatePackages')
themeActivator = spyOn(atom.themes, 'activatePackages')
afterEach ->
atom.packages.deactivatePackages()
atom.packages.unloadPackages()
Syntax = require '../src/syntax'
atom.syntax = window.syntax = new Syntax()
it "activates all the packages, and none of the themes", ->
atom.packages.activate()
expect(packageActivator).toHaveBeenCalled()
expect(themeActivator).toHaveBeenCalled()
packages = packageActivator.mostRecentCall.args[0]
expect(['atom', 'textmate']).toContain(pack.getType()) for pack in packages
themes = themeActivator.mostRecentCall.args[0]
expect(['theme']).toContain(theme.getType()) for theme in themes
describe "::enablePackage() and ::disablePackage()", ->
describe "with packages", ->
it ".enablePackage() enables a disabled package", ->
packageName = 'package-with-main'
atom.config.pushAtKeyPath('core.disabledPackages', packageName)
atom.packages.observeDisabledPackages()
expect(atom.config.get('core.disabledPackages')).toContain packageName
pack = atom.packages.enablePackage(packageName)
loadedPackages = atom.packages.getLoadedPackages()
activatedPackages = null
waitsFor ->
activatedPackages = atom.packages.getActivePackages()
activatedPackages.length > 0
runs ->
expect(loadedPackages).toContain(pack)
expect(activatedPackages).toContain(pack)
expect(atom.config.get('core.disabledPackages')).not.toContain packageName
it ".disablePackage() disables an enabled package", ->
packageName = 'package-with-main'
waitsForPromise ->
atom.packages.activatePackage(packageName)
runs ->
atom.packages.observeDisabledPackages()
expect(atom.config.get('core.disabledPackages')).not.toContain packageName
pack = atom.packages.disablePackage(packageName)
activatedPackages = atom.packages.getActivePackages()
expect(activatedPackages).not.toContain(pack)
expect(atom.config.get('core.disabledPackages')).toContain packageName
describe "with themes", ->
reloadedHandler = null
beforeEach ->
waitsForPromise ->
atom.themes.activateThemes()
afterEach ->
atom.themes.deactivateThemes()
it ".enablePackage() and .disablePackage() enables and disables a theme", ->
packageName = 'theme-with-package-file'
expect(atom.config.get('core.themes')).not.toContain packageName
expect(atom.config.get('core.disabledPackages')).not.toContain packageName
# enabling of theme
pack = atom.packages.enablePackage(packageName)
waitsFor ->
pack in atom.packages.getActivePackages()
runs ->
expect(atom.config.get('core.themes')).toContain packageName
expect(atom.config.get('core.disabledPackages')).not.toContain packageName
reloadedHandler = jasmine.createSpy('reloadedHandler')
reloadedHandler.reset()
atom.themes.onDidReloadAll reloadedHandler
pack = atom.packages.disablePackage(packageName)
waitsFor ->
reloadedHandler.callCount is 1
runs ->
expect(atom.packages.getActivePackages()).not.toContain pack
expect(atom.config.get('core.themes')).not.toContain packageName
expect(atom.config.get('core.themes')).not.toContain packageName
expect(atom.config.get('core.disabledPackages')).not.toContain packageName
+3 -3
Ver Arquivo
@@ -5,11 +5,11 @@ PaneView = require '../src/pane-view'
{$, View, $$} = require 'atom'
describe "PaneContainerView", ->
[TestView, container, pane1, pane2, pane3] = []
[TestView, container, pane1, pane2, pane3, deserializerDisposable] = []
beforeEach ->
class TestView extends View
atom.deserializers.add(this)
deserializerDisposable = atom.deserializers.add(this)
@deserialize: ({name}) -> new TestView(name)
@content: -> @div tabindex: -1
initialize: (@name) -> @text(@name)
@@ -25,7 +25,7 @@ describe "PaneContainerView", ->
pane3 = pane2.splitDown(new TestView('3'))
afterEach ->
atom.deserializers.remove(TestView)
deserializerDisposable.dispose()
describe ".getActivePaneView()", ->
it "returns the most-recently focused pane", ->
+4 -2
Ver Arquivo
@@ -4,6 +4,8 @@ PaneAxis = require '../src/pane-axis'
PaneContainer = require '../src/pane-container'
describe "Pane", ->
deserializerDisposable = null
class Item extends Model
@deserialize: ({name, uri}) -> new this(name, uri)
constructor: (@name, @uri) ->
@@ -13,10 +15,10 @@ describe "Pane", ->
isEqual: (other) -> @name is other?.name
beforeEach ->
atom.deserializers.add(Item)
deserializerDisposable = atom.deserializers.add(Item)
afterEach ->
atom.deserializers.remove(Item)
deserializerDisposable.dispose()
describe "construction", ->
it "sets the active item to the first item", ->
+3 -3
Ver Arquivo
@@ -7,7 +7,7 @@ path = require 'path'
temp = require 'temp'
describe "PaneView", ->
[container, containerModel, view1, view2, editor1, editor2, pane, paneModel] = []
[container, containerModel, view1, view2, editor1, editor2, pane, paneModel, deserializerDisposable] = []
class TestView extends View
@deserialize: ({id, text}) -> new TestView({id, text})
@@ -23,7 +23,7 @@ describe "PaneView", ->
@emitter.on 'did-change-title', callback
beforeEach ->
atom.deserializers.add(TestView)
deserializerDisposable = atom.deserializers.add(TestView)
container = new PaneContainerView
containerModel = container.model
view1 = new TestView(id: 'view-1', text: 'View 1')
@@ -40,7 +40,7 @@ describe "PaneView", ->
paneModel.addItems([view1, editor1, view2, editor2])
afterEach ->
atom.deserializers.remove(TestView)
deserializerDisposable.dispose()
describe "when the active pane item changes", ->
it "hides all item views except the active one", ->
+3 -3
Ver Arquivo
@@ -1,9 +1,9 @@
{times, random} = require 'underscore-plus'
randomWords = require 'random-words'
TextBuffer = require 'text-buffer'
Editor = require '../src/editor'
TextEditor = require '../src/text-editor'
describe "Editor", ->
describe "TextEditor", ->
[editor, tokenizedBuffer, buffer, steps, previousSteps] = []
softWrapColumn = 80
@@ -17,7 +17,7 @@ describe "Editor", ->
times 10, (i) ->
buffer = new TextBuffer
editor = new Editor({buffer})
editor = new TextEditor({buffer})
editor.setEditorWidthInChars(80)
tokenizedBuffer = editor.displayBuffer.tokenizedBuffer
steps = []
+2 -2
Ver Arquivo
@@ -1,11 +1,11 @@
Editor = require '../src/editor'
TextEditor = require '../src/text-editor'
describe "Selection", ->
[buffer, editor, selection] = []
beforeEach ->
buffer = atom.project.bufferForPathSync('sample.js')
editor = new Editor(buffer: buffer, tabLength: 2)
editor = new TextEditor(buffer: buffer, tabLength: 2)
selection = editor.getLastSelection()
afterEach ->
+11 -11
Ver Arquivo
@@ -12,10 +12,10 @@ KeymapManager = require '../src/keymap-extensions'
Config = require '../src/config'
{Point} = require 'text-buffer'
Project = require '../src/project'
Editor = require '../src/editor'
EditorView = require '../src/editor-view'
TextEditor = require '../src/text-editor'
TextEditorView = require '../src/text-editor-view'
TokenizedBuffer = require '../src/tokenized-buffer'
EditorComponent = require '../src/editor-component'
TextEditorComponent = require '../src/text-editor-component'
pathwatcher = require 'pathwatcher'
clipboard = require 'clipboard'
@@ -27,6 +27,7 @@ fixturePackagesPath = path.resolve(__dirname, './fixtures/packages')
atom.packages.packageDirPaths.unshift(fixturePackagesPath)
atom.keymaps.loadBundledKeymaps()
keyBindingsToRestore = atom.keymaps.getKeyBindings()
commandsToRestore = atom.commands.getSnapshot()
$(window).on 'core:close', -> window.close()
$(window).on 'beforeunload', ->
@@ -65,6 +66,7 @@ beforeEach ->
atom.workspace = new Workspace()
atom.keymaps.keyBindings = _.clone(keyBindingsToRestore)
atom.commands.setRootNode(document.body)
atom.commands.restoreSnapshot(commandsToRestore)
window.resetTimeouts()
atom.packages.packageStates = {}
@@ -89,26 +91,26 @@ beforeEach ->
config = new Config({resourcePath, configDirPath: atom.getConfigDirPath()})
spyOn(config, 'load')
spyOn(config, 'save')
config.setDefaults('core', WorkspaceView.configDefaults)
config.setDefaults('editor', EditorView.configDefaults)
atom.config = config
atom.loadConfig()
config.set "core.destroyEmptyPanes", false
config.set "editor.fontFamily", "Courier"
config.set "editor.fontSize", 16
config.set "editor.autoIndent", false
config.set "core.disabledPackages", ["package-that-throws-an-exception",
"package-with-broken-package-json", "package-with-broken-keymap"]
config.load.reset()
config.save.reset()
atom.config = config
# make editor display updates synchronous
spyOn(EditorView.prototype, 'requestDisplayUpdate').andCallFake -> @updateDisplay()
EditorComponent.performSyncUpdates = true
spyOn(TextEditorView.prototype, 'requestDisplayUpdate').andCallFake -> @updateDisplay()
TextEditorComponent.performSyncUpdates = true
spyOn(WorkspaceView.prototype, 'setTitle').andCallFake (@title) ->
spyOn(window, "setTimeout").andCallFake window.fakeSetTimeout
spyOn(window, "clearTimeout").andCallFake window.fakeClearTimeout
spyOn(pathwatcher.File.prototype, "detectResurrectionAfterDelay").andCallFake -> @detectResurrection()
spyOn(Editor.prototype, "shouldPromptToSave").andReturn false
spyOn(TextEditor.prototype, "shouldPromptToSave").andReturn false
# make tokenization synchronous
TokenizedBuffer.prototype.chunkSize = Infinity
@@ -121,8 +123,6 @@ beforeEach ->
addCustomMatchers(this)
afterEach ->
atom.commands.clear()
atom.packages.deactivatePackages()
atom.menu.template = []
+4 -1
Ver Arquivo
@@ -4,7 +4,6 @@ temp = require 'temp'
describe "the `syntax` global", ->
beforeEach ->
waitsForPromise ->
atom.packages.activatePackage('language-text')
@@ -17,6 +16,10 @@ describe "the `syntax` global", ->
waitsForPromise ->
atom.packages.activatePackage('language-ruby')
afterEach ->
atom.packages.deactivatePackages()
atom.packages.unloadPackages()
describe "serialization", ->
it "remembers grammar overrides by path", ->
filePath = '/foo/bar/file.js'
@@ -1,11 +1,11 @@
_ = require 'underscore-plus'
{extend, flatten, toArray, last} = _
EditorView = require '../src/editor-view'
EditorComponent = require '../src/editor-component'
TextEditorView = require '../src/text-editor-view'
TextEditorComponent = require '../src/text-editor-component'
nbsp = String.fromCharCode(160)
describe "EditorComponent", ->
describe "TextEditorComponent", ->
[contentNode, editor, wrapperView, wrapperNode, component, componentNode, verticalScrollbarNode, horizontalScrollbarNode] = []
[lineHeightInPixels, charWidth, nextAnimationFrame, noAnimationFrame, lineOverdrawMargin] = []
@@ -34,7 +34,7 @@ describe "EditorComponent", ->
contentNode = document.querySelector('#jasmine-content')
contentNode.style.width = '1000px'
wrapperView = new EditorView(editor, {lineOverdrawMargin})
wrapperView = new TextEditorView(editor, {lineOverdrawMargin})
wrapperView.attachToDom()
wrapperNode = wrapperView.element
@@ -1734,11 +1734,11 @@ describe "EditorComponent", ->
nextAnimationFrame()
expect(verticalScrollbarNode.scrollTop).toBe 10
it "parses negative scrollSensitivity values as positive", ->
it "parses negative scrollSensitivity values at the minimum", ->
atom.config.set('editor.scrollSensitivity', -50)
componentNode.dispatchEvent(new WheelEvent('mousewheel', wheelDeltaX: 0, wheelDeltaY: -10))
nextAnimationFrame()
expect(verticalScrollbarNode.scrollTop).toBe 5
expect(verticalScrollbarNode.scrollTop).toBe 1
describe "when the mousewheel event's target is a line", ->
it "keeps the line on the DOM if it is scrolled off-screen", ->
@@ -1999,7 +1999,7 @@ describe "EditorComponent", ->
hiddenParent.style.display = 'none'
contentNode.appendChild(hiddenParent)
wrapperView = new EditorView(editor, {lineOverdrawMargin})
wrapperView = new TextEditorView(editor, {lineOverdrawMargin})
wrapperNode = wrapperView.element
wrapperView.appendTo(hiddenParent)
@@ -2259,6 +2259,15 @@ describe "EditorComponent", ->
editor.setGrammar(atom.syntax.nullGrammar)
expect(wrapperNode.dataset.grammar).toBe 'text plain null-grammar'
describe "detaching and reattaching the editor (regression)", ->
it "does not throw an exception", ->
wrapperView.detach()
wrapperView.attachToDom()
wrapperView.trigger('core:move-right')
expect(editor.getCursorBufferPosition()).toEqual [0, 1]
buildMouseEvent = (type, properties...) ->
properties = extend({bubbles: true, cancelable: true}, properties...)
properties.detail ?= 1
@@ -1,7 +1,7 @@
clipboard = require 'clipboard'
Editor = require '../src/editor'
TextEditor = require '../src/text-editor'
describe "Editor", ->
describe "TextEditor", ->
[buffer, editor, lineLengths] = []
convertToHardTabs = (buffer) ->
@@ -49,7 +49,7 @@ describe "Editor", ->
state = editor.serialize()
atom.config.set('editor.invisibles', eol: '?')
editor2 = Editor.deserialize(state)
editor2 = TextEditor.deserialize(state)
expect(editor2.displayBuffer.invisibles.eol).toBe '?'
expect(editor2.displayBuffer.tokenizedBuffer.invisibles.eol).toBe '?'
@@ -3263,6 +3263,9 @@ describe "Editor", ->
runs ->
expect(editor.softTabs).toBe false
atom.packages.deactivatePackage('language-coffee-script')
atom.packages.unloadPackage('language-coffee-script')
describe ".destroy()", ->
it "destroys all markers associated with the edit session", ->
expect(buffer.getMarkerCount()).toBeGreaterThan 0
@@ -3669,7 +3672,7 @@ describe "Editor", ->
describe '.get/setPlaceholderText()', ->
it 'can be created with placeholderText', ->
TextBuffer = require 'text-buffer'
newEditor = new Editor
newEditor = new TextEditor
buffer: new TextBuffer
mini: true
placeholderText: 'yep'
+5 -6
Ver Arquivo
@@ -52,7 +52,7 @@ describe "ThemeManager", ->
expect(themeManager.getEnabledThemeNames()).toEqual ['atom-dark-ui', 'atom-light-ui']
describe "getImportPaths()", ->
describe "::getImportPaths()", ->
it "returns the theme directories before the themes are loaded", ->
atom.config.set('core.themes', ['theme-with-index-less', 'atom-dark-ui', 'atom-light-ui'])
@@ -129,7 +129,7 @@ describe "ThemeManager", ->
spyOn(console, 'warn')
expect(-> atom.packages.activatePackage('a-theme-that-will-not-be-found')).toThrow()
describe "requireStylesheet(path)", ->
describe "::requireStylesheet(path)", ->
it "synchronously loads css at the given path and installs a style tag for it in the head", ->
themeManager.onDidChangeStylesheets stylesheetsChangedHandler = jasmine.createSpy("stylesheetsChangedHandler")
themeManager.onDidAddStylesheet stylesheetAddedHandler = jasmine.createSpy("stylesheetAddedHandler")
@@ -185,18 +185,17 @@ describe "ThemeManager", ->
$('head style[id*="css.css"]').remove()
$('head style[id*="sample.less"]').remove()
describe ".removeStylesheet(path)", ->
it "removes styling applied by given stylesheet path", ->
it "returns a disposable allowing styles applied by the given path to be removed", ->
cssPath = require.resolve('./fixtures/css.css')
expect($(document.body).css('font-weight')).not.toBe("bold")
themeManager.requireStylesheet(cssPath)
disposable = themeManager.requireStylesheet(cssPath)
expect($(document.body).css('font-weight')).toBe("bold")
themeManager.onDidRemoveStylesheet stylesheetRemovedHandler = jasmine.createSpy("stylesheetRemovedHandler")
themeManager.onDidChangeStylesheets stylesheetsChangedHandler = jasmine.createSpy("stylesheetsChangedHandler")
themeManager.removeStylesheet(cssPath)
disposable.dispose()
expect($(document.body).css('font-weight')).not.toBe("bold")
+1 -1
Ver Arquivo
@@ -586,7 +586,7 @@ describe "TokenizedBuffer", ->
atom.config.set('editor.tabLength', 1)
expect(tokenizedBuffer.tokenForPosition([0,0]).value).toBe ' '
atom.config.set('editor.tabLength', 0)
expect(tokenizedBuffer.tokenForPosition([0,0]).value).toBe ' '
expect(tokenizedBuffer.tokenForPosition([0,0]).value).toBe ' '
describe "when the invisibles value changes", ->
beforeEach ->
+2 -2
Ver Arquivo
@@ -1,6 +1,6 @@
{$, $$} = require 'atom'
path = require 'path'
Editor = require '../src/editor'
TextEditor = require '../src/text-editor'
WindowEventHandler = require '../src/window-event-handler'
describe "Window", ->
@@ -59,7 +59,7 @@ describe "Window", ->
[beforeUnloadEvent] = []
beforeEach ->
jasmine.unspy(Editor.prototype, "shouldPromptToSave")
jasmine.unspy(TextEditor.prototype, "shouldPromptToSave")
beforeUnloadEvent = $.Event(new Event('beforeunload'))
describe "when pane items are are modified", ->
+2 -2
Ver Arquivo
@@ -2,7 +2,7 @@
Q = require 'q'
path = require 'path'
temp = require 'temp'
EditorView = require '../src/editor-view'
TextEditorView = require '../src/text-editor-view'
PaneView = require '../src/pane-view'
Workspace = require '../src/workspace'
@@ -253,7 +253,7 @@ describe "WorkspaceView", ->
editorViewCreatedHandler = jasmine.createSpy('editorViewCreatedHandler')
atom.workspaceView.eachEditorView(editorViewCreatedHandler)
editorViewCreatedHandler.reset()
miniEditor = new EditorView(mini: true)
miniEditor = new TextEditorView(mini: true)
atom.workspaceView.append(miniEditor)
expect(editorViewCreatedHandler).not.toHaveBeenCalled()
+6 -4
Ver Arquivo
@@ -215,7 +215,7 @@ class Atom extends Model
@deserializers.add(TextBuffer)
TokenizedBuffer = require './tokenized-buffer'
DisplayBuffer = require './display-buffer'
Editor = require './editor'
TextEditor = require './text-editor'
@windowEventHandler = new WindowEventHandler
@@ -466,9 +466,7 @@ class Atom extends Model
console.warn error.message if error?
dimensions = @restoreWindowDimensions()
@config.load()
@config.setDefaults('core', require('./workspace-view').configDefaults)
@config.setDefaults('editor', require('./editor-view').configDefaults)
@loadConfig()
@keymaps.loadBundledKeymaps()
@themes.loadBaseStylesheets()
@packages.loadPackages()
@@ -604,6 +602,10 @@ class Atom extends Model
@deserializeProject()
@deserializeWorkspaceView()
loadConfig: ->
@config.setSchema null, {type: 'object', properties: _.clone(require('./config-schema'))}
@config.load()
loadThemes: ->
@themes.load()
+9 -1
Ver Arquivo
@@ -492,6 +492,14 @@ class AtomApplication
else
BrowserWindow.getFocusedWindow()
openOptions =
properties: properties.concat(['multiSelections', 'createDirectory'])
title: 'Open'
if process.platform is 'linux'
if projectPath = @lastFocusedWindow?.projectPath
openOptions.defaultPath = projectPath
dialog = require 'dialog'
dialog.showOpenDialog parentWindow, title: 'Open', properties: properties.concat(['multiSelections', 'createDirectory']), (pathsToOpen) =>
dialog.showOpenDialog parentWindow, openOptions, (pathsToOpen) =>
@openPaths({pathsToOpen, devMode, safeMode, window})
+89 -33
Ver Arquivo
@@ -46,13 +46,15 @@ class CommandRegistry
constructor: (@rootNode) ->
@listenersByCommandName = {}
getRootNode: -> @rootNode
setRootNode: (newRootNode) ->
oldRootNode = @rootNode
@rootNode = newRootNode
for commandName of @listenersByCommandName
oldRootNode?.removeEventListener(commandName, @dispatchCommand, true)
newRootNode?.addEventListener(commandName, @dispatchCommand, true)
@removeCommandListener(oldRootNode, commandName)
@addCommandListener(newRootNode, commandName)
# Public: Add one or more command listeners associated with a selector.
#
@@ -88,7 +90,7 @@ class CommandRegistry
return disposable
unless @listenersByCommandName[commandName]?
@rootNode?.addEventListener(commandName, @dispatchCommand, true)
@addCommandListener(@rootNode, commandName)
@listenersByCommandName[commandName] = []
listener = new CommandListener(selector, callback)
@@ -99,35 +101,7 @@ class CommandRegistry
listenersForCommand.splice(listenersForCommand.indexOf(listener), 1)
if listenersForCommand.length is 0
delete @listenersByCommandName[commandName]
@rootNode.removeEventListener(commandName, @dispatchCommand, true)
dispatchCommand: (event) =>
propagationStopped = false
immediatePropagationStopped = false
currentTarget = event.target
syntheticEvent = Object.create event,
eventPhase: value: Event.BUBBLING_PHASE
currentTarget: get: -> currentTarget
stopPropagation: value: ->
propagationStopped = true
stopImmediatePropagation: value: ->
propagationStopped = true
immediatePropagationStopped = true
loop
matchingListeners =
@listenersByCommandName[event.type]
.filter (listener) -> currentTarget.webkitMatchesSelector(listener.selector)
.sort (a, b) -> a.compare(b)
for listener in matchingListeners
break if immediatePropagationStopped
listener.callback.call(currentTarget, syntheticEvent)
break if propagationStopped
break if currentTarget is @rootNode
currentTarget = currentTarget.parentNode
@removeCommandListener(@rootNode, commandName)
# Public: Find all registered commands matching a query.
#
@@ -154,6 +128,7 @@ class CommandRegistry
break if currentTarget is @rootNode
currentTarget = currentTarget.parentNode
break unless currentTarget?
for name, displayName of $(target).events() when displayName
commands.push({name, displayName, jQuery: true})
@@ -163,10 +138,91 @@ class CommandRegistry
commands
clear: ->
# Public: Simulate the dispatch of a command on a DOM node.
#
# This can be useful for testing when you want to simulate the invocation of a
# command on a detached DOM node. Otherwise, the DOM node in question needs to
# be attached to the document so the event bubbles up to the root node to be
# processed.
#
# * `target` The DOM node at which to start bubbling the command event.
# * `commandName` {String} indicating the name of the command to dispatch.
dispatch: (target, commandName) ->
event = new CustomEvent(commandName, bubbles: true)
eventWithTarget = Object.create(event, target: value: target)
@handleCommandEvent(eventWithTarget)
getSnapshot: ->
snapshot = {}
for commandName, listeners of @listenersByCommandName
snapshot[commandName] = listeners.slice()
snapshot
restoreSnapshot: (snapshot) ->
rootNode = @getRootNode()
@setRootNode(null) # clear listeners for current commands
@listenersByCommandName = {}
for commandName, listeners of snapshot
@listenersByCommandName[commandName] = listeners.slice()
@setRootNode(rootNode) # restore listeners for commands in snapshot
handleCommandEvent: (originalEvent) =>
originalEvent.__handledByCommandRegistry = true
propagationStopped = false
immediatePropagationStopped = false
matched = false
currentTarget = originalEvent.target
invokedListeners = []
syntheticEvent = Object.create originalEvent,
eventPhase: value: Event.BUBBLING_PHASE
currentTarget: get: -> currentTarget
stopPropagation: value: ->
originalEvent.stopPropagation()
propagationStopped = true
stopImmediatePropagation: value: ->
originalEvent.stopImmediatePropagation()
propagationStopped = true
immediatePropagationStopped = true
disableInvokedListeners: value: ->
listener.enabled = false for listener in invokedListeners
-> listener.enabled = true for listener in invokedListeners
loop
matchingListeners =
(@listenersByCommandName[originalEvent.type] ? [])
.filter (listener) -> currentTarget.webkitMatchesSelector(listener.selector)
.sort (a, b) -> a.compare(b)
matched = true if matchingListeners.length > 0
for listener in matchingListeners when listener.enabled
break if immediatePropagationStopped
invokedListeners.push(listener)
listener.callback.call(currentTarget, syntheticEvent)
break if currentTarget is @rootNode
break if propagationStopped
currentTarget = currentTarget.parentNode
break unless currentTarget?
matched
handleJQueryCommandEvent: (event) =>
@handleCommandEvent(event) unless event.originalEvent?.__handledByCommandRegistry
addCommandListener: (node, commandName, listener) ->
node?.addEventListener(commandName, @handleCommandEvent, true)
$(node).on commandName, @handleJQueryCommandEvent
removeCommandListener: (node, commandName) ->
node?.removeEventListener(commandName, @handleCommandEvent, true)
$(node).off commandName, @handleJQueryCommandEvent
class CommandListener
enabled: true
constructor: (@selector, @callback) ->
@specificity = (SpecificityCache[@selector] ?= specificity(@selector))
@sequenceNumber = SequenceCount++
+113
Ver Arquivo
@@ -0,0 +1,113 @@
path = require 'path'
fs = require 'fs-plus'
# This is loaded by atom.coffee
module.exports =
core:
type: 'object'
properties:
ignoredNames:
type: 'array'
default: [".git", ".hg", ".svn", ".DS_Store", "Thumbs.db"]
items:
type: 'string'
excludeVcsIgnoredPaths:
type: 'boolean'
default: true
disabledPackages:
type: 'array'
default: []
items:
type: 'string'
themes:
type: 'array'
default: ['atom-dark-ui', 'atom-dark-syntax']
items:
type: 'string'
projectHome:
type: 'string'
default: path.join(fs.getHomeDirectory(), 'github')
audioBeep:
type: 'boolean'
default: true
destroyEmptyPanes:
type: 'boolean'
default: true
editor:
type: 'object'
properties:
fontFamily:
type: 'string'
default: ''
fontSize:
type: 'integer'
default: 16
minimum: 1
lineHeight:
type: ['string', 'number']
default: 1.3
showInvisibles:
type: 'boolean'
default: false
showIndentGuide:
type: 'boolean'
default: false
showLineNumbers:
type: 'boolean'
default: true
autoIndent:
type: 'boolean'
default: true
normalizeIndentOnPaste:
type: 'boolean'
default: true
nonWordCharacters:
type: 'string'
default: "/\\()\"':,.;<>~!@#$%^&*|+=[]{}`?-"
preferredLineLength:
type: 'integer'
default: 80
minimum: 1
tabLength:
type: 'integer'
default: 2
minimum: 1
softWrap:
type: 'boolean'
default: false
softTabs:
type: 'boolean'
default: true
softWrapAtPreferredLineLength:
type: 'boolean'
default: false
scrollSensitivity:
type: 'integer'
default: 40
minimum: 10
maximum: 200
scrollPastEnd:
type: 'boolean'
default: false
useHardwareAcceleration:
type: 'boolean'
default: true
confirmCheckoutHeadRevision:
type: 'boolean'
default: true
invisibles:
type: 'object'
properties:
eol:
type: ['boolean', 'string']
default: '\u00ac'
space:
type: ['boolean', 'string']
default: '\u00b7'
tab:
type: ['boolean', 'string']
default: '\u00bb'
cr:
type: ['boolean', 'string']
default: '\u00a4'
+670 -207
Ver Arquivo
@@ -1,39 +1,510 @@
_ = require 'underscore-plus'
fs = require 'fs-plus'
{Emitter} = require 'emissary'
EmitterMixin = require('emissary').Emitter
{Emitter} = require 'event-kit'
CSON = require 'season'
path = require 'path'
async = require 'async'
pathWatcher = require 'pathwatcher'
{deprecate} = require 'grim'
# Essential: Used to access all of Atom's configuration details.
#
# An instance of this class is always available as the `atom.config` global.
#
# ## Best practices
#
# * Create your own root keypath using your package's name.
# * Don't depend on (or write to) configuration keys outside of your keypath.
#
# ## Examples
# ## Getting and setting config settings. Note that with no value set, {::get}
# returns the setting's default value.
#
# ```coffee
# atom.config.set('my-package.key', 'value')
# atom.config.observe 'my-package.key', ->
# console.log 'My configuration changed:', atom.config.get('my-package.key')
# atom.config.get('my-package.myKey') # -> 'defaultValue'
#
# atom.config.set('my-package.myKey', 'value')
# atom.config.get('my-package.myKey') # -> 'value'
# ```
#
# You may want to watch for changes. Use {::observe} to catch changes to the setting.
#
# ```coffee
# atom.config.set('my-package.myKey', 'value')
# atom.config.observe 'my-package.myKey', (newValue) ->
# # `observe` calls immediately and every time the value is changed
# console.log 'My configuration changed:', newValue
# ```
#
# If you want a notification only when the value changes, use {::onDidChange}.
#
# ```coffee
# atom.config.onDidChange 'my-package.myKey', ({newValue, oldValue}) ->
# console.log 'My configuration changed:', newValue, oldValue
# ```
#
# ### Value Coercion
#
# Config settings each have a type specified by way of a
# [schema](json-schema.org). For example we might an integer setting that only
# allows integers greater than `0`:
#
# ```coffee
# # When no value has been set, `::get` returns the setting's default value
# atom.config.get('my-package.anInt') # -> 12
#
# # The string will be coerced to the integer 123
# atom.config.set('my-package.anInt', '123')
# atom.config.get('my-package.anInt') # -> 123
#
# # The string will be coerced to an integer, but it must be greater than 0, so is set to 1
# atom.config.set('my-package.anInt', '-20')
# atom.config.get('my-package.anInt') # -> 1
# ```
#
# ## Defining settings for your package
#
# Define a schema under a `config` key in your package main.
#
# ```coffee
# module.exports =
# # Your config schema
# config:
# someInt:
# type: 'integer'
# default: 23
# minimum: 1
#
# activate: (state) -> # ...
# # ...
# ```
#
# See [Creating a Package](https://atom.io/docs/latest/creating-a-package) for
# more info.
#
# ## Config Schemas
#
# We use [json schema](json-schema.org) which allows you to define your value's
# default, the type it should be, etc. A simple example:
#
# ```coffee
# # We want to provide an `enableThing`, and a `thingVolume`
# config:
# enableThing:
# type: 'boolean'
# default: false
# thingVolume:
# type: 'integer'
# default: 5
# minimum: 1
# maximum: 11
# ```
#
# The type keyword allows for type coercion and validation. If a `thingVolume` is
# set to a string `'10'`, it will be coerced into an integer.
#
# ```coffee
# atom.config.set('my-package.thingVolume', '10')
# atom.config.get('my-package.thingVolume') # -> 10
#
# # It respects the min / max
# atom.config.set('my-package.thingVolume', '400')
# atom.config.get('my-package.thingVolume') # -> 11
#
# # If it cannot be coerced, the value will not be set
# atom.config.set('my-package.thingVolume', 'cats')
# atom.config.get('my-package.thingVolume') # -> 11
# ```
#
# ### Supported Types
#
# The `type` keyword can be a string with any one of the following. You can also
# chain them by specifying multiple in an an array. For example
#
# ```coffee
# config:
# someSetting:
# type: ['boolean', 'integer']
# default: 5
#
# # Then
# atom.config.set('my-package.someSetting', 'true')
# atom.config.get('my-package.someSetting') # -> true
#
# atom.config.set('my-package.someSetting', '12')
# atom.config.get('my-package.someSetting') # -> 12
# ```
#
# #### string
#
# Values must be a string.
#
# ```coffee
# config:
# someSetting:
# type: 'string'
# default: 'hello'
# ```
#
# #### integer
#
# Values will be coerced into integer. Supports the (optional) `minimum` and
# `maximum` keys.
#
# ```coffee
# config:
# someSetting:
# type: 'integer'
# default: 5
# minimum: 1
# maximum: 11
# ```
#
# #### number
#
# Values will be coerced into a number, including real numbers. Supports the
# (optional) `minimum` and `maximum` keys.
#
# ```coffee
# config:
# someSetting:
# type: 'number'
# default: 5.3
# minimum: 1.5
# maximum: 11.5
# ```
#
# #### boolean
#
# Values will be coerced into a Boolean. `'true'` and `'false'` will be coerced into
# a boolean. Numbers, arrays, objects, and anything else will not be coerced.
#
# ```coffee
# config:
# someSetting:
# type: 'boolean'
# default: false
# ```
#
# #### array
#
# Value must be an Array. The types of the values can be specified by a
# subschema in the `items` key.
#
# ```coffee
# config:
# someSetting:
# type: 'array'
# default: [1, 2, 3]
# items:
# type: 'integer'
# minimum: 1.5
# maximum: 11.5
# ```
#
# #### object
#
# Value must be an object. This allows you to nest config options. Sub options
# must be under a `properties key`
#
# ```coffee
# config:
# someSetting:
# type: 'object'
# properties:
# myChildIntOption:
# type: 'integer'
# minimum: 1.5
# maximum: 11.5
# ```
#
# ### Other Supported Keys
#
# #### enum
#
# All types support an `enum` key. The enum key lets you specify all values
# that the config setting can possibly be. `enum` _must_ be an array of values
# of your specified type.
#
# ```coffee
# config:
# someSetting:
# type: 'integer'
# default: 4
# enum: [2, 4, 6, 8]
# ```
#
# ```coffee
# atom.config.set('my-package.someSetting', '2')
# atom.config.get('my-package.someSetting') # -> 2
#
# # will not set values outside of the enum values
# atom.config.set('my-package.someSetting', '3')
# atom.config.get('my-package.someSetting') # -> 2
#
# # If it cannot be coerced, the value will not be set
# atom.config.set('my-package.someSetting', '4')
# atom.config.get('my-package.someSetting') # -> 4
# ```
#
# #### title and description
#
# The settings view will use the `title` and `description` keys to display your
# config setting in a readable way. By default the settings view humanizes your
# config key, so `someSetting` becomes `Some Setting`. In some cases, this is
# confusing for users, and a more descriptive title is useful.
#
# Descriptions will be displayed below the title in the settings view.
#
# ```coffee
# config:
# someSetting:
# title: 'Setting Magnitude'
# description: 'This will affect the blah and the other blah'
# type: 'integer'
# default: 4
# ```
#
# __Note__: You should strive to be so clear in your naming of the setting that
# you do not need to specify a title or description!
#
# ## Best practices
#
# * Don't depend on (or write to) configuration keys outside of your keypath.
#
module.exports =
class Config
Emitter.includeInto(this)
EmitterMixin.includeInto(this)
@schemaEnforcers = {}
@addSchemaEnforcer: (typeName, enforcerFunction) ->
@schemaEnforcers[typeName] ?= []
@schemaEnforcers[typeName].push(enforcerFunction)
@addSchemaEnforcers: (filters) ->
for typeName, functions of filters
for name, enforcerFunction of functions
@addSchemaEnforcer(typeName, enforcerFunction)
@executeSchemaEnforcers: (keyPath, value, schema) ->
error = null
types = schema.type
types = [types] unless Array.isArray(types)
for type in types
try
enforcerFunctions = @schemaEnforcers[type].concat(@schemaEnforcers['*'])
for enforcer in enforcerFunctions
# At some point in one's life, one must call upon an enforcer.
value = enforcer.call(this, keyPath, value, schema)
error = null
break
catch e
error = e
throw error if error?
value
# Created during initialization, available as `atom.config`
constructor: ({@configDirPath, @resourcePath}={}) ->
@emitter = new Emitter
@schema =
type: 'object'
properties: {}
@defaultSettings = {}
@settings = {}
@configFileHasErrors = false
@configFilePath = fs.resolve(@configDirPath, 'config', ['json', 'cson'])
@configFilePath ?= path.join(@configDirPath, 'config.cson')
###
Section: Config Subscription
###
# Essential: Add a listener for changes to a given key path. This is different
# than {::onDidChange} in that it will immediately call your callback with the
# current value of the config entry.
#
# * `keyPath` {String} name of the key to observe
# * `callback` {Function} to call when the value of the key changes.
# * `value` the new value of the key
#
# Returns a {Disposable} with the following keys on which you can call
# `.dispose()` to unsubscribe.
observe: (keyPath, options={}, callback) ->
if _.isFunction(options)
callback = options
options = {}
else
message = ""
message = "`callNow` was set to false. Use ::onDidChange instead. Note that ::onDidChange calls back with different arguments." if options.callNow == false
deprecate "Config::observe no longer supports options. #{message}"
callback(_.clone(@get(keyPath))) unless options.callNow == false
@emitter.on 'did-change', (event) =>
callback(event.newValue) if keyPath? and keyPath.indexOf(event?.keyPath) is 0
# Essential: Add a listener for changes to a given key path. If `keyPath` is
# not specified, your callback will be called on changes to any key.
#
# * `keyPath` (optional) {String} name of the key to observe
# * `callback` {Function} to call when the value of the key changes.
# * `event` {Object}
# * `newValue` the new value of the key
# * `oldValue` the prior value of the key.
# * `keyPath` the keyPath of the changed key
#
# Returns a {Disposable} with the following keys on which you can call
# `.dispose()` to unsubscribe.
onDidChange: (keyPath, callback) ->
if arguments.length is 1
callback = keyPath
keyPath = undefined
@emitter.on 'did-change', (event) =>
callback(event) if not keyPath? or (keyPath? and keyPath.indexOf(event?.keyPath) is 0)
###
Section: Managing Settings
###
# Essential: Retrieves the setting for the given key.
#
# * `keyPath` The {String} name of the key to retrieve.
#
# Returns the value from Atom's default settings, the user's configuration
# file in the type specified by the configuration schema.
get: (keyPath) ->
value = _.valueForKeyPath(@settings, keyPath)
defaultValue = _.valueForKeyPath(@defaultSettings, keyPath)
if value?
value = _.deepClone(value)
valueIsObject = _.isObject(value) and not _.isArray(value)
defaultValueIsObject = _.isObject(defaultValue) and not _.isArray(defaultValue)
if valueIsObject and defaultValueIsObject
_.defaults(value, defaultValue)
else
value = _.deepClone(defaultValue)
value
# Essential: Sets the value for a configuration setting.
#
# This value is stored in Atom's internal configuration file.
#
# * `keyPath` The {String} name of the key.
# * `value` The value of the setting. Passing `undefined` will revert the
# setting to the default value.
#
# Returns a {Boolean}
# * `true` if the value was set.
# * `false` if the value was not able to be coerced to the type specified in the setting's schema.
set: (keyPath, value) ->
unless value == undefined
try
value = @makeValueConformToSchema(keyPath, value)
catch e
return false
@setRawValue(keyPath, value)
@save() unless @configFileHasErrors
true
# Extended: Restore the key path to its default value.
#
# * `keyPath` The {String} name of the key.
#
# Returns the new value.
restoreDefault: (keyPath) ->
@set(keyPath, _.valueForKeyPath(@defaultSettings, keyPath))
@get(keyPath)
# Extended: Get the default value of the key path. _Please note_ that in most
# cases calling this is not necessary! {::get} returns the default value when
# a custom value is not specified.
#
# * `keyPath` The {String} name of the key.
#
# Returns the default value.
getDefault: (keyPath) ->
defaultValue = _.valueForKeyPath(@defaultSettings, keyPath)
_.deepClone(defaultValue)
# Extended: Is the key path value its default value?
#
# * `keyPath` The {String} name of the key.
#
# Returns a {Boolean}, `true` if the current value is the default, `false`
# otherwise.
isDefault: (keyPath) ->
not _.valueForKeyPath(@settings, keyPath)?
# Extended: Retrieve the schema for a specific key path. The shema will tell
# you what type the keyPath expects, and other metadata about the config
# option.
#
# * `keyPath` The {String} name of the key.
#
# Returns an {Object} eg. `{type: 'integer', default: 23, minimum: 1}`.
# Returns `null` when the keyPath has no schema specified.
getSchema: (keyPath) ->
keys = keyPath.split('.')
schema = @schema
for key in keys
break unless schema?
schema = schema.properties[key]
schema
# Extended: Returns a new {Object} containing all of settings and defaults.
getSettings: ->
_.deepExtend(@settings, @defaultSettings)
# Extended: Get the {String} path to the config file being used.
getUserConfigPath: ->
@configFilePath
###
Section: Deprecated
###
getInt: (keyPath) ->
deprecate '''Config::getInt is no longer necessary. Use ::get instead.
Make sure the config option you are accessing has specified an `integer`
schema. See the schema section of
https://atom.io/docs/api/latest/Config for more info.'''
parseInt(@get(keyPath))
getPositiveInt: (keyPath, defaultValue=0) ->
deprecate '''Config::getPositiveInt is no longer necessary. Use ::get instead.
Make sure the config option you are accessing has specified an `integer`
schema with `minimum: 1`. See the schema section of
https://atom.io/docs/api/latest/Config for more info.'''
Math.max(@getInt(keyPath), 0) or defaultValue
toggle: (keyPath) ->
deprecate 'Config::toggle is no longer supported. Please remove from your code.'
@set(keyPath, !@get(keyPath))
unobserve: (keyPath) ->
deprecate 'Config::unobserve no longer does anything. Call `.dispose()` on the object returned by Config::observe instead.'
###
Section: Private
###
pushAtKeyPath: (keyPath, value) ->
arrayValue = @get(keyPath) ? []
result = arrayValue.push(value)
@set(keyPath, arrayValue)
result
unshiftAtKeyPath: (keyPath, value) ->
arrayValue = @get(keyPath) ? []
result = arrayValue.unshift(value)
@set(keyPath, arrayValue)
result
removeAtKeyPath: (keyPath, value) ->
arrayValue = @get(keyPath) ? []
result = _.remove(arrayValue, value)
@set(keyPath, arrayValue)
result
initializeConfigDirectory: (done) ->
return if fs.existsSync(@configDirPath)
@@ -62,210 +533,202 @@ class Config
try
userConfig = CSON.readFileSync(@configFilePath)
_.extend(@settings, userConfig)
@settings = {} # Reset to the defaults
if isPlainObject(userConfig)
@setRecursive(null, userConfig)
else
@emitter.emit 'did-change'
@configFileHasErrors = false
@emit 'updated'
catch e
catch error
@configFileHasErrors = true
console.error "Failed to load user config '#{@configFilePath}'", e.message
console.error e.stack
console.error "Failed to load user config '#{@configFilePath}'", error.message
console.error error.stack
observeUserConfig: ->
@watchSubscription ?= pathWatcher.watch @configFilePath, (eventType) =>
@loadUserConfig() if eventType is 'change' and @watchSubscription?
try
@watchSubscription ?= pathWatcher.watch @configFilePath, (eventType) =>
@loadUserConfig() if eventType is 'change' and @watchSubscription?
catch error
console.error "Failed to watch user config '#{@configFilePath}'", error.message
console.error error.stack
unobserveUserConfig: ->
@watchSubscription?.close()
@watchSubscription = null
setDefaults: (keyPath, defaults) ->
keys = keyPath.split('.')
hash = @defaultSettings
for key in keys
hash[key] ?= {}
hash = hash[key]
_.extend hash, defaults
@emit 'updated'
# Extended: Get the {String} path to the config file being used.
getUserConfigPath: ->
@configFilePath
# Extended: Returns a new {Object} containing all of settings and defaults.
getSettings: ->
_.deepExtend(@settings, @defaultSettings)
# Essential: Retrieves the setting for the given key.
#
# * `keyPath` The {String} name of the key to retrieve.
#
# Returns the value from Atom's default settings, the user's configuration
# file, or `null` if the key doesn't exist in either.
get: (keyPath) ->
value = _.valueForKeyPath(@settings, keyPath)
defaultValue = _.valueForKeyPath(@defaultSettings, keyPath)
if value?
value = _.deepClone(value)
valueIsObject = _.isObject(value) and not _.isArray(value)
defaultValueIsObject = _.isObject(defaultValue) and not _.isArray(defaultValue)
if valueIsObject and defaultValueIsObject
_.defaults(value, defaultValue)
else
value = _.deepClone(defaultValue)
value
# Extended: Retrieves the setting for the given key as an integer.
#
# * `keyPath` The {String} name of the key to retrieve
#
# Returns the value from Atom's default settings, the user's configuration
# file, or `NaN` if the key doesn't exist in either.
getInt: (keyPath) ->
parseInt(@get(keyPath))
# Extended: Retrieves the setting for the given key as a positive integer.
#
# * `keyPath` The {String} name of the key to retrieve
# * `defaultValue` The integer {Number} to fall back to if the value isn't
# positive, defaults to 0.
#
# Returns the value from Atom's default settings, the user's configuration
# file, or `defaultValue` if the key value isn't greater than zero.
getPositiveInt: (keyPath, defaultValue=0) ->
Math.max(@getInt(keyPath), 0) or defaultValue
# Essential: Sets the value for a configuration setting.
#
# This value is stored in Atom's internal configuration file.
#
# * `keyPath` The {String} name of the key.
# * `value` The value of the setting.
#
# Returns the `value`.
set: (keyPath, value) ->
if @get(keyPath) isnt value
defaultValue = _.valueForKeyPath(@defaultSettings, keyPath)
value = undefined if _.isEqual(defaultValue, value)
_.setValueForKeyPath(@settings, keyPath, value)
@update()
value
# Extended: Toggle the value at the key path.
#
# The new value will be `true` if the value is currently falsy and will be
# `false` if the value is currently truthy.
#
# * `keyPath` The {String} name of the key.
#
# Returns the new value.
toggle: (keyPath) ->
@set(keyPath, !@get(keyPath))
# Extended: Restore the key path to its default value.
#
# * `keyPath` The {String} name of the key.
#
# Returns the new value.
restoreDefault: (keyPath) ->
@set(keyPath, _.valueForKeyPath(@defaultSettings, keyPath))
# Extended: Get the default value of the key path.
#
# * `keyPath` The {String} name of the key.
#
# Returns the default value.
getDefault: (keyPath) ->
defaultValue = _.valueForKeyPath(@defaultSettings, keyPath)
_.deepClone(defaultValue)
# Extended: Is the key path value its default value?
#
# * `keyPath` The {String} name of the key.
#
# Returns a {Boolean}, `true` if the current value is the default, `false`
# otherwise.
isDefault: (keyPath) ->
not _.valueForKeyPath(@settings, keyPath)?
# Extended: Push the value to the array at the key path.
#
# * `keyPath` The {String} key path.
# * `value` The value to push to the array.
#
# Returns the new array length {Number} of the setting.
pushAtKeyPath: (keyPath, value) ->
arrayValue = @get(keyPath) ? []
result = arrayValue.push(value)
@set(keyPath, arrayValue)
result
# Extended: Add the value to the beginning of the array at the key path.
#
# * `keyPath` The {String} key path.
# * `value` The value to shift onto the array.
#
# Returns the new array length {Number} of the setting.
unshiftAtKeyPath: (keyPath, value) ->
arrayValue = @get(keyPath) ? []
result = arrayValue.unshift(value)
@set(keyPath, arrayValue)
result
# Public: Remove the value from the array at the key path.
#
# * `keyPath` The {String} key path.
# * `value` The value to remove from the array.
#
# Returns the new array value of the setting.
removeAtKeyPath: (keyPath, value) ->
arrayValue = @get(keyPath) ? []
result = _.remove(arrayValue, value)
@set(keyPath, arrayValue)
result
# Essential: Add a listener for changes to a given key path.
#
# * `keyPath` The {String} name of the key to observe
# * `options` An optional {Object} containing the `callNow` key.
# * `callback` The {Function} to call when the value of the key changes.
# The first argument will be the new value of the key and the
#   second argument will be an {Object} with a `previous` property
# that is the prior value of the key.
#
# Returns an {Object} with the following keys:
# * `off` A {Function} that unobserves the `keyPath` when called.
observe: (keyPath, options={}, callback) ->
if _.isFunction(options)
callback = options
options = {}
value = @get(keyPath)
previousValue = _.clone(value)
updateCallback = =>
value = @get(keyPath)
unless _.isEqual(value, previousValue)
previous = previousValue
previousValue = _.clone(value)
callback(value, {previous})
eventName = "updated.#{keyPath.replace(/\./, '-')}"
subscription = @on eventName, updateCallback
callback(value) if options.callNow ? true
subscription
# Unobserve all callbacks on a given key.
#
# * `keyPath` The {String} name of the key to unobserve.
unobserve: (keyPath) ->
@off("updated.#{keyPath.replace(/\./, '-')}")
update: ->
return if @configFileHasErrors
@save()
@emit 'updated'
save: ->
CSON.writeFileSync(@configFilePath, @settings)
setRawValue: (keyPath, value) ->
defaultValue = _.valueForKeyPath(@defaultSettings, keyPath)
value = undefined if _.isEqual(defaultValue, value)
oldValue = _.clone(@get(keyPath))
_.setValueForKeyPath(@settings, keyPath, value)
newValue = @get(keyPath)
@emitter.emit 'did-change', {oldValue, newValue, keyPath} if newValue isnt oldValue
setRawDefault: (keyPath, value) ->
oldValue = _.clone(@get(keyPath))
_.setValueForKeyPath(@defaultSettings, keyPath, value)
newValue = @get(keyPath)
@emitter.emit 'did-change', {oldValue, newValue, keyPath} if newValue isnt oldValue
setRecursive: (keyPath, value) ->
if value? and isPlainObject(value)
keys = if keyPath? then keyPath.split('.') else []
for key, childValue of value
continue unless value.hasOwnProperty(key)
@setRecursive(keys.concat([key]).join('.'), childValue)
else
try
value = @makeValueConformToSchema(keyPath, value)
@setRawValue(keyPath, value)
catch e
console.warn("'#{keyPath}' could not be set. Attempted value: #{JSON.stringify(value)}; Schema: #{JSON.stringify(@getSchema(keyPath))}")
return
setDefaults: (keyPath, defaults) ->
if defaults? and isPlainObject(defaults)
keys = if keyPath? then keyPath.split('.') else []
for key, childValue of defaults
continue unless defaults.hasOwnProperty(key)
@setDefaults(keys.concat([key]).join('.'), childValue)
else
try
defaults = @makeValueConformToSchema(keyPath, defaults)
@setRawDefault(keyPath, defaults)
catch e
console.warn("'#{keyPath}' could not set the default. Attempted default: #{JSON.stringify(defaults)}; Schema: #{JSON.stringify(@getSchema(keyPath))}")
setSchema: (keyPath, schema) ->
unless isPlainObject(schema)
throw new Error("Error loading schema for #{keyPath}: schemas can only be objects!")
unless typeof schema.type?
throw new Error("Error loading schema for #{keyPath}: schema objects must have a type attribute")
rootSchema = @schema
if keyPath
for key in keyPath.split('.')
rootSchema.type = 'object'
rootSchema.properties ?= {}
properties = rootSchema.properties
properties[key] ?= {}
rootSchema = properties[key]
_.extend rootSchema, schema
@setDefaults(keyPath, @extractDefaultsFromSchema(schema))
extractDefaultsFromSchema: (schema) ->
if schema.default?
schema.default
else if schema.type is 'object' and schema.properties? and isPlainObject(schema.properties)
defaults = {}
properties = schema.properties or {}
defaults[key] = @extractDefaultsFromSchema(value) for key, value of properties
defaults
makeValueConformToSchema: (keyPath, value) ->
value = @constructor.executeSchemaEnforcers(keyPath, value, schema) if schema = @getSchema(keyPath)
value
# Base schema enforcers. These will coerce raw input into the specified type,
# and will throw an error when the value cannot be coerced. Throwing the error
# will indicate that the value should not be set.
#
# Enforcers are run from most specific to least. For a schema with type
# `integer`, all the enforcers for the `integer` type will be run first, in
# order of specification. Then the `*` enforcers will be run, in order of
# specification.
Config.addSchemaEnforcers
'integer':
coerce: (keyPath, value, schema) ->
value = parseInt(value)
throw new Error("Validation failed at #{keyPath}, #{JSON.stringify(value)} cannot be coerced into an int") if isNaN(value) or not isFinite(value)
value
'number':
coerce: (keyPath, value, schema) ->
value = parseFloat(value)
throw new Error("Validation failed at #{keyPath}, #{JSON.stringify(value)} cannot be coerced into a number") if isNaN(value) or not isFinite(value)
value
'boolean':
coerce: (keyPath, value, schema) ->
switch typeof value
when 'string'
if value.toLowerCase() is 'true'
true
else if value.toLowerCase() is 'false'
false
else
throw new Error("Validation failed at #{keyPath}, #{JSON.stringify(value)} must be a boolean or the string 'true' or 'false'")
when 'boolean'
value
else
throw new Error("Validation failed at #{keyPath}, #{JSON.stringify(value)} must be a boolean or the string 'true' or 'false'")
'string':
validate: (keyPath, value, schema) ->
unless typeof value is 'string'
throw new Error("Validation failed at #{keyPath}, #{JSON.stringify(value)} must be a string")
value
'null':
# null sort of isnt supported. It will just unset in this case
coerce: (keyPath, value, schema) ->
throw new Error("Validation failed at #{keyPath}, #{JSON.stringify(value)} must be null") unless value == null
value
'object':
coerce: (keyPath, value, schema) ->
throw new Error("Validation failed at #{keyPath}, #{JSON.stringify(value)} must be an object") unless isPlainObject(value)
return value unless schema.properties?
newValue = {}
for prop, childSchema of schema.properties
continue unless value.hasOwnProperty(prop)
try
newValue[prop] = @executeSchemaEnforcers("#{keyPath}.#{prop}", value[prop], childSchema)
catch error
console.warn "Error setting item in object: #{error.message}"
newValue
'array':
coerce: (keyPath, value, schema) ->
throw new Error("Validation failed at #{keyPath}, #{JSON.stringify(value)} must be an array") unless Array.isArray(value)
itemSchema = schema.items
if itemSchema?
newValue = []
for item in value
try
newValue.push @executeSchemaEnforcers(keyPath, item, itemSchema)
catch error
console.warn "Error setting item in array: #{error.message}"
newValue
else
value
'*':
coerceMinimumAndMaximum: (keyPath, value, schema) ->
return value unless typeof value is 'number'
if schema.minimum? and typeof schema.minimum is 'number'
value = Math.max(value, schema.minimum)
if schema.maximum? and typeof schema.maximum is 'number'
value = Math.min(value, schema.maximum)
value
validateEnum: (keyPath, value, schema) ->
possibleValues = schema.enum
return value unless possibleValues? and Array.isArray(possibleValues) and possibleValues.length
for possibleValue in possibleValues
# Using `isEqual` for possibility of placing enums on array and object schemas
return value if _.isEqual(possibleValue, value)
throw new Error("Validation failed at #{keyPath}, #{JSON.stringify(value)} is not one of #{JSON.stringify(possibleValues)}")
isPlainObject = (value) ->
_.isObject(value) and not _.isArray(value) and not _.isFunction(value) and not _.isString(value)
+5 -5
Ver Arquivo
@@ -7,7 +7,7 @@ Grim = require 'grim'
# Extended: The `Cursor` class represents the little blinking line identifying
# where text can be inserted.
#
# Cursors belong to {Editor}s and have some metadata attached in the form
# Cursors belong to {TextEditor}s and have some metadata attached in the form
# of a {Marker}.
module.exports =
class Cursor extends Model
@@ -17,7 +17,7 @@ class Cursor extends Model
visible: true
needsAutoscroll: null
# Instantiated by an {Editor}
# Instantiated by an {TextEditor}
constructor: ({@editor, @marker, id}) ->
@emitter = new Emitter
@@ -114,7 +114,7 @@ class Cursor extends Model
#
# * `screenPosition` {Array} of two numbers: the screen row, and the screen column.
# * `options` (optional) {Object} with the following keys:
# * `autoscroll` A Boolean which, if `true`, scrolls the {Editor} to wherever
# * `autoscroll` A Boolean which, if `true`, scrolls the {TextEditor} to wherever
# the cursor moves to.
setScreenPosition: (screenPosition, options={}) ->
@changePosition options, =>
@@ -128,7 +128,7 @@ class Cursor extends Model
#
# * `bufferPosition` {Array} of two numbers: the buffer row, and the buffer column.
# * `options` (optional) {Object} with the following keys:
# * `autoscroll` A Boolean which, if `true`, scrolls the {Editor} to wherever
# * `autoscroll` A Boolean which, if `true`, scrolls the {TextEditor} to wherever
# the cursor moves to.
setBufferPosition: (bufferPosition, options={}) ->
@changePosition options, =>
@@ -232,7 +232,7 @@ class Cursor extends Model
else
bufferPosition.column > firstCharacterColumn
# Public: Identifies if this cursor is the last in the {Editor}.
# Public: Identifies if this cursor is the last in the {TextEditor}.
#
# "Last" is defined as the most recently added cursor.
#
+1 -1
Ver Arquivo
@@ -12,7 +12,7 @@ nextId = -> idCounter++
# around marked ranges of text.
#
# {Decoration} objects are not meant to be created directly, but created with
# {Editor::decorateMarker}. eg.
# {TextEditor::decorateMarker}. eg.
#
# ```coffee
# range = editor.getSelectedBufferRange() # any range you like
+12 -6
Ver Arquivo
@@ -1,3 +1,6 @@
{Disposable} = require 'event-kit'
Grim = require 'grim'
# Extended: Manages the deserializers used for serialized state
#
# An instance of this class is always available as the `atom.deserializers`
@@ -24,14 +27,17 @@ class DeserializerManager
# Public: Register the given class(es) as deserializers.
#
# * `classes` One or more classes to register.
add: (classes...) ->
@deserializers[klass.name] = klass for klass in classes
# * `deserializers` One or more deserializers to register. A deserializer can
# be any object with a `.name` property and a `.deserialize()` method. A
# common approach is to register a *constructor* as the deserializer for its
# instances by adding a `.deserialize()` class method.
add: (deserializers...) ->
@deserializers[deserializer.name] = deserializer for deserializer in deserializers
new Disposable =>
delete @deserializers[deserializer.name] for deserializer in deserializers
# Public: Remove the given class(es) as deserializers.
#
# * `classes` One or more classes to remove.
remove: (classes...) ->
Grim.deprecate("Call .dispose() on the Disposable return from ::add instead")
delete @deserializers[name] for {name} in classes
# Public: Deserialize the state and params.
+10 -5
Ver Arquivo
@@ -59,10 +59,10 @@ class DisplayBuffer extends Model
@subscribe @buffer.onDidUpdateMarkers @handleBufferMarkersUpdated
@subscribe @buffer.onDidCreateMarker @handleBufferMarkerCreated
@subscribe atom.config.observe 'editor.preferredLineLength', callNow: false, =>
@subscribe atom.config.onDidChange 'editor.preferredLineLength', =>
@updateWrappedScreenLines() if @isSoftWrapped() and atom.config.get('editor.softWrapAtPreferredLineLength')
@subscribe atom.config.observe 'editor.softWrapAtPreferredLineLength', callNow: false, =>
@subscribe atom.config.onDidChange 'editor.softWrapAtPreferredLineLength', =>
@updateWrappedScreenLines() if @isSoftWrapped()
@updateAllScreenLines()
@@ -315,9 +315,14 @@ class DisplayBuffer extends Model
@charWidthsByScope = {}
getScrollHeight: ->
return 0 unless @getLineHeightInPixels() > 0
lineHeight = @getLineHeightInPixels()
return 0 unless lineHeight > 0
@getLineCount() * @getLineHeightInPixels()
scrollHeight = @getLineCount() * lineHeight
if @height? and atom.config.get('editor.scrollPastEnd')
scrollHeight = scrollHeight + @height - (lineHeight * 3)
scrollHeight
getScrollWidth: ->
@scrollWidth
@@ -434,7 +439,7 @@ class DisplayBuffer extends Model
getSoftWrapColumn: ->
if atom.config.get('editor.softWrapAtPreferredLineLength')
Math.min(@getEditorWidthInChars(), atom.config.getPositiveInt('editor.preferredLineLength', @getEditorWidthInChars()))
Math.min(@getEditorWidthInChars(), atom.config.get('editor.preferredLineLength'))
else
@getEditorWidthInChars()
+3 -3
Ver Arquivo
@@ -8,9 +8,9 @@ class LanguageMode
Emitter.includeInto(this)
Subscriber.includeInto(this)
# Sets up a `LanguageMode` for the given {Editor}.
# Sets up a `LanguageMode` for the given {TextEditor}.
#
# editor - The {Editor} to associate with
# editor - The {TextEditor} to associate with
constructor: (@editor) ->
{@buffer} = @editor
@@ -283,7 +283,7 @@ class LanguageMode
# Given a buffer row, this indents it.
#
# bufferRow - The row {Number}.
# options - An options {Object} to pass through to {Editor::setIndentationForBufferRow}.
# options - An options {Object} to pass through to {TextEditor::setIndentationForBufferRow}.
autoIndentBufferRow: (bufferRow, options) ->
indentLevel = @suggestedIndentForBufferRow(bufferRow)
@editor.setIndentationForBufferRow(bufferRow, indentLevel, options)
+2 -2
Ver Arquivo
@@ -12,7 +12,7 @@ Grim = require 'grim'
#
# ### Marker Creation
#
# Use {Editor::markBufferRange} rather than creating Markers directly.
# Use {TextEditor::markBufferRange} rather than creating Markers directly.
#
# ### Head and Tail
#
@@ -42,7 +42,7 @@ Grim = require 'grim'
# region in any way, including changes that end at the marker's
# start or start at the marker's end. This is the most fragile strategy.
#
# See {Editor::markBufferRange} for usage.
# See {TextEditor::markBufferRange} for usage.
module.exports =
class Marker
EmitterMixin.includeInto(this)
+30 -4
Ver Arquivo
@@ -4,6 +4,7 @@ _ = require 'underscore-plus'
ipc = require 'ipc'
CSON = require 'season'
fs = require 'fs-plus'
{Disposable} = require 'event-kit'
# Extended: Provides a registry for menu items that you'd like to appear in the
# application menu.
@@ -34,10 +35,17 @@ class MenuManager
# * `submenu` An optional {Array} of sub menu items.
# * `command` An optional {String} command to trigger when the item is
# clicked.
#
# Returns a {Disposable} on which `.dispose()` can be called to remove the
# added menu items.
add: (items) ->
@merge(@template, item) for item in items
@update()
undefined
new Disposable => @remove(items)
remove: (items) ->
@unmerge(@template, item) for item in items
@update()
# Should the binding for the given selector be included in the menu
# commands.
@@ -96,11 +104,29 @@ class MenuManager
# appended to the bottom of existing menus where possible.
merge: (menu, item) ->
item = _.deepClone(item)
matchingItem = @findMatchingItem(menu, item)
if item.submenu? and match = _.find(menu, ({label, submenu}) => submenu? and label and @normalizeLabel(label) is @normalizeLabel(item.label))
@merge(match.submenu, i) for i in item.submenu
if matchingItem?
if item.submenu?
@merge(matchingItem.submenu, submenuItem) for submenuItem in item.submenu
else
menu.push(item) unless _.find(menu, ({label}) => label and @normalizeLabel(label) is @normalizeLabel(item.label))
menu.push(item)
unmerge: (menu, item) ->
if matchingItem = @findMatchingItem(menu, item)
if item.submenu?
@unmerge(matchingItem.submenu, submenuItem) for submenuItem in item.submenu
unless matchingItem.submenu?.length > 0
menu.splice(menu.indexOf(matchingItem), 1)
# find an existing menu item matching the given item
findMatchingItem: (menu, {label, submenu}) ->
debugger unless menu?
for item in menu
if @normalizeLabel(item.label) is @normalizeLabel(label) and item.submenu? is submenu?
return item
null
# OSX can't handle displaying accelerators for multiple keystrokes.
# If they are sent across, it will stop processing accelerators for the rest
+3 -3
Ver Arquivo
@@ -260,9 +260,9 @@ class PackageManager
@disabledPackagesSubscription = null
observeDisabledPackages: ->
@disabledPackagesSubscription ?= atom.config.observe 'core.disabledPackages', callNow: false, (disabledPackages, {previous}) =>
packagesToEnable = _.difference(previous, disabledPackages)
packagesToDisable = _.difference(disabledPackages, previous)
@disabledPackagesSubscription ?= atom.config.onDidChange 'core.disabledPackages', ({newValue, oldValue}) =>
packagesToEnable = _.difference(oldValue, newValue)
packagesToDisable = _.difference(newValue, oldValue)
@deactivatePackage(packageName) for packageName in packagesToDisable when @getActivePackage(packageName)
@activatePackage(packageName) for packageName in packagesToEnable
+58 -60
Ver Arquivo
@@ -5,7 +5,7 @@ async = require 'async'
CSON = require 'season'
fs = require 'fs-plus'
EmitterMixin = require('emissary').Emitter
{Emitter} = require 'event-kit'
{Emitter, CompositeDisposable} = require 'event-kit'
Q = require 'q'
{deprecate} = require 'grim'
@@ -99,7 +99,7 @@ class Package
@loadMenus()
@loadStylesheets()
@scopedPropertiesPromise = @loadScopedProperties()
@requireMainModule() unless @hasActivationEvents()
@requireMainModule() unless @hasActivationCommands()
catch error
console.warn "Failed to load package named '#{@name}'", error.stack ? error
@@ -119,8 +119,8 @@ class Package
@activationDeferred = Q.defer()
@measure 'activateTime', =>
@activateResources()
if @hasActivationEvents()
@subscribeToActivationEvents()
if @hasActivationCommands()
@subscribeToActivationCommands()
else
@activateNow()
@@ -143,7 +143,13 @@ class Package
@requireMainModule()
if @mainModule?
atom.config.setDefaults(@name, @mainModule.configDefaults)
if @mainModule.config? and typeof @mainModule.config is 'object'
atom.config.setSchema @name, {type: 'object', properties: @mainModule.config}
else if @mainModule.configDefaults? and typeof @mainModule.configDefaults is 'object'
deprecate """Use a config schema instead. See the configuration section
of https://atom.io/docs/latest/creating-a-package and
https://atom.io/docs/api/latest/Config for more details"""
atom.config.setDefaults(@name, @mainModule.configDefaults)
@mainModule.activateConfig?()
@configActivated = true
@@ -270,7 +276,7 @@ class Package
deactivate: ->
@activationDeferred?.reject()
@activationDeferred = null
@unsubscribeFromActivationEvents()
@activationCommandSubscriptions?.dispose()
@deactivateResources()
@deactivateConfig()
if @mainActivated
@@ -319,64 +325,56 @@ class Package
path.join(@path, 'index')
@mainModulePath = fs.resolveExtension(mainModulePath, ["", _.keys(require.extensions)...])
hasActivationEvents: ->
if _.isArray(@metadata.activationEvents)
return @metadata.activationEvents.some (activationEvent) ->
activationEvent?.length > 0
else if _.isString(@metadata.activationEvents)
return @metadata.activationEvents.length > 0
else if _.isObject(@metadata.activationEvents)
for event, selector of @metadata.activationEvents
return true if event.length > 0 and selector.length > 0
hasActivationCommands: ->
for selector, commands of @getActivationCommands()
return true if commands.length > 0
false
subscribeToActivationEvents: ->
return unless @metadata.activationEvents?
if _.isArray(@metadata.activationEvents)
atom.workspaceView.command(event, @handleActivationEvent) for event in @metadata.activationEvents
else if _.isString(@metadata.activationEvents)
atom.workspaceView.command(@metadata.activationEvents, @handleActivationEvent)
else
atom.workspaceView.command(event, selector, @handleActivationEvent) for event, selector of @metadata.activationEvents
subscribeToActivationCommands: ->
@activationCommandSubscriptions = new CompositeDisposable
for selector, commands of @getActivationCommands()
for command in commands
@activationCommandSubscriptions.add(
atom.commands.add(selector, command, @handleActivationCommand)
)
handleActivationEvent: (event) =>
bubblePathEventHandlers = @disableEventHandlersOnBubblePath(event)
getActivationCommands: ->
return @activationCommands if @activationCommands?
@activationCommands = {}
if @metadata.activationCommands?
for selector, commands of @metadata.activationCommands
@activationCommands[selector] ?= []
if _.isString(commands)
@activationCommands[selector].push(commands)
else if _.isArray(commands)
@activationCommands[selector].push(commands...)
if @metadata.activationEvents?
if _.isArray(@metadata.activationEvents)
for eventName in @metadata.activationEvents
@activationCommands['.workspace'] ?= []
@activationCommands['.workspace'].push(eventName)
else if _.isString(@metadata.activationEvents)
eventName = @metadata.activationEvents
@activationCommands['.workspace'] ?= []
@activationCommands['.workspace'].push(eventName)
else
for eventName, selector of @metadata.activationEvents
selector ?= '.workspace'
@activationCommands[selector] ?= []
@activationCommands[selector].push(eventName)
@activationCommands
handleActivationCommand: (event) =>
event.stopImmediatePropagation()
@activationCommandSubscriptions.dispose()
reenableInvokedListeners = event.disableInvokedListeners()
@activateNow()
$ ?= require('./space-pen-extensions').$
$(event.target).trigger(event)
@restoreEventHandlersOnBubblePath(bubblePathEventHandlers)
@unsubscribeFromActivationEvents()
false
unsubscribeFromActivationEvents: ->
return unless atom.workspaceView?
if _.isArray(@metadata.activationEvents)
atom.workspaceView.off(event, @handleActivationEvent) for event in @metadata.activationEvents
else if _.isString(@metadata.activationEvents)
atom.workspaceView.off(@metadata.activationEvents, @handleActivationEvent)
else
atom.workspaceView.off(event, selector, @handleActivationEvent) for event, selector of @metadata.activationEvents
disableEventHandlersOnBubblePath: (event) ->
bubblePathEventHandlers = []
disabledHandler = ->
$ ?= require('./space-pen-extensions').$
element = $(event.target)
while element.length
if eventHandlers = element.handlers()?[event.type]
for eventHandler in eventHandlers
eventHandler.disabledHandler = eventHandler.handler
eventHandler.handler = disabledHandler
bubblePathEventHandlers.push(eventHandler)
element = element.parent()
bubblePathEventHandlers
restoreEventHandlersOnBubblePath: (eventHandlers) ->
for eventHandler in eventHandlers
eventHandler.handler = eventHandler.disabledHandler
delete eventHandler.disabledHandler
event.target.dispatchEvent(new CustomEvent(event.type, bubbles: true))
reenableInvokedListeners()
# Does the given module path contain native code?
isNativeModule: (modulePath) ->
+1 -1
Ver Arquivo
@@ -8,7 +8,7 @@ Pane = require './pane'
# A container which can contains multiple items to be switched between.
#
# Items can be almost anything however most commonly they're {EditorView}s.
# Items can be almost anything however most commonly they're {TextEditorView}s.
#
# Most packages won't need to use this class, unless you're interested in
# building a package that deals with switching between panes or items.
+3 -3
Ver Arquivo
@@ -4,7 +4,7 @@
Serializable = require 'serializable'
Grim = require 'grim'
PaneAxis = require './pane-axis'
Editor = require './editor'
TextEditor = require './text-editor'
PaneView = null
# Extended: A container for presenting content in the center of the workspace.
@@ -261,9 +261,9 @@ class Pane extends Model
@emitter.emit 'did-change-active-item', @activeItem
@activeItem
# Return an {Editor} if the pane item is an {Editor}, or null otherwise.
# Return an {TextEditor} if the pane item is an {TextEditor}, or null otherwise.
getActiveEditor: ->
@activeItem if @activeItem instanceof Editor
@activeItem if @activeItem instanceof TextEditor
# Public: Return the item at the given index.
#
+5 -5
Ver Arquivo
@@ -11,7 +11,7 @@ Serializable = require 'serializable'
TextBuffer = require 'text-buffer'
{Directory} = require 'pathwatcher'
Editor = require './editor'
TextEditor = require './text-editor'
Task = require './task'
GitRepository = require './git-repository'
@@ -232,12 +232,12 @@ class Project extends Model
###
# Given a path to a file, this constructs and associates a new
# {Editor}, showing the file.
# {TextEditor}, showing the file.
#
# * `filePath` The {String} path of the file to associate with.
# * `options` Options that you can pass to the {Editor} constructor.
# * `options` Options that you can pass to the {TextEditor} constructor.
#
# Returns a promise that resolves to an {Editor}.
# Returns a promise that resolves to an {TextEditor}.
open: (filePath, options={}) ->
filePath = @resolve(filePath)
@bufferForPath(filePath).then (buffer) =>
@@ -330,7 +330,7 @@ class Project extends Model
buffer?.destroy()
buildEditorForBuffer: (buffer, editorOptions) ->
editor = new Editor(_.extend({buffer, registerEditor: true}, editorOptions))
editor = new TextEditor(_.extend({buffer, registerEditor: true}, editorOptions))
editor
eachBuffer: (args...) ->
+2 -2
Ver Arquivo
@@ -1,5 +1,5 @@
{$, View} = require './space-pen-extensions'
EditorView = require './editor-view'
TextEditorView = require './text-editor-view'
fuzzyFilter = require('fuzzaldrin').filter
# Essential: Provides a view that renders a list of items with an editor that
@@ -34,7 +34,7 @@ module.exports =
class SelectListView extends View
@content: ->
@div class: 'select-list', =>
@subview 'filterEditorView', new EditorView(mini: true)
@subview 'filterEditorView', new TextEditorView(mini: true)
@div class: 'error-message', outlet: 'error'
@div class: 'loading', outlet: 'loadingArea', =>
@span class: 'loading-message', outlet: 'loading'
+3 -3
Ver Arquivo
@@ -4,7 +4,7 @@
{Emitter} = require 'event-kit'
Grim = require 'grim'
# Extended: Represents a selection in the {Editor}.
# Extended: Represents a selection in the {TextEditor}.
module.exports =
class Selection extends Model
cursor: null
@@ -93,7 +93,7 @@ class Selection extends Model
# * `screenRange` The new {Range} to select.
# * `options` (optional) {Object} with the keys:
# * `preserveFolds` if `true`, the fold settings are preserved after the selection moves.
# * `autoscroll` if `true`, the {Editor} scrolls to the new selection.
# * `autoscroll` if `true`, the {TextEditor} scrolls to the new selection.
setBufferRange: (bufferRange, options={}) ->
bufferRange = Range.fromObject(bufferRange)
@needsAutoscroll = options.autoscroll
@@ -591,7 +591,7 @@ class Selection extends Model
#
# * `options` (optional) {Object} with the keys:
# * `autoIndent` If `true`, the line is indented to an automatically-inferred
# level. Otherwise, {Editor::getTabText} is inserted.
# level. Otherwise, {TextEditor::getTabText} is inserted.
indent: ({ autoIndent }={}) ->
{ row, column } = @cursor.getBufferPosition()
@@ -14,8 +14,8 @@ ScrollbarCornerComponent = require './scrollbar-corner-component'
SubscriberMixin = require './subscriber-mixin'
module.exports =
EditorComponent = React.createClass
displayName: 'EditorComponent'
TextEditorComponent = React.createClass
displayName: 'TextEditorComponent'
mixins: [SubscriberMixin]
statics:
@@ -236,7 +236,7 @@ EditorComponent = React.createClass
@updateRequestedWhilePaused = true
return
if @performSyncUpdates ? EditorComponent.performSyncUpdates
if @performSyncUpdates ? TextEditorComponent.performSyncUpdates
@forceUpdate()
else unless @updateRequested
@updateRequested = true
@@ -506,16 +506,16 @@ EditorComponent = React.createClass
'editor:move-line-down': -> editor.moveLineDown()
'editor:duplicate-lines': -> editor.duplicateLines()
'editor:join-lines': -> editor.joinLines()
'editor:toggle-indent-guide': -> atom.config.toggle('editor.showIndentGuide')
'editor:toggle-line-numbers': -> atom.config.toggle('editor.showLineNumbers')
'editor:toggle-indent-guide': -> atom.config.set('editor.showIndentGuide', not atom.config.get('editor.showIndentGuide'))
'editor:toggle-line-numbers': -> atom.config.set('editor.showLineNumbers', not atom.config.get('editor.showLineNumbers'))
'editor:scroll-to-cursor': -> editor.scrollToCursorPosition()
'benchmark:scroll': @runScrollBenchmark
addCommandListeners: (listenersByCommandName) ->
{parentView} = @props
addListener = (command, listener) ->
parentView.command command, (event) ->
addListener = (command, listener) =>
@subscribe parentView.command command, (event) ->
event.stopPropagation()
listener(event)
@@ -606,7 +606,7 @@ EditorComponent = React.createClass
onScrollViewScroll: ->
if @isMounted()
console.warn "EditorScrollView scrolled when it shouldn't have."
console.warn "TextEditorScrollView scrolled when it shouldn't have."
scrollViewNode = @refs.scrollView.getDOMNode()
scrollViewNode.scrollTop = 0
scrollViewNode.scrollLeft = 0
@@ -2,24 +2,24 @@
React = require 'react-atom-fork'
{defaults} = require 'underscore-plus'
TextBuffer = require 'text-buffer'
Editor = require './editor'
EditorComponent = require './editor-component'
TextEditor = require './text-editor'
TextEditorComponent = require './text-editor-component'
{deprecate} = require 'grim'
# Public: Represents the entire visual pane in Atom.
#
# The EditorView manages the {Editor}, which manages the file buffers.
# `EditorView` is intentionally sparse. Most of the things you'll want
# to do are on {Editor}.
# The TextEditorView manages the {TextEditor}, which manages the file buffers.
# `TextEditorView` is intentionally sparse. Most of the things you'll want
# to do are on {TextEditor}.
#
# ## Examples
#
# Requiring in packages
#
# ```coffee
# {EditorView} = require 'atom'
# {TextEditorView} = require 'atom'
#
# miniEditorView = new EditorView(mini: true)
# miniEditorView = new TextEditorView(mini: true)
# ```
#
# Iterating over the open editor views
@@ -36,31 +36,7 @@ EditorComponent = require './editor-component'
# console.log(editorView.getModel().getPath())
# ```
module.exports =
class EditorView extends View
@configDefaults:
fontFamily: ''
fontSize: 16
lineHeight: 1.3
showInvisibles: false
showIndentGuide: false
showLineNumbers: true
autoIndent: true
normalizeIndentOnPaste: true
nonWordCharacters: "/\\()\"':,.;<>~!@#$%^&*|+=[]{}`?-"
preferredLineLength: 80
tabLength: 2
softWrap: false
softTabs: true
softWrapAtPreferredLineLength: false
scrollSensitivity: 40
useHardwareAcceleration: true
confirmCheckoutHeadRevision: true
invisibles:
eol: '\u00ac'
space: '\u00b7'
tab: '\u00bb'
cr: '\u00a4'
class TextEditorView extends View
@content: (params) ->
attributes = params.attributes ? {}
attributes.class = 'editor react editor-colors'
@@ -69,23 +45,23 @@ class EditorView extends View
focusOnAttach: false
# The constructor for setting up an `EditorView` instance.
# The constructor for setting up an `TextEditorView` instance.
#
# * `editorOrParams` Either an {Editor}, or an object with one property, `mini`.
# If `mini` is `true`, a "miniature" `Editor` is constructed.
# * `editorOrParams` Either an {TextEditor}, or an object with one property, `mini`.
# If `mini` is `true`, a "miniature" `TextEditor` is constructed.
# Typically, this is ideal for scenarios where you need an Atom editor,
# but without all the chrome, like scrollbars, gutter, _e.t.c._.
#
constructor: (editorOrParams, props) ->
super
if editorOrParams instanceof Editor
if editorOrParams instanceof TextEditor
@editor = editorOrParams
else
{@editor, mini, placeholderText} = editorOrParams
props ?= {}
props.mini = mini
@editor ?= new Editor
@editor ?= new TextEditor
buffer: new TextBuffer
softWrapped: false
tabLength: 2
@@ -94,7 +70,8 @@ class EditorView extends View
placeholderText: placeholderText
props = defaults({@editor, parentView: this}, props)
@component = React.renderComponent(EditorComponent(props), @element)
@componentDescriptor = TextEditorComponent(props)
@component = React.renderComponent(@componentDescriptor, @element)
node = @component.getDOMNode()
@@ -128,7 +105,7 @@ class EditorView extends View
# Public: Get the underlying editor model for this view.
#
# Returns an {Editor}
# Returns an {TextEditor}
getModel: -> @editor
getEditor: -> @editor
@@ -145,6 +122,7 @@ class EditorView extends View
return unless onDom
return if @attached
@attached = true
@component = React.renderComponent(@componentDescriptor, @element) unless @component.isMounted()
@component.checkForVisibilityChange()
@focus() if @focusOnAttach
@@ -171,27 +149,27 @@ class EditorView extends View
@editor.getScrollLeft()
scrollToBottom: ->
deprecate 'Use Editor::scrollToBottom instead. You can get the editor via editorView.getModel()'
deprecate 'Use TextEditor::scrollToBottom instead. You can get the editor via editorView.getModel()'
@editor.setScrollBottom(Infinity)
scrollToScreenPosition: (screenPosition, options) ->
deprecate 'Use Editor::scrollToScreenPosition instead. You can get the editor via editorView.getModel()'
deprecate 'Use TextEditor::scrollToScreenPosition instead. You can get the editor via editorView.getModel()'
@editor.scrollToScreenPosition(screenPosition, options)
scrollToBufferPosition: (bufferPosition, options) ->
deprecate 'Use Editor::scrollToBufferPosition instead. You can get the editor via editorView.getModel()'
deprecate 'Use TextEditor::scrollToBufferPosition instead. You can get the editor via editorView.getModel()'
@editor.scrollToBufferPosition(bufferPosition, options)
scrollToCursorPosition: ->
deprecate 'Use Editor::scrollToCursorPosition instead. You can get the editor via editorView.getModel()'
deprecate 'Use TextEditor::scrollToCursorPosition instead. You can get the editor via editorView.getModel()'
@editor.scrollToCursorPosition()
pixelPositionForBufferPosition: (bufferPosition) ->
deprecate 'Use Editor::pixelPositionForBufferPosition instead. You can get the editor via editorView.getModel()'
deprecate 'Use TextEditor::pixelPositionForBufferPosition instead. You can get the editor via editorView.getModel()'
@editor.pixelPositionForBufferPosition(bufferPosition)
pixelPositionForScreenPosition: (screenPosition) ->
deprecate 'Use Editor::pixelPositionForScreenPosition instead. You can get the editor via editorView.getModel()'
deprecate 'Use TextEditor::pixelPositionForScreenPosition instead. You can get the editor via editorView.getModel()'
@editor.pixelPositionForScreenPosition(screenPosition)
appendToLinesView: (view) ->
@@ -251,13 +229,13 @@ class EditorView extends View
pane = @getPaneView()
pane?.splitDown(pane?.copyActiveItem()).activeView
# Public: Get this {EditorView}'s {PaneView}.
# Public: Get this {TextEditorView}'s {PaneView}.
#
# Returns a {PaneView}
getPaneView: ->
@parent('.item-views').parents('.pane').view()
getPane: ->
deprecate 'Use EditorView::getPaneView() instead'
deprecate 'Use TextEditorView::getPaneView() instead'
@getPaneView()
show: ->
@@ -277,11 +255,11 @@ class EditorView extends View
@editor.pageUp()
getFirstVisibleScreenRow: ->
deprecate 'Use Editor::getFirstVisibleScreenRow instead. You can get the editor via editorView.getModel()'
deprecate 'Use TextEditor::getFirstVisibleScreenRow instead. You can get the editor via editorView.getModel()'
@editor.getFirstVisibleScreenRow()
getLastVisibleScreenRow: ->
deprecate 'Use Editor::getLastVisibleScreenRow instead. You can get the editor via editorView.getModel()'
deprecate 'Use TextEditor::getLastVisibleScreenRow instead. You can get the editor via editorView.getModel()'
@editor.getLastVisibleScreenRow()
getFontFamily: ->
@@ -312,7 +290,7 @@ class EditorView extends View
@component.setShowIndentGuide(showIndentGuide)
setSoftWrap: (softWrapped) ->
deprecate 'Use Editor::setSoftWrapped instead. You can get the editor via editorView.getModel()'
deprecate 'Use TextEditor::setSoftWrapped instead. You can get the editor via editorView.getModel()'
@editor.setSoftWrapped(softWrapped)
setShowInvisibles: (showInvisibles) ->
+72 -72
Ver Arquivo
@@ -16,16 +16,16 @@ TextMateScopeSelector = require('first-mate').ScopeSelector
# Public: This class represents all essential editing state for a single
# {TextBuffer}, including cursor and selection positions, folds, and soft wraps.
# If you're manipulating the state of an editor, use this class. If you're
# interested in the visual appearance of editors, use {EditorView} instead.
# interested in the visual appearance of editors, use {TextEditorView} instead.
#
# A single {TextBuffer} can belong to multiple editors. For example, if the
# same file is open in two different panes, Atom creates a separate editor for
# each pane. If the buffer is manipulated the changes are reflected in both
# editors, but each maintains its own cursor position, folded lines, etc.
#
# ## Accessing Editor Instances
# ## Accessing TextEditor Instances
#
# The easiest way to get hold of `Editor` objects is by registering a callback
# The easiest way to get hold of `TextEditor` objects is by registering a callback
# with `::observeTextEditors` on the `atom.workspace` global. Your callback will
# then be called with all current editor instances and also when any editor is
# created in the future.
@@ -53,7 +53,7 @@ TextMateScopeSelector = require('first-mate').ScopeSelector
# **When in doubt, just default to buffer coordinates**, then experiment with
# soft wraps and folds to ensure your code interacts with them correctly.
module.exports =
class Editor extends Model
class TextEditor extends Model
Serializable.includeInto(this)
atom.deserializers.add(this)
Delegator.includeInto(this)
@@ -113,8 +113,8 @@ class Editor extends Model
@emit 'scroll-left-changed', scrollLeft
@emitter.emit 'did-change-scroll-left', scrollLeft
@subscribe atom.config.observe 'editor.showInvisibles', callNow: false, (show) => @updateInvisibles()
@subscribe atom.config.observe 'editor.invisibles', callNow: false, => @updateInvisibles()
@subscribe atom.config.onDidChange 'editor.showInvisibles', => @updateInvisibles()
@subscribe atom.config.onDidChange 'editor.invisibles', => @updateInvisibles()
atom.workspace?.editorAdded(this) if registerEditor
@@ -163,7 +163,7 @@ class Editor extends Model
@subscribe @displayBuffer.onDidRemoveDecoration (decoration) => @emit 'decoration-removed', decoration
getViewClass: ->
require './editor-view'
require './text-editor-view'
destroyed: ->
@unsubscribe()
@@ -426,57 +426,57 @@ class Editor extends Model
on: (eventName) ->
switch eventName
when 'title-changed'
deprecate("Use Editor::onDidChangeTitle instead")
deprecate("Use TextEditor::onDidChangeTitle instead")
when 'path-changed'
deprecate("Use Editor::onDidChangePath instead")
deprecate("Use TextEditor::onDidChangePath instead")
when 'modified-status-changed'
deprecate("Use Editor::onDidChangeModified instead")
deprecate("Use TextEditor::onDidChangeModified instead")
when 'soft-wrap-changed'
deprecate("Use Editor::onDidChangeSoftWrapped instead")
deprecate("Use TextEditor::onDidChangeSoftWrapped instead")
when 'grammar-changed'
deprecate("Use Editor::onDidChangeGrammar instead")
deprecate("Use TextEditor::onDidChangeGrammar instead")
when 'character-widths-changed'
deprecate("Use Editor::onDidChangeCharacterWidths instead")
deprecate("Use TextEditor::onDidChangeCharacterWidths instead")
when 'contents-modified'
deprecate("Use Editor::onDidStopChanging instead")
deprecate("Use TextEditor::onDidStopChanging instead")
when 'contents-conflicted'
deprecate("Use Editor::onDidConflict instead")
deprecate("Use TextEditor::onDidConflict instead")
when 'will-insert-text'
deprecate("Use Editor::onWillInsertText instead")
deprecate("Use TextEditor::onWillInsertText instead")
when 'did-insert-text'
deprecate("Use Editor::onDidInsertText instead")
deprecate("Use TextEditor::onDidInsertText instead")
when 'cursor-added'
deprecate("Use Editor::onDidAddCursor instead")
deprecate("Use TextEditor::onDidAddCursor instead")
when 'cursor-removed'
deprecate("Use Editor::onDidRemoveCursor instead")
deprecate("Use TextEditor::onDidRemoveCursor instead")
when 'cursor-moved'
deprecate("Use Editor::onDidChangeCursorPosition instead")
deprecate("Use TextEditor::onDidChangeCursorPosition instead")
when 'selection-added'
deprecate("Use Editor::onDidAddSelection instead")
deprecate("Use TextEditor::onDidAddSelection instead")
when 'selection-removed'
deprecate("Use Editor::onDidRemoveSelection instead")
deprecate("Use TextEditor::onDidRemoveSelection instead")
when 'selection-screen-range-changed'
deprecate("Use Editor::onDidChangeSelectionRange instead")
deprecate("Use TextEditor::onDidChangeSelectionRange instead")
when 'decoration-added'
deprecate("Use Editor::onDidAddDecoration instead")
deprecate("Use TextEditor::onDidAddDecoration instead")
when 'decoration-removed'
deprecate("Use Editor::onDidRemoveDecoration instead")
deprecate("Use TextEditor::onDidRemoveDecoration instead")
when 'decoration-updated'
deprecate("Use Decoration::onDidChangeProperties instead. You will get the decoration back from `Editor::decorateMarker()`")
deprecate("Use Decoration::onDidChangeProperties instead. You will get the decoration back from `TextEditor::decorateMarker()`")
when 'decoration-changed'
deprecate("Use Marker::onDidChange instead. eg. `editor::decorateMarker(...).getMarker().onDidChange()`")
when 'screen-lines-changed'
deprecate("Use Editor::onDidChange instead")
deprecate("Use TextEditor::onDidChange instead")
when 'scroll-top-changed'
deprecate("Use Editor::onDidChangeScrollTop instead")
deprecate("Use TextEditor::onDidChangeScrollTop instead")
when 'scroll-left-changed'
deprecate("Use Editor::onDidChangeScrollLeft instead")
deprecate("Use TextEditor::onDidChangeScrollLeft instead")
EmitterMixin::on.apply(this, arguments)
@@ -486,12 +486,12 @@ class Editor extends Model
# Retrieves the current buffer's URI.
getUri: -> @buffer.getUri()
# Create an {Editor} with its initial state based on this object
# Create an {TextEditor} with its initial state based on this object
copy: ->
tabLength = @getTabLength()
displayBuffer = @displayBuffer.copy()
softTabs = @getSoftTabs()
newEditor = new Editor({@buffer, displayBuffer, tabLength, softTabs, suppressCursorCreation: true, registerEditor: true})
newEditor = new TextEditor({@buffer, displayBuffer, tabLength, softTabs, suppressCursorCreation: true, registerEditor: true})
for marker in @findMarkers(editorId: @id)
marker.copy(editorId: newEditor.id, preserveFolds: true)
newEditor
@@ -507,7 +507,7 @@ class Editor extends Model
# Set the number of characters that can be displayed horizontally in the
# editor.
#
# * `editorWidthInChars` A {Number} representing the width of the {EditorView}
# * `editorWidthInChars` A {Number} representing the width of the {TextEditorView}
# in characters.
setEditorWidthInChars: (editorWidthInChars) ->
@displayBuffer.setEditorWidthInChars(editorWidthInChars)
@@ -615,7 +615,7 @@ class Editor extends Model
# * `bufferRow` A {Number} representing a zero-indexed buffer row.
lineTextForBufferRow: (bufferRow) -> @buffer.lineForRow(bufferRow)
lineForBufferRow: (bufferRow) ->
deprecate 'Use Editor::lineTextForBufferRow(bufferRow) instead'
deprecate 'Use TextEditor::lineTextForBufferRow(bufferRow) instead'
@lineTextForBufferRow(bufferRow)
# Essential: Returns a {String} representing the contents of the line at the
@@ -631,13 +631,13 @@ class Editor extends Model
# Returns {TokenizedLine}
tokenizedLineForScreenRow: (screenRow) -> @displayBuffer.tokenizedLineForScreenRow(screenRow)
lineForScreenRow: (screenRow) ->
deprecate "Editor::tokenizedLineForScreenRow(bufferRow) is the new name. But it's private. Try to use Editor::lineTextForScreenRow instead"
deprecate "TextEditor::tokenizedLineForScreenRow(bufferRow) is the new name. But it's private. Try to use TextEditor::lineTextForScreenRow instead"
@tokenizedLineForScreenRow(screenRow)
# {Delegates to: DisplayBuffer.tokenizedLinesForScreenRows}
tokenizedLinesForScreenRows: (start, end) -> @displayBuffer.tokenizedLinesForScreenRows(start, end)
linesForScreenRows: (start, end) ->
deprecate "Use Editor::tokenizedLinesForScreenRows instead"
deprecate "Use TextEditor::tokenizedLinesForScreenRows instead"
@tokenizedLinesForScreenRows(start, end)
# Returns a {Number} representing the line length for the given
@@ -889,7 +889,7 @@ class Editor extends Model
# Deprecated: Use {::duplicateLines} instead.
duplicateLine: ->
deprecate("Use Editor::duplicateLines() instead")
deprecate("Use TextEditor::duplicateLines() instead")
@duplicateLines()
replaceSelectedText: (options={}, fn) ->
@@ -1024,12 +1024,12 @@ class Editor extends Model
# Deprecated: Use {::deleteToBeginningOfWord} instead.
backspaceToBeginningOfWord: ->
deprecate("Use Editor::deleteToBeginningOfWord() instead")
deprecate("Use TextEditor::deleteToBeginningOfWord() instead")
@deleteToBeginningOfWord()
# Deprecated: Use {::deleteToBeginningOfLine} instead.
backspaceToBeginningOfLine: ->
deprecate("Use Editor::deleteToBeginningOfLine() instead")
deprecate("Use TextEditor::deleteToBeginningOfLine() instead")
@deleteToBeginningOfLine()
###
@@ -1075,7 +1075,7 @@ class Editor extends Model
abortTransaction: -> @buffer.abortTransaction()
###
Section: Editor Coordinates
Section: TextEditor Coordinates
###
# Essential: Convert a position in buffer-coordinates to screen-coordinates.
@@ -1438,7 +1438,7 @@ class Editor extends Model
moveUp: (lineCount) ->
@moveCursors (cursor) -> cursor.moveUp(lineCount, moveToEndOfSelection: true)
moveCursorUp: (lineCount) ->
deprecate("Use Editor::moveUp() instead")
deprecate("Use TextEditor::moveUp() instead")
@moveUp(lineCount)
# Essential: Move every cursor down one row in screen coordinates.
@@ -1447,7 +1447,7 @@ class Editor extends Model
moveDown: (lineCount) ->
@moveCursors (cursor) -> cursor.moveDown(lineCount, moveToEndOfSelection: true)
moveCursorDown: (lineCount) ->
deprecate("Use Editor::moveDown() instead")
deprecate("Use TextEditor::moveDown() instead")
@moveDown(lineCount)
# Essential: Move every cursor left one column.
@@ -1456,7 +1456,7 @@ class Editor extends Model
moveLeft: (columnCount) ->
@moveCursors (cursor) -> cursor.moveLeft(columnCount, moveToEndOfSelection: true)
moveCursorLeft: ->
deprecate("Use Editor::moveLeft() instead")
deprecate("Use TextEditor::moveLeft() instead")
@moveLeft()
# Essential: Move every cursor right one column.
@@ -1465,56 +1465,56 @@ class Editor extends Model
moveRight: (columnCount) ->
@moveCursors (cursor) -> cursor.moveRight(columnCount, moveToEndOfSelection: true)
moveCursorRight: ->
deprecate("Use Editor::moveRight() instead")
deprecate("Use TextEditor::moveRight() instead")
@moveRight()
# Essential: Move every cursor to the beginning of its line in buffer coordinates.
moveToBeginningOfLine: ->
@moveCursors (cursor) -> cursor.moveToBeginningOfLine()
moveCursorToBeginningOfLine: ->
deprecate("Use Editor::moveToBeginningOfLine() instead")
deprecate("Use TextEditor::moveToBeginningOfLine() instead")
@moveToBeginningOfLine()
# Essential: Move every cursor to the beginning of its line in screen coordinates.
moveToBeginningOfScreenLine: ->
@moveCursors (cursor) -> cursor.moveToBeginningOfScreenLine()
moveCursorToBeginningOfScreenLine: ->
deprecate("Use Editor::moveToBeginningOfScreenLine() instead")
deprecate("Use TextEditor::moveToBeginningOfScreenLine() instead")
@moveToBeginningOfScreenLine()
# Essential: Move every cursor to the first non-whitespace character of its line.
moveToFirstCharacterOfLine: ->
@moveCursors (cursor) -> cursor.moveToFirstCharacterOfLine()
moveCursorToFirstCharacterOfLine: ->
deprecate("Use Editor::moveToFirstCharacterOfLine() instead")
deprecate("Use TextEditor::moveToFirstCharacterOfLine() instead")
@moveToFirstCharacterOfLine()
# Essential: Move every cursor to the end of its line in buffer coordinates.
moveToEndOfLine: ->
@moveCursors (cursor) -> cursor.moveToEndOfLine()
moveCursorToEndOfLine: ->
deprecate("Use Editor::moveToEndOfLine() instead")
deprecate("Use TextEditor::moveToEndOfLine() instead")
@moveToEndOfLine()
# Essential: Move every cursor to the end of its line in screen coordinates.
moveToEndOfScreenLine: ->
@moveCursors (cursor) -> cursor.moveToEndOfScreenLine()
moveCursorToEndOfScreenLine: ->
deprecate("Use Editor::moveToEndOfScreenLine() instead")
deprecate("Use TextEditor::moveToEndOfScreenLine() instead")
@moveToEndOfScreenLine()
# Essential: Move every cursor to the beginning of its surrounding word.
moveToBeginningOfWord: ->
@moveCursors (cursor) -> cursor.moveToBeginningOfWord()
moveCursorToBeginningOfWord: ->
deprecate("Use Editor::moveToBeginningOfWord() instead")
deprecate("Use TextEditor::moveToBeginningOfWord() instead")
@moveToBeginningOfWord()
# Essential: Move every cursor to the end of its surrounding word.
moveToEndOfWord: ->
@moveCursors (cursor) -> cursor.moveToEndOfWord()
moveCursorToEndOfWord: ->
deprecate("Use Editor::moveToEndOfWord() instead")
deprecate("Use TextEditor::moveToEndOfWord() instead")
@moveToEndOfWord()
# Cursor Extended
@@ -1525,7 +1525,7 @@ class Editor extends Model
moveToTop: ->
@moveCursors (cursor) -> cursor.moveToTop()
moveCursorToTop: ->
deprecate("Use Editor::moveToTop() instead")
deprecate("Use TextEditor::moveToTop() instead")
@moveToTop()
# Extended: Move every cursor to the bottom of the buffer.
@@ -1534,42 +1534,42 @@ class Editor extends Model
moveToBottom: ->
@moveCursors (cursor) -> cursor.moveToBottom()
moveCursorToBottom: ->
deprecate("Use Editor::moveToBottom() instead")
deprecate("Use TextEditor::moveToBottom() instead")
@moveToBottom()
# Extended: Move every cursor to the beginning of the next word.
moveToBeginningOfNextWord: ->
@moveCursors (cursor) -> cursor.moveToBeginningOfNextWord()
moveCursorToBeginningOfNextWord: ->
deprecate("Use Editor::moveToBeginningOfNextWord() instead")
deprecate("Use TextEditor::moveToBeginningOfNextWord() instead")
@moveToBeginningOfNextWord()
# Extended: Move every cursor to the previous word boundary.
moveToPreviousWordBoundary: ->
@moveCursors (cursor) -> cursor.moveToPreviousWordBoundary()
moveCursorToPreviousWordBoundary: ->
deprecate("Use Editor::moveToPreviousWordBoundary() instead")
deprecate("Use TextEditor::moveToPreviousWordBoundary() instead")
@moveToPreviousWordBoundary()
# Extended: Move every cursor to the next word boundary.
moveToNextWordBoundary: ->
@moveCursors (cursor) -> cursor.moveToNextWordBoundary()
moveCursorToNextWordBoundary: ->
deprecate("Use Editor::moveToNextWordBoundary() instead")
deprecate("Use TextEditor::moveToNextWordBoundary() instead")
@moveToNextWordBoundary()
# Extended: Move every cursor to the beginning of the next paragraph.
moveToBeginningOfNextParagraph: ->
@moveCursors (cursor) -> cursor.moveToBeginningOfNextParagraph()
moveCursorToBeginningOfNextParagraph: ->
deprecate("Use Editor::moveToBeginningOfNextParagraph() instead")
deprecate("Use TextEditor::moveToBeginningOfNextParagraph() instead")
@moveToBeginningOfNextParagraph()
# Extended: Move every cursor to the beginning of the previous paragraph.
moveToBeginningOfPreviousParagraph: ->
@moveCursors (cursor) -> cursor.moveToBeginningOfPreviousParagraph()
moveCursorToBeginningOfPreviousParagraph: ->
deprecate("Use Editor::moveToBeginningOfPreviousParagraph() instead")
deprecate("Use TextEditor::moveToBeginningOfPreviousParagraph() instead")
@moveToBeginningOfPreviousParagraph()
# Extended: Returns the most recently added {Cursor}
@@ -1578,7 +1578,7 @@ class Editor extends Model
# Deprecated:
getCursor: ->
deprecate("Use Editor::getLastCursor() instead")
deprecate("Use TextEditor::getLastCursor() instead")
@getLastCursor()
# Extended: Returns the word surrounding the most recently added cursor.
@@ -1660,7 +1660,7 @@ class Editor extends Model
# Essential: Get the {Range}s of all selections in buffer coordinates.
#
# The ranges are sorted by their position in the buffer.
# The ranges are sorted by when the selections were added. Most recent at the end.
#
# Returns an {Array} of {Range}s.
getSelectedBufferRanges: ->
@@ -1706,7 +1706,7 @@ class Editor extends Model
# Essential: Get the {Range}s of all selections in screen coordinates.
#
# The ranges are sorted by their position in the buffer.
# The ranges are sorted by when the selections were added. Most recent at the end.
#
# Returns an {Array} of {Range}s.
getSelectedScreenRanges: ->
@@ -1892,14 +1892,14 @@ class Editor extends Model
selectLinesContainingCursors: ->
@expandSelectionsForward (selection) -> selection.selectLine()
selectLine: ->
deprecate('Use Editor::selectLinesContainingCursors instead')
deprecate('Use TextEditor::selectLinesContainingCursors instead')
@selectLinesContainingCursors()
# Essential: Select the word surrounding each cursor.
selectWordsContainingCursors: ->
@expandSelectionsForward (selection) -> selection.selectWord()
selectWord: ->
deprecate('Use Editor::selectWordsContainingCursors instead')
deprecate('Use TextEditor::selectWordsContainingCursors instead')
@selectWordsContainingCursors()
# Selection Extended
@@ -1959,10 +1959,10 @@ class Editor extends Model
# Deprecated:
getSelection: (index) ->
if index?
deprecate("Use Editor::getSelections()[index] instead when getting a specific selection")
deprecate("Use TextEditor::getSelections()[index] instead when getting a specific selection")
@getSelections()[index]
else
deprecate("Use Editor::getLastSelection() instead")
deprecate("Use TextEditor::getLastSelection() instead")
@getLastSelection()
# Extended: Get current {Selection}s.
@@ -2222,7 +2222,7 @@ class Editor extends Model
# Returns a {Boolean}.
isSoftWrapped: (softWrapped) -> @displayBuffer.isSoftWrapped()
getSoftWrapped: ->
deprecate("Use Editor::isSoftWrapped instead")
deprecate("Use TextEditor::isSoftWrapped instead")
@displayBuffer.isSoftWrapped()
# Essential: Enable or disable soft wrapping for this editor.
@@ -2232,7 +2232,7 @@ class Editor extends Model
# Returns a {Boolean}.
setSoftWrapped: (softWrapped) -> @displayBuffer.setSoftWrapped(softWrapped)
setSoftWrap: (softWrapped) ->
deprecate("Use Editor::setSoftWrapped instead")
deprecate("Use TextEditor::setSoftWrapped instead")
@setSoftWrapped(softWrapped)
# Essential: Toggle soft wrapping for this editor
@@ -2240,7 +2240,7 @@ class Editor extends Model
# Returns a {Boolean}.
toggleSoftWrapped: -> @setSoftWrapped(not @isSoftWrapped())
toggleSoftWrap: ->
deprecate("Use Editor::toggleSoftWrapped instead")
deprecate("Use TextEditor::toggleSoftWrapped instead")
@toggleSoftWrapped()
# Public: Gets the column at which column will soft wrap
@@ -2354,7 +2354,7 @@ class Editor extends Model
# Returns an {Array} of {String}s.
scopesAtCursor: -> @getLastCursor().getScopes()
getCursorScopes: ->
deprecate 'Use Editor::scopesAtCursor() instead'
deprecate 'Use TextEditor::scopesAtCursor() instead'
@scopesAtCursor()
# Essential: Get the syntactic scopes for the given position in buffer
@@ -2574,7 +2574,7 @@ class Editor extends Model
@displayBuffer.outermostFoldsInBufferRowRange(startRow, endRow)
###
Section: Scrolling the Editor
Section: Scrolling the TextEditor
###
# Essential: Scroll the editor to reveal the most recently added cursor if it is
@@ -2676,7 +2676,7 @@ class Editor extends Model
@addSelection(marker)
###
Section: Editor Rendering
Section: TextEditor Rendering
###
# Public: Retrieves the greyed out placeholder of a mini editor.
@@ -2783,7 +2783,7 @@ class Editor extends Model
# Deprecated: Call {::joinLines} instead.
joinLine: ->
deprecate("Use Editor::joinLines() instead")
deprecate("Use TextEditor::joinLines() instead")
@joinLines()
###
@@ -2791,6 +2791,6 @@ class Editor extends Model
###
inspect: ->
"<Editor #{@id}>"
"<TextEditor #{@id}>"
logScreenLines: (start, end) -> @displayBuffer.logLines(start, end)
+4 -4
Ver Arquivo
@@ -2,7 +2,7 @@ path = require 'path'
_ = require 'underscore-plus'
EmitterMixin = require('emissary').Emitter
{Emitter} = require 'event-kit'
{Emitter, Disposable} = require 'event-kit'
{File} = require 'pathwatcher'
fs = require 'fs-plus'
Q = require 'q'
@@ -182,16 +182,16 @@ class ThemeManager
# * `stylesheetPath` A {String} path to the stylesheet that can be an absolute
# path or a relative path that will be resolved against the load path.
#
# Returns the absolute path to the required stylesheet.
# Returns a {Disposable} on which `.dispose()` can be called to remove the
# required stylesheet.
requireStylesheet: (stylesheetPath, type='bundled') ->
if fullPath = @resolveStylesheet(stylesheetPath)
content = @loadStylesheet(fullPath)
@applyStylesheet(fullPath, content, type)
new Disposable => @removeStylesheet(fullPath)
else
throw new Error("Could not find a file at path '#{stylesheetPath}'")
fullPath
unwatchUserStylesheet: ->
@userStylesheetFile?.off()
@userStylesheetFile = null
+2 -3
Ver Arquivo
@@ -25,7 +25,7 @@ class TokenizedBuffer extends Model
constructor: ({@buffer, @tabLength, @invisibles}) ->
@emitter = new Emitter
@tabLength ?= atom.config.getPositiveInt('editor.tabLength', 2)
@tabLength ?= atom.config.get('editor.tabLength')
@subscribe atom.syntax.onDidAddGrammar(@grammarAddedOrUpdated)
@subscribe atom.syntax.onDidUpdateGrammar(@grammarAddedOrUpdated)
@@ -35,8 +35,7 @@ class TokenizedBuffer extends Model
@subscribe @$tabLength.changes, (tabLength) => @retokenizeLines()
@subscribe atom.config.observe 'editor.tabLength', callNow: false, =>
@setTabLength(atom.config.getPositiveInt('editor.tabLength', 2))
@subscribe atom.config.onDidChange 'editor.tabLength', ({newValue}) => @setTabLength(newValue)
@reloadGrammar()
+25 -35
Ver Arquivo
@@ -6,14 +6,13 @@ Delegator = require 'delegato'
{deprecate, logDeprecationWarnings} = require 'grim'
scrollbarStyle = require 'scrollbar-style'
{$, $$, View} = require './space-pen-extensions'
fs = require 'fs-plus'
Workspace = require './workspace'
CommandInstaller = require './command-installer'
PaneView = require './pane-view'
PaneColumnView = require './pane-column-view'
PaneRowView = require './pane-row-view'
PaneContainerView = require './pane-container-view'
Editor = require './editor'
TextEditor = require './text-editor'
atom.commands.add '.workspace',
'window:increase-font-size': -> @getModel().increaseFontSize()
@@ -67,15 +66,6 @@ class WorkspaceView extends View
@version: 4
@configDefaults:
ignoredNames: [".git", ".hg", ".svn", ".DS_Store", "Thumbs.db"]
excludeVcsIgnoredPaths: true
disabledPackages: []
themes: ['atom-dark-ui', 'atom-dark-syntax']
projectHome: path.join(fs.getHomeDirectory(), 'github')
audioBeep: true
destroyEmptyPanes: true
@content: ->
@div class: 'workspace', tabindex: -1, =>
@div class: 'horizontal', outlet: 'horizontal', =>
@@ -155,11 +145,11 @@ class WorkspaceView extends View
@command 'window:focus-pane-on-left', => @focusPaneViewOnLeft()
@command 'window:focus-pane-on-right', => @focusPaneViewOnRight()
@command 'window:save-all', => @saveAll()
@command 'window:toggle-invisibles', -> atom.config.toggle("editor.showInvisibles")
@command 'window:toggle-invisibles', -> atom.config.set("editor.showInvisibles", not atom.config.get("editor.showInvisibles"))
@command 'window:log-deprecation-warnings', -> logDeprecationWarnings()
@command 'window:toggle-auto-indent', ->
atom.config.toggle("editor.autoIndent")
atom.config.set("editor.autoIndent", not atom.config.get("editor.autoIndent"))
@command 'pane:reopen-closed-item', => @getModel().reopenItem()
@@ -183,11 +173,11 @@ class WorkspaceView extends View
###
# Essential: Register a function to be called for every current and future
# editor view in the workspace (only includes {EditorView}s that are pane
# editor view in the workspace (only includes {TextEditorView}s that are pane
# items).
#
# * `callback` A {Function} with an {EditorView} as its only argument.
# * `editorView` {EditorView}
# * `callback` A {Function} with an {TextEditorView} as its only argument.
# * `editorView` {TextEditorView}
#
# Returns a subscription object with an `.off` method that you can call to
# unregister the callback.
@@ -403,7 +393,7 @@ class WorkspaceView extends View
# to the view objects. Also consider using {::eachEditorView}, which will call
# a callback for all current and *future* editor views.
#
# Returns an {Array} of {EditorView}s.
# Returns an {Array} of {TextEditorView}s.
getEditorViews: ->
for editorElement in @panes.element.querySelectorAll('.pane > .item-views > .editor')
$(editorElement).view()
@@ -421,13 +411,13 @@ class WorkspaceView extends View
when 'beep'
deprecate('Use Atom::onDidBeep instead')
when 'cursor:moved'
deprecate('Use Editor::onDidChangeCursorPosition instead')
deprecate('Use TextEditor::onDidChangeCursorPosition instead')
when 'editor:attached'
deprecate('Use Editor::onDidAddTextEditor instead')
deprecate('Use TextEditor::onDidAddTextEditor instead')
when 'editor:detached'
deprecate('Use Editor::onDidDestroy instead')
deprecate('Use TextEditor::onDidDestroy instead')
when 'editor:will-be-removed'
deprecate('Use Editor::onDidDestroy instead')
deprecate('Use TextEditor::onDidDestroy instead')
when 'pane:active-item-changed'
deprecate('Use Pane::onDidChangeActiveItem instead')
when 'pane:active-item-modified-status-changed'
@@ -451,38 +441,38 @@ class WorkspaceView extends View
when 'pane-container:active-pane-item-changed'
deprecate('Use Workspace::onDidChangeActivePaneItem instead')
when 'selection:changed'
deprecate('Use Editor::onDidChangeSelectionRange instead')
deprecate('Use TextEditor::onDidChangeSelectionRange instead')
when 'uri-opened'
deprecate('Use Workspace::onDidOpen instead')
originalWorkspaceViewOn.apply(this, arguments)
EditorView = require './editor-view'
originalEditorViewOn = EditorView::on
EditorView::on = (eventName) ->
TextEditorView = require './text-editor-view'
originalEditorViewOn = TextEditorView::on
TextEditorView::on = (eventName) ->
switch eventName
when 'cursor:moved'
deprecate('Use Editor::onDidChangeCursorPosition instead')
deprecate('Use TextEditor::onDidChangeCursorPosition instead')
when 'editor:attached'
deprecate('Use Editor::onDidAddTextEditor instead')
deprecate('Use TextEditor::onDidAddTextEditor instead')
when 'editor:detached'
deprecate('Use Editor::onDidDestroy instead')
deprecate('Use TextEditor::onDidDestroy instead')
when 'editor:will-be-removed'
deprecate('Use Editor::onDidDestroy instead')
deprecate('Use TextEditor::onDidDestroy instead')
when 'selection:changed'
deprecate('Use Editor::onDidChangeSelectionRange instead')
deprecate('Use TextEditor::onDidChangeSelectionRange instead')
originalEditorViewOn.apply(this, arguments)
originalPaneViewOn = PaneView::on
PaneView::on = (eventName) ->
switch eventName
when 'cursor:moved'
deprecate('Use Editor::onDidChangeCursorPosition instead')
deprecate('Use TextEditor::onDidChangeCursorPosition instead')
when 'editor:attached'
deprecate('Use Editor::onDidAddTextEditor instead')
deprecate('Use TextEditor::onDidAddTextEditor instead')
when 'editor:detached'
deprecate('Use Editor::onDidDestroy instead')
deprecate('Use TextEditor::onDidDestroy instead')
when 'editor:will-be-removed'
deprecate('Use Editor::onDidDestroy instead')
deprecate('Use TextEditor::onDidDestroy instead')
when 'pane:active-item-changed'
deprecate('Use Pane::onDidChangeActiveItem instead')
when 'pane:active-item-modified-status-changed'
@@ -504,7 +494,7 @@ class WorkspaceView extends View
when 'pane:removed'
deprecate('Use Pane::onDidDestroy instead')
when 'selection:changed'
deprecate('Use Editor::onDidChangeSelectionRange instead')
deprecate('Use TextEditor::onDidChangeSelectionRange instead')
originalPaneViewOn.apply(this, arguments)
# Deprecated
+14 -14
Ver Arquivo
@@ -6,7 +6,7 @@ Q = require 'q'
Serializable = require 'serializable'
Delegator = require 'delegato'
{Emitter} = require 'event-kit'
Editor = require './editor'
TextEditor = require './text-editor'
PaneContainer = require './pane-container'
Pane = require './pane'
ViewRegistry = require './view-registry'
@@ -19,7 +19,7 @@ WorkspaceView = null
# editors, and manipulate panes. To add panels, you'll need to use the
# {WorkspaceView} class for now until we establish APIs at the model layer.
#
# * `editor` {Editor} the new editor
# * `editor` {TextEditor} the new editor
#
module.exports =
class Workspace extends Model
@@ -104,7 +104,7 @@ class Workspace extends Model
# editors in the workspace.
#
# * `callback` {Function} to be called with current and future text editors.
# * `editor` An {Editor} that is present in {::getTextEditors} at the time
# * `editor` An {TextEditor} that is present in {::getTextEditors} at the time
# of subscription or that is added at some later time.
#
# Returns a {Disposable} on which `.dispose()` can be called to unsubscribe.
@@ -200,7 +200,7 @@ class Workspace extends Model
#
# * `callback` {Function} to be called panes are added.
# * `event` {Object} with the following keys:
# * `textEditor` {Editor} that was added.
# * `textEditor` {TextEditor} that was added.
# * `pane` {Pane} containing the added text editor.
# * `index` {Number} indicating the index of the added text editor in its
# pane.
@@ -208,7 +208,7 @@ class Workspace extends Model
# Returns a {Disposable} on which `.dispose()` can be called to unsubscribe.
onDidAddTextEditor: (callback) ->
@onDidAddPaneItem ({item, pane, index}) ->
callback({textEditor: item, pane, index}) if item instanceof Editor
callback({textEditor: item, pane, index}) if item instanceof TextEditor
eachEditor: (callback) ->
deprecate("Use Workspace::observeTextEditors instead")
@@ -221,7 +221,7 @@ class Workspace extends Model
editors = []
for pane in @paneContainer.getPanes()
editors.push(item) for item in pane.getItems() when item instanceof Editor
editors.push(item) for item in pane.getItems() when item instanceof TextEditor
editors
@@ -258,7 +258,7 @@ class Workspace extends Model
# If `false`, only the active pane will be searched for
# an existing item for the same URI. Defaults to `false`.
#
# Returns a promise that resolves to the {Editor} for the file URI.
# Returns a promise that resolves to the {TextEditor} for the file URI.
open: (uri, options={}) ->
searchAllPanes = options.searchAllPanes
split = options.split
@@ -352,7 +352,7 @@ class Workspace extends Model
# Public: Register an opener for a uri.
#
# An {Editor} will be used if no openers return a value.
# An {TextEditor} will be used if no openers return a value.
#
# ## Examples
#
@@ -391,17 +391,17 @@ class Workspace extends Model
# Essential: Get all text editors in the workspace.
#
# Returns an {Array} of {Editor}s.
# Returns an {Array} of {TextEditor}s.
getTextEditors: ->
@getPaneItems().filter (item) -> item instanceof Editor
@getPaneItems().filter (item) -> item instanceof TextEditor
# Essential: Get the active item if it is an {Editor}.
# Essential: Get the active item if it is an {TextEditor}.
#
# Returns an {Editor} or `undefined` if the current active item is not an
# {Editor}.
# Returns an {TextEditor} or `undefined` if the current active item is not an
# {TextEditor}.
getActiveTextEditor: ->
activeItem = @getActivePaneItem()
activeItem if activeItem instanceof Editor
activeItem if activeItem instanceof TextEditor
# Deprecated:
getActiveEditor: ->
+1 -1
Ver Arquivo
@@ -173,7 +173,7 @@ body {
-webkit-line-clamp: 10;
overflow: hidden;
&:hover {
&.expanded {
-webkit-line-clamp: inherit;
// overflow: hidden;
}