Comparar commits

..

396 Commits

Autor SHA1 Mensagem Data
Paul Betts 85ca8350e5 Twerk error message 2014-10-15 11:04:32 -07:00
Paul Betts feb97eb7b2 Don't fail create-installer if ATOM_ACCESS_TOKEN isn't set
This lets users create one-off installers locally without having to download
every other release to create deltas.
2014-10-14 16:17:32 -07:00
Nathan Sobo c9869580d4 Use more specific selectors for Workspace::horizontal/::vertical outlets
Fixes #3793
2014-10-14 12:03:42 -06:00
Cheng Zhao f4b67190bd Merge pull request #3825 from atom/atom-shell-v0.18.0
Upgrade to Chrome 38.0.2125.102
2014-10-14 22:28:12 +08:00
Cheng Zhao fcf230ccb5 --harmony_collections is no more needed 2014-10-14 22:01:32 +08:00
Cheng Zhao e7be5adaf1 Upgrade to apm@0.102.0 2014-10-14 21:42:30 +08:00
Cheng Zhao 1377ec5583 Upgrade to atom-shell@0.18.0 2014-10-14 21:42:12 +08:00
Kevin Sawicki 4821c1aa5a Upgrade to language-xml@0.24 2014-10-13 23:07:57 -04:00
Kevin Sawicki 8f97e5f81b Upgrade to language-xml@0.23 2014-10-13 23:03:31 -04:00
Ben Ogle c16d84527d fix specs related to title 2014-10-13 17:48:06 -07:00
Ben Ogle 5c8e20a01d 💄 2014-10-13 17:30:40 -07:00
Ben Ogle ae0b3b47e3 Merge pull request #3814 from Parasithe/master
Add Atom in the title bar
2014-10-13 17:27:16 -07:00
Ben Ogle d73c34af25 Merge pull request #3817 from atom/bo-rename-scopes
Rename scopes -> scopeDescriptor
2014-10-13 17:25:49 -07:00
Ben Ogle 3ba44b955d Deprecate Token::scopes 2014-10-13 17:12:35 -07:00
Ben Ogle b1e9e6b312 Deprecate the use of scopes. 2014-10-13 16:52:49 -07:00
Ben Ogle 22e43600d2 Fix Token::isEqual() to accept scopes for now. 2014-10-13 16:51:10 -07:00
Ben Ogle b9f13d05a8 📝 Update docs for Config::get 2014-10-13 16:50:42 -07:00
Ben Ogle b2cc190a3b Actually get the cursor 2014-10-13 16:35:50 -07:00
Ben Ogle 274bbeec27 Fix deprecate reference 2014-10-13 16:32:17 -07:00
Ben Ogle c0091b4601 scopes -> scopeDescriptor
!!!
2014-10-13 16:30:41 -07:00
Ben Ogle 8cf36af1dc scopesForPosition -> scopeDescriptorForPosition 2014-10-13 16:18:36 -07:00
Ben Ogle 80f52aa3ef Reorganize scopes section 2014-10-13 16:17:01 -07:00
Ben Ogle 56c6c3516a scopesForBufferPosition -> scopeDescriptorForBufferPosition 2014-10-13 16:16:44 -07:00
Ben Ogle f7ab04404c Remove scopesAtCursor from TextEditor class 2014-10-13 16:15:58 -07:00
Ben Ogle b0de88de74 grammarScopeDescriptor -> rootScopeDescriptor 2014-10-13 16:15:05 -07:00
Ben Ogle 6ab002d4be Cursor::getScopes -> Cursor::getScopeDescriptor 2014-10-13 16:14:31 -07:00
Ben Ogle 0588e14850 Only notify when changed key path is really sub path of observed path
Closes #3775
2014-10-13 14:25:55 -07:00
Parasithe 82bf5da9aa Add Atom in the title bar 2014-10-13 17:06:05 -04:00
Paul Betts 9481260f6f Merge pull request #3738 from atom/delta-releases
Squirrel for Windows: Delta Packages
2014-10-13 14:03:22 -07:00
Ben Ogle b8fdaa2dc5 Upgrade markdown-preview 2014-10-13 13:33:30 -07:00
Ben Ogle b57f5a7afa Merge pull request #3812 from atom/bo-speedup-scoped-config
Speedup scoped config
2014-10-13 13:26:45 -07:00
Kevin Sawicki a2a4379974 Merge pull request #3803 from matttbe/master
🐧 .desktop file without capital letter
2014-10-13 15:57:12 -04:00
Ben Ogle 7f1947f7b2 💄 2014-10-13 12:47:19 -07:00
Ben Ogle 55c9b42a74 Clarity 2014-10-13 12:45:43 -07:00
Ben Ogle 9a41b5050e Cache the editor.tabLength config value 2014-10-13 12:34:06 -07:00
Ben Ogle 8ed751f5da Cache scoped settings in the display buffer 2014-10-13 12:22:25 -07:00
Kevin Sawicki 3abe6eb098 Upgrade to language-css@0.21 2014-10-13 11:21:00 -04:00
Kevin Sawicki 4aa7a1ebd8 Upgrade to tree-view@0.130 2014-10-13 11:04:25 -04:00
Kevin Sawicki 4997be54df Upgrade to welcome@0.19 2014-10-13 10:45:11 -04:00
Kevin Sawicki 93902b54e4 Only parse package.json when it is a file
Closes #3784
2014-10-13 10:42:47 -04:00
Kevin Sawicki 1d89150242 Upgrade to settings-view@0.151 2014-10-13 10:32:50 -04:00
Kevin Sawicki ec5819a684 Upgrade to language-python@0.20 2014-10-13 10:12:38 -04:00
Matthieu Baerts d6f43f1858 🐧 .desktop file without capital letter
The .desktop file of Atom was named Atom.desktop but it should be
renamed to atom.desktop because a .desktop should not contain capital
letters as any other .desktop files in /usr/share/applications.

Note that without that, it can be not easy to link the window with the
.desktop file and then a dock/panel could not link a launcher with its
window.
2014-10-12 18:47:06 +02:00
Nathan Sobo b149d47b09 Dispose of subscriptions on SpacePen views in callRemoveHooks
Fixes atom/bracket-matcher#75
2014-10-11 07:25:28 -07:00
Ben Ogle f81f24fea6 Upgrade scoped property settings for mo beta
🐎, less temp objects, more straight forward
2014-10-10 14:16:31 -07:00
Ben Ogle 201345ec5d Allow for optimization of config::get 2014-10-10 12:21:41 -07:00
Ben Ogle 95ee29ea39 Upgrade to scoped-property-store@0.13.0 for 🐎 2014-10-10 12:07:37 -07:00
Kevin Sawicki 4c6803cf6a Merge pull request #3773 from mkoniecz/master
fakeroot is also necessary
2014-10-09 08:56:10 -07:00
Nathan Sobo d3512514d8 Merge pull request #3746 from atom/ns-custom-tag-names
Use custom tag names in core
2014-10-09 07:58:54 -07:00
Nathan Sobo 014e2e6fce Make atom-workspace tag have ‘display: block’ style 2014-10-09 07:39:14 -07:00
Nathan Sobo 1eb3d8bf99 Use ‘atom-text-editor’ custom tag name for TextEditorElement 2014-10-09 07:39:14 -07:00
Nathan Sobo 8e06e88efa Use ‘atom-workspace-axis’ custom tag name instead of ‘div’ 2014-10-09 07:39:14 -07:00
Nathan Sobo 8941b97ed2 Use ‘atom-workspace’ custom tag name for WorkspaceElement 2014-10-09 07:39:14 -07:00
Nathan Sobo eedf4894ae Use ‘atom-pane-container’ custom tag name for PaneContainerElement 2014-10-09 07:39:14 -07:00
Nathan Sobo ddf36a013c Use ‘atom-pane-axis’ custom tag name for PaneAxisElement 2014-10-09 07:39:14 -07:00
Nathan Sobo ee9284e228 Use ‘atom-pane’ custom tag name for PaneElement 2014-10-09 07:39:13 -07:00
Mateusz Konieczny e6e039293a fakeroot is also necessary 2014-10-09 13:11:06 +02:00
Ben Ogle 17bfc29c5b Merge pull request #3718 from atom/bo-scoped-user-config
Add scoped settings to user config
2014-10-08 16:37:20 -07:00
Ben Ogle c154b8f4ec 💄 edit spec descriptions 2014-10-08 16:01:42 -07:00
Ben Ogle a28fed8bae 📝 Expose TextEditor::observeGrammar 2014-10-08 16:01:42 -07:00
Ben Ogle c2081fa569 💄 test 2014-10-08 16:01:42 -07:00
Ben Ogle 841412bd01 Fix spec 2014-10-08 16:01:42 -07:00
Ben Ogle f2d480fc72 getGrammarScopeDescriptor -> getRootScopeDescriptor 2014-10-08 16:01:42 -07:00
Ben Ogle d7cd0de0f8 Upgrade scoped-property-store 2014-10-08 16:01:42 -07:00
Ben Ogle 8910dd1a11 Update to not new format from propertiesForSource 2014-10-08 16:01:42 -07:00
Ben Ogle c315631efd Remove scopeDescriptor from getTabLength 2014-10-08 16:01:42 -07:00
Ben Ogle 26524e87b0 💄 tests 2014-10-08 16:01:42 -07:00
Ben Ogle 2a73d7052d 💄 Clean up spec names 2014-10-08 16:01:42 -07:00
Ben Ogle a3bbbc19b5 Read and write scoped settings from the user’s config 2014-10-08 16:01:42 -07:00
Ben Ogle b44a5dd1f0 Use jasmine json 2014-10-08 16:01:41 -07:00
Ben Ogle f662b3d745 💄 Normalize the names of related subscription things 2014-10-08 16:01:41 -07:00
Ben Ogle d3b00f67f2 Fix spec 2014-10-08 16:01:41 -07:00
Ben Ogle 2605044f19 Scope editor.showIndentGuide 2014-10-08 16:01:41 -07:00
Ben Ogle fbe4cf5677 Invisibles will be set in a call to updateInvisibles() 2014-10-08 16:01:41 -07:00
Ben Ogle ca4c40936a Scope editor.autoIndent 2014-10-08 16:01:41 -07:00
Ben Ogle 6958e0af10 Scope editor.normalizeIndentOnPaste 2014-10-08 16:01:41 -07:00
Ben Ogle 237c668ef0 Scope editor.invisibles and editor.showInvisibles 2014-10-08 16:01:41 -07:00
Ben Ogle c1ff53b02c getCurrentScopeDescriptor -> getGrammarScopeDescriptor 2014-10-08 16:01:41 -07:00
Ben Ogle 938f216cab Scope softWrap, softWrapAtPreferredLineLength, preferredLineLength
`editor.*` config settings
2014-10-08 16:01:41 -07:00
Ben Ogle fbcaabacab Fix weird spec 2014-10-08 16:01:41 -07:00
Ben Ogle 857fd5eaf4 Retokenize when setTabLength() was called. 2014-10-08 16:01:40 -07:00
Ben Ogle 8cd217e50a Handle changes to the tabLength setting 2014-10-08 16:01:40 -07:00
Ben Ogle 339cb02269 Scope editor.tabLength 2014-10-08 16:01:40 -07:00
Ben Ogle 416898e278 Scope usage of editor.nonWordCharacters 2014-10-08 16:01:40 -07:00
Nathan Sobo 6b9345a97d Avoid double clone of menu item now that helper does it 2014-10-08 15:56:13 -07:00
Nathan Sobo d1b2147921 Store specificity based on the cloned item instead of the original 2014-10-08 15:55:41 -07:00
Nathan Sobo 9914c49773 Clone menu items before merging them in in menu-helpers 2014-10-08 15:27:09 -07:00
Nathan Sobo 079ea4862a Merge pull request #3735 from atom/ns-text-editor-custom-element
Convert text editor to custom element
2014-10-08 14:12:35 -07:00
Ben Ogle 9ff435a203 Upgrade find and replace 2014-10-08 13:50:39 -07:00
Ben Ogle 0067e44681 Do not access space-pen view when no elements 2014-10-08 13:48:50 -07:00
Ben Ogle 34a8c6f3bc Use disposables for keymap and menu deactivation 2014-10-08 13:48:50 -07:00
Ben Ogle 9bf7540657 Call dispose not off 2014-10-08 13:48:50 -07:00
Nathan Sobo bc790ee838 Only try selector based listeners if target has .webkitMatchesSelector 2014-10-08 13:21:15 -07:00
Kevin Sawicki 810c851ab3 Upgrade to tree-view@0.129 2014-10-08 13:12:12 -07:00
Kevin Sawicki d015343616 Upgrade to language-css@0.20 2014-10-08 13:11:26 -07:00
Nathan Sobo fab0ac814d Fix checkout-head-revision command 2014-10-08 12:13:13 -07:00
Nathan Sobo eaa3a27328 Add text-editor-element-spec and fix handling of focus and attributes 2014-10-08 12:13:13 -07:00
Nathan Sobo 1e4f4e0882 Move editor commands to global command registry 2014-10-08 12:13:13 -07:00
Nathan Sobo 2d7aa2efda Forward .abortKeyBinding() on CommandRegistry events to original event 2014-10-08 12:13:13 -07:00
Nathan Sobo c63d22b4d1 Update wrap-guide to fix specs 2014-10-08 12:13:13 -07:00
Nathan Sobo 1ca479877e Null guard ::element in TextEditorView::component synthetic property 2014-10-08 12:13:13 -07:00
Nathan Sobo 49dd9b0c07 Update settings-view to fix specs 2014-10-08 12:13:13 -07:00
Nathan Sobo 49e22a41b2 Assign attributes passed to TextEditorView constructor 2014-10-08 12:13:13 -07:00
Nathan Sobo 4eff0f82d8 Destroy model if TextEditorView is explicitly removed for compatibility 2014-10-08 12:13:13 -07:00
Nathan Sobo 003b67ee19 Add TextEditorElement and make TextEditorView a wrapper around it
This is the next step on converting all internal views to custom
elements instead of using SpacePen. The TextEditorElement instances
are associated with ::__spacePenView fields that are used for supporting
legacy access paths via atom.workspaceView.
2014-10-08 12:13:13 -07:00
Nathan Sobo 541c140a19 Merge pull request #3734 from atom/ns-commands-backward-compatibility
Make command registry backward compatible with jQuery::on and ::trigger
2014-10-08 12:10:51 -07:00
Nathan Sobo 19c0540eec Add workspace commands via command registry again
Now that legacy jQuery command listeners are properly integrated with
the command registry, these commands can be moved back.
2014-10-08 11:57:46 -07:00
Nathan Sobo c39f2019db Remove unused __handledByCommandRegistry property 2014-10-08 11:56:50 -07:00
Nathan Sobo f869edee2f Forward preventDefault to original event 2014-10-08 11:56:50 -07:00
Nathan Sobo bb6294cb7c Upgrade keymap to fix simulated command dispatch for detached nodes 2014-10-08 11:56:50 -07:00
Nathan Sobo 5d538fb1b0 💄 spec 2014-10-08 11:56:50 -07:00
Nathan Sobo b78ac53224 Remove logging 2014-10-08 11:56:50 -07:00
Nathan Sobo fb5d826d84 Force native event handler to be registered for activation commands
We use onWillDispatch internally to manage activation commands,
activating packages *before* the activation command starts dispatching.
This means we need to explicitly tell the command registry to subscribe
to the command in question.
2014-10-08 11:56:50 -07:00
Nathan Sobo a75faec64e 💄 2014-10-08 11:56:50 -07:00
Nathan Sobo cdb4ed1327 Integrate jQuery::on and ::trigger with command registry dispatch 2014-10-08 11:56:50 -07:00
Nathan Sobo 0d55a377fb Support inline listeners
This extends the command registry to support listeners registered on
individual elements in addition to selectors. The analogy is inline
styles vs selector-based styles. I’m hoping this will be the foundation
of integrating cleanly with legacy commands registered via our
jQuery::command extension.
2014-10-08 11:56:50 -07:00
Nathan Sobo 2084c45404 💄 spec description 2014-10-08 11:56:50 -07:00
Nathan Sobo 550f0d2a72 Merge pull request #3721 from atom/ns-pure-custom-element-pane-items
Allow pure custom element pane item views
2014-10-08 11:35:36 -07:00
Nathan Sobo ec6614c919 Delegate pane focus methods from workspace to pane container
Fixes #3754
2014-10-08 10:43:40 -07:00
Kevin Sawicki 8db2c4d70a Merge pull request #3750 from mlloreda/patch-1
💄 Remove unnecessary conditional
2014-10-08 08:21:09 -07:00
Miguel Lloreda bcbf01c852 💄 Remove unnecessary conditional
`mkdir -p` is an idempotent operation.
2014-10-07 21:39:36 -04:00
Kevin Sawicki 058ff116b6 Upgrade to language-css@0.19 2014-10-07 14:31:12 -07:00
Kevin Sawicki 33dc3fd684 Upgrade to language-todo@0.13 2014-10-07 14:30:00 -07:00
Nathan Sobo 481c99d852 Use native DOM APIs to remove pane item views 2014-10-07 13:01:56 -06:00
Nathan Sobo 2e6b1cf902 Attach, show and hide pane item views with native DOM APIs
We continue to invoke SpacePen attach hooks on any shim wrappers
for backward compatibility, but SpacePen wrappers are no longer required
for attoch/hide/show as they were previously. Next: removal.
2014-10-07 12:59:12 -06:00
Kevin Sawicki c4e54df100 Prepare 0.137 2014-10-07 09:00:03 -07:00
Paul Betts 20b94c8a4c We've got a valid ReleasesDir, don't clear it 2014-10-06 18:21:23 -07:00
Paul Betts c9ee9b46ed Kill trailing whitespace 2014-10-06 18:12:51 -07:00
Paul Betts 74d1afa8ef Download previous releases so that Squirrel will build updates for them 2014-10-06 18:06:04 -07:00
Paul Betts 182f1324a4 Version bump Squirrel for Windows to 0.5.3 2014-10-06 17:35:38 -07:00
Kevin Sawicki 0b2599565e Upgrade to apm 0.101 2014-10-06 13:29:39 -07:00
Nathan Sobo 34bd103c3d Move remaining workspace commands back to $::command temporarily 2014-10-06 13:19:47 -06:00
Nathan Sobo b00441bee7 Register workspace commands via $::command until compatibility is better
This is a temporary measure.

Currently, commands registered via atom.commands.add don’t mesh properly
with the dispatch of commands registered via jQuery. Didn’t think this
was a big deal until I realized that it broke the ability to preempt
commands on ancestor nodes by calling stopPropagation, which might break
packages.
2014-10-06 13:16:36 -06:00
Kevin Sawicki e33e5df467 Upgrade to language-gfm@0.51 2014-10-06 11:16:55 -07:00
Ben Ogle 212fbd915d Add tabLength 3
Closes #3724
2014-10-06 10:46:31 -07:00
Kevin Sawicki 8bd3e848e0 Upgrade to language-ruby@0.39 2014-10-06 10:05:10 -07:00
Kevin Sawicki 400c8f3dcd Upgrade to language-yaml@0.18 2014-10-06 09:24:12 -07:00
Kevin Sawicki fff752d944 Upgrade to language-css@0.18 2014-10-06 08:51:06 -07:00
Kevin Sawicki f843d07403 Add missing CommandInstaller require
Closes #3729
2014-10-06 08:47:44 -07:00
Nathan Sobo d7efa9bb37 Add PaneElement::attached to prevent shape change 2014-10-03 17:51:44 -06:00
Kevin Sawicki d12a2cf284 Unfocus spec 2014-10-03 15:23:54 -07:00
Kevin Sawicki a807619906 Only call show on active item when attached
Closes atom/settings-view#258
2014-10-03 15:23:21 -07:00
Nathan Sobo e3245ec4b8 Remove logging from spec 2014-10-03 15:56:12 -06:00
Kevin Sawicki 4231d69421 Upgrade to apm 0.100 2014-10-03 14:06:12 -07:00
Ben Ogle 64cc7f98ea Merge pull request #3697 from atom/bo-config-scoped-properties
Add scoped settings to config
2014-10-03 14:01:03 -07:00
Ben Ogle 062fa29895 addRawScopedValue -> setRawScopedValue 2014-10-03 11:57:50 -07:00
Ben Ogle 4e3c8406ee Clean up docs 2014-10-03 11:57:35 -07:00
Ben Ogle 47d5b46a1d Fix warnings from schema incorrectness 2014-10-03 11:42:45 -07:00
Ben Ogle a711e908d5 💄 2014-10-03 10:46:57 -07:00
Ben Ogle 27da0669f3 Moar 📝 2014-10-03 10:46:57 -07:00
Ben Ogle 16fd53c123 Add schemas for scoped configs 2014-10-03 10:46:57 -07:00
Ben Ogle 2475e1a9a6 📝 Update docs for scoped settings 2014-10-03 10:46:57 -07:00
Ben Ogle f724c7fca8 Implement observing on scoped properties 2014-10-03 10:46:57 -07:00
Ben Ogle f8a3ae6104 Pull observing out into special methods for global config 2014-10-03 10:46:57 -07:00
Ben Ogle 899929a1ce addScopedDefaults -> addScopedSettings 2014-10-03 10:46:57 -07:00
Ben Ogle e5d67bb2ff Can remove the clearing of scoped properties
Config is being created on each spec run!
2014-10-03 10:46:57 -07:00
Ben Ogle 3732bdf1e9 Ugh, add settingsForScopeDescriptor back
It’s used by language mode and autocomplete for different things
2014-10-03 10:46:57 -07:00
Ben Ogle aedf02a3e3 Remove +default junk 2014-10-03 10:46:57 -07:00
Ben Ogle d47dbede29 Fix specs 2014-10-03 10:46:57 -07:00
Ben Ogle b1f8c6a6e8 Remove special method for language mode 2014-10-03 10:46:57 -07:00
Ben Ogle a8fad6a0fb Use disposables for removing properties 2014-10-03 10:46:13 -07:00
Ben Ogle e2ac19c17f Use config rather than syntax for scoped properties 2014-10-03 10:46:13 -07:00
Ben Ogle 82990cfc77 rename method 2014-10-03 10:46:13 -07:00
Ben Ogle d72b179b3b Use config in spec helper 2014-10-03 10:46:13 -07:00
Ben Ogle 9a957fe0a4 Fix specs for settings view. 2014-10-03 10:46:13 -07:00
Ben Ogle 21feab322f Add deprecations to the syntax scoped property methods 2014-10-03 10:46:13 -07:00
Ben Ogle dd05c6cec1 Syntax calls into atom.config for scoped properties 2014-10-03 10:46:13 -07:00
Ben Ogle f61a7d0c62 Remove unused method 2014-10-03 10:46:13 -07:00
Ben Ogle 7a5054027e Shift the args before coercing the value 2014-10-03 10:46:13 -07:00
Ben Ogle 778d9fafc5 fix value and default value object checks 2014-10-03 10:46:13 -07:00
Ben Ogle 38e889b7d8 Reorganize private methods into section 2014-10-03 10:46:13 -07:00
Ben Ogle 356f4bec7c Basic scoped settings in Config works 2014-10-03 10:46:13 -07:00
Ben Ogle 8533286114 Move internal things into an internal section 2014-10-03 10:46:13 -07:00
Kevin Sawicki 98d31a1d30 💄 Remove some lint 2014-10-02 17:54:23 -07:00
Kevin Sawicki 59aa3a446c Upgrade to apm 0.99 2014-10-02 16:57:16 -07:00
Kevin Sawicki 679031ce83 Upgrade to text-buffer@3.2.8 2014-10-02 16:50:53 -07:00
Kevin Sawicki 3860091c62 Upgrade to scoped-property-store@0.11 2014-10-02 16:46:25 -07:00
Kevin Sawicki 06af3f38c0 Upgrade to tree-view@0.128 2014-10-02 16:37:57 -07:00
Kevin Sawicki da6f664903 Upgrade to snippets@0.55 2014-10-02 16:08:54 -07:00
Nathan Sobo 4c124b8174 Merge pull request #3633 from atom/ns-workspace-custom-elements
Use custom elements for workspace views
2014-10-02 16:00:31 -06:00
Kevin Sawicki 4a818d76d6 Upgrade to language-go@0.18 2014-10-02 14:15:02 -07:00
Kevin Sawicki 811758aec7 Prepare 0.136 2014-10-02 10:56:20 -07:00
Kevin Sawicki a1dc7daf48 unless -> if 2014-10-02 10:04:26 -07:00
Kevin Sawicki fd66348658 Use isFinite instead of isNaN 2014-10-02 10:02:57 -07:00
Kevin Sawicki 0de17d1b84 Call process.kill with a number
This appears to have changed in node 0.11.14 to be stricter

Closes #3708
2014-10-02 09:56:17 -07:00
Nathan Sobo 6ce5356505 Fix handling of submenus in conversion of legacy context menu format 2014-10-02 10:47:03 -06:00
Nathan Sobo eff70b07d9 Update docs for context menus 2014-10-02 10:36:29 -06:00
Kevin Sawicki 368c06a95c Upgrade to git-utils@2.1.5 2014-10-02 09:33:46 -07:00
Kevin Sawicki 913e4e4248 Add missing Grim prefix to deprecate calls
Closes #3706
2014-10-02 08:47:23 -07:00
Nathan Sobo 5cb31c874f Properly emit item argument in pane:before-item-destroyed legacy event 2014-10-01 17:58:09 -06:00
Nathan Sobo b24e1fa405 Merge branch 'master' into ns-workspace-custom-elements 2014-10-01 17:15:09 -06:00
Nathan Sobo e44f4fbc84 Fix renaming error throwing exception in checkout-head-revision command 2014-10-01 17:04:34 -06:00
Ben Ogle 28ee1f3598 Fix spec 2014-10-01 14:53:31 -07:00
Ben Ogle 72f40ae647 Fix 📝 2014-10-01 14:25:07 -07:00
Ben Ogle 7f5428e2a4 Update config schema to use some new features. 2014-10-01 12:21:33 -07:00
Nathan Sobo f004f8c45d Merge branch 'master' into ns-workspace-custom-elements
Conflicts:
	spec/pane-view-spec.coffee
	spec/workspace-view-spec.coffee
	src/workspace-view.coffee
	src/workspace.coffee
2014-10-01 11:49:23 -06:00
Nathan Sobo 4c94233895 Merge pull request #3691 from atom/ns-pluralize-project-api
Pluralize Project API
2014-10-01 11:14:30 -06:00
Kevin Sawicki 05ccf8adc3 Prepare 0.135 2014-10-01 10:11:01 -07:00
Nathan Sobo 99b8e159bd Add Project::onDidChangePaths event 2014-10-01 10:48:39 -06:00
Nathan Sobo 33c1ce863e Pluralize Project API
This changes all APIs concerning paths and repositories on the project
to be plural, preparing us to switch to multi-folder projects. It
doesn’t make any changes to actually support multiple folders. Instead
we just wrap the previous return values in singleton arrays.

* constructor ‘path’ params -> ‘paths’
* getRootDirectory -> getDirectories
* getPath -> getPaths
* setPath -> setPaths
* getRepo -> getRepositories
2014-10-01 10:48:39 -06:00
Ben Ogle 0fafc21bc8 Merge pull request #3690 from atom/bo-fix-config-issue
Fix config resetting all values when one changes.
2014-10-01 09:47:29 -07:00
Ben Ogle 57603b3a00 Fix config resetting all values when one changes.
Closes atom/settings-view#257
2014-10-01 09:37:25 -07:00
Kevin Sawicki cd8c6690aa Upgrade to image-view@0.37 2014-10-01 08:40:08 -07:00
Kevin Sawicki 8806eef231 Upgrade to language-xml@0.22 2014-10-01 08:32:59 -07:00
Kevin Sawicki de434fcfbf Upgrade to fs-plus@2.3.1 2014-10-01 08:31:58 -07:00
Cheng Zhao 754429978e Merge pull request #3688 from atom/atom-shell-v0.17.0
Upgrade to atom-shell@0.17.1
2014-10-01 22:04:34 +08:00
Cheng Zhao fdb4cd7e53 Disable DirectWrite, fixes #3540 2014-10-01 21:37:50 +08:00
Cheng Zhao bf19d098d5 Upgrade to atom-shell@0.17.1 2014-10-01 21:27:51 +08:00
Cheng Zhao 5e0c7d3a70 Upgrade to apm@0.98.0 2014-10-01 20:20:43 +08:00
Cheng Zhao c66df2c05a Upgrade to atom-shell@0.17.0 2014-10-01 20:14:32 +08:00
Kevin Sawicki df161d7d9b Upgrade to settings-view@0.149 2014-09-30 16:57:06 -07:00
Kevin Sawicki ebf026def4 📝 Make HEAD all caps in title 2014-09-30 16:13:46 -07:00
Kevin Sawicki a12fb94d77 Specific VCS in config title
Closes atom/settings-view#41
2014-09-30 16:13:46 -07:00
Nathan Sobo 70a804bdb4 Rename Workspace::registerOpener to ::addOpener for consistency 2014-09-30 17:09:35 -06:00
Nathan Sobo 0242e1c4ef Merge pull request #3658 from atom/ns-context-menu-cleanup
Clean up context menu API
2014-09-30 16:38:58 -06:00
Kevin Sawicki f84cb83e1e Use -> arrows 2014-09-30 14:02:10 -07:00
Nathan Sobo 72538891dd Merge remote-tracking branch 'origin/master' into ns-context-menu-cleanup
Conflicts:
	src/menu-manager.coffee
2014-09-30 14:53:10 -06:00
Nathan Sobo 73f6904ab7 Merge pull request #3671 from atom/ns-require-stylesheet-disposable
Return a Disposable from ThemeManager::requireStylesheet
2014-09-30 14:50:56 -06:00
Nathan Sobo 8ebfa495b5 Merge pull request #3670 from atom/ns-register-opener-disposable
Return a Disposable from Workspace::registerOpener
2014-09-30 14:50:46 -06:00
Kevin Sawicki ef1e05fb89 Prepare 0.134 2014-09-30 13:36:38 -07:00
Kevin Sawicki 1f4359d429 Treat debugger statements as lint errors 2014-09-30 13:25:55 -07:00
Nathan Sobo 276102e197 Require grim 2014-09-30 14:24:47 -06:00
Nathan Sobo 99a14c07f5 Return a Disposable from Workspace::registerOpener 2014-09-30 14:13:50 -06:00
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 b2cc28fb5b Rename commandOptions to commandDetail on context menu items 2014-09-30 12:15:56 -06:00
Nathan Sobo f6938183cc Add pane splitting context menu items for all panes
The same menu items remain for `.overlayer` to force them to be ordered
before package context menu items.
2014-09-30 12:06:27 -06:00
Nathan Sobo 4a0c5aaa70 Prevent adjacent menu separators 2014-09-30 12:06:27 -06:00
Nathan Sobo eb929cb7a2 Honor item specificity while still preserving addition order
Rather than using order to specify item precedence, we now construct
a set of menu items for each element traversing upward from the target.
When merging items for a given element, we pass the specificity to the
merge function, which uses it to decide whether or not to clobber
existing items. When assembling the overall menu, we don’t ever clobber
to ensure that items added for elements closer to the target always win
over items matching further up the tree.
2014-09-30 12:06:27 -06:00
Nathan Sobo cf80b92f9a Remove logging 2014-09-30 12:06:27 -06:00
Nathan Sobo 1187b50d90 Put platform items back on .overlayer so they sort before package items 2014-09-30 12:06:27 -06:00
Nathan Sobo 36d5359ef4 Restore original context menu ordering
Previously I used CSS specificity to order the most specific / recently
added menu items for a given element *first* when building up the
context menu. When a duplicate label was found for a given menu I would
refrain from inserting it. Now instead I order things the opposite way.
The most specific / recently added items come later and items with the
same label are clobbered by later items.
2014-09-30 12:06:26 -06:00
Nathan Sobo 915cfe15f5 Clear context menus between specs 2014-09-30 12:06:26 -06:00
Nathan Sobo f082f93ead Update specs for new ContextMenuManager API/behavior
When selectors have the same specificity, menu items added *later*
appear higher in the list.
2014-09-30 12:06:26 -06:00
Nathan Sobo f9bf42db64 Remove commented line 2014-09-30 12:06:26 -06:00
Nathan Sobo ff76e36f7d Only display ‘Inspect Element’ item in dev mode 2014-09-30 12:06:26 -06:00
Nathan Sobo 740778e129 Auto-detect context menu items in the old format 2014-09-30 12:06:26 -06:00
Nathan Sobo 483e746439 Use new format for platform menus 2014-09-30 12:06:26 -06:00
Nathan Sobo aec6df828e fixup! Call context menu item ::created hooks with the click event 2014-09-30 12:06:09 -06:00
Nathan Sobo 703197bcca Deprecate old style calls to ContextMenuManager::add 2014-09-30 12:06:09 -06:00
Nathan Sobo 2142c8e63e :public: Document new ContextMenuManager::add API 2014-09-30 12:06:09 -06:00
Nathan Sobo 782f9c609e Add shouldDisplay hook for context menu items
If present, if a falsy value is returned from this function for a given
context menu invocation, the item will not be displayed.
2014-09-30 12:06:09 -06:00
Nathan Sobo 3a567b3c5b Call context menu item ::created hooks with the click event 2014-09-30 12:06:08 -06:00
Nathan Sobo c5b395579b Add devMode flag to individual items 2014-09-30 12:06:08 -06:00
Nathan Sobo f8225a6441 Make arguments atom.contextMenu.add consistent with atom.menu.add 2014-09-30 12:06:08 -06:00
Nathan Sobo 504c4c7af6 Extract MenuHelpers from MenuManager for reuse by ContextMenuManager 2014-09-30 12:06:08 -06: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 19ff2bd986 Set the project path is the represented file path if undefined for item
This prevents exceptions on the browser process from passing a null
argument over IPC.
2014-09-29 11:21:33 -06:00
Nathan Sobo be7d093a4a Merge remote-tracking branch 'origin/master' into ns-workspace-custom-elements
Conflicts:
	package.json
2014-09-29 11:13:45 -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
Nathan Sobo 0ebedeec3a Merge remote-tracking branch 'origin/master' into ns-workspace-custom-elements
Conflicts:
	package.json
	src/workspace.coffee
2014-09-26 14:49:28 -06:00
Nathan Sobo aa1eb94fa7 Ignore redundant calls to $::attachToDom 2014-09-25 22:17:26 -06:00
Nathan Sobo 8723e69f1c Upgrade status-bar to fix specs 2014-09-25 21:58:44 -06:00
Nathan Sobo b1c5442f93 Upgrade command-palette to fix specs 2014-09-25 21:28:52 -06:00
Nathan Sobo 756a389ccf Don't require Workspace in WorkspaceView 2014-09-25 21:28:09 -06:00
Nathan Sobo 5a72d12026 Don’t use jQuery to attach window listeners in spec-helper
This prevents the command palette spec from failing because it’s
explicitly asserting that no listener registered on the window without
a description should show up in the palette, but core:close is also
registered on the workspace.
2014-09-25 20:57:09 -06:00
Nathan Sobo 06e0919597 Revert "Make $::view return __spacePenView from the first element if present"
This reverts commit edaf1e2ced.
2014-09-25 20:45:18 -06:00
Nathan Sobo 0afe2a55e9 Handle direct construction of WorkspaceView in a better way 2014-09-25 20:40:11 -06:00
Nathan Sobo 3442157e16 Fix command-installer-spec 2014-09-25 20:39:04 -06:00
Nathan Sobo 039d87caa0 Allow WorkspaceView to be instantiated directly for compatibility 2014-09-25 20:17:04 -06:00
Nathan Sobo edaf1e2ced Make $::view return __spacePenView from the first element if present 2014-09-25 20:16:40 -06:00
Nathan Sobo 4b746deb73 Move shell command installation entirely into CommandInstaller 2014-09-25 13:11:15 -06:00
Nathan Sobo 442223f97b 💄 spec language 2014-09-25 12:44:53 -06:00
Nathan Sobo 4207752a08 Rename deprecatedViewEvents to deprecateViewEvents 2014-09-25 12:42:12 -06:00
Nathan Sobo a5781d65c3 Remove methods carried over from old view 2014-09-25 12:36:44 -06:00
Nathan Sobo 9d2bb71109 More cleanup 2014-09-25 12:35:08 -06:00
Nathan Sobo eaa90e6158 Clean up debugging 2014-09-25 12:33:05 -06:00
Nathan Sobo 187e300167 Apply workaround for clearing of focus upon loading of window
After the first window focus event, the focus is getting cleared back
to document.body regardless of the prior active element. Refocusing
workspace on a delay after the first window focus event works around
the problem.
2014-09-25 11:56:29 -06:00
Nathan Sobo 670f3e4946 Add WorkspaceElement 2014-09-25 11:41:09 -06:00
Nathan Sobo ae488fc7fe Update document edited status in workspace model
This also fixes a previous oversight where the status wasn’t updated
when switching between pane items with different modified status.
2014-09-24 17:00:25 -06:00
Nathan Sobo 28deb9dec5 Maintain document.title in the workspace model, not the view 2014-09-24 16:26:54 -06:00
Nathan Sobo 186335d619 Mock out document.title with Object.defineProperty
Previously the WorkspaceView::setTitle was mocked in specs to prevent
the title from changing. But I would like to move the title update logic
without breaking assertions, so now we can assert directly on
document.title.
2014-09-24 15:56:50 -06:00
Nathan Sobo 1c58438124 Move PaneContainerView::confirmClose to the model layer 2014-09-24 15:46:01 -06:00
Nathan Sobo 3e0477ffcb Move shell command installation to workspace model 2014-09-24 15:28:35 -06:00
Nathan Sobo 368ef59b85 Remove stray log 2014-09-24 15:28:34 -06:00
Nathan Sobo 465d2afd95 Remove the old root view properly 2014-09-24 15:28:34 -06:00
Nathan Sobo 32f0eb4f76 Don’t emit repeated attached events for the same PaneView 2014-09-24 15:28:34 -06:00
Nathan Sobo 60a551b308 Only dispose PaneElement subscriptions when pane is destroyed
Not when the element is detached, because it might be reattached.
2014-09-24 15:28:34 -06:00
Nathan Sobo f76f7e17d3 Upgrade space-pen for simulated dom attachment bug fix 2014-09-24 15:28:34 -06:00
Nathan Sobo da87f321e8 Add PaneAxisElement 2014-09-24 15:28:34 -06:00
Nathan Sobo 11ede2d436 Upgrade autosave to fix specs 2014-09-24 15:28:34 -06:00
Nathan Sobo 2cc6c9e4c0 💄 2014-09-24 15:28:34 -06:00
Nathan Sobo 887a7bcaf4 Restore $.fn.element property
We define element in certain space-pen views, but this makes it
available for all jQuery objects. Can’t remove it from the prototype.
2014-09-24 15:28:34 -06:00
Nathan Sobo df37d77895 Remove Pane::getViewClass as we now use a view provider 2014-09-24 15:28:34 -06:00
Nathan Sobo cf8dc29cc5 Use Pane::onDidAddItem instead of ::observeItems
The former includes the index at which the item was added and the latter
does not.
2014-09-24 15:28:33 -06:00
Nathan Sobo de29ca6906 Keep existing PaneView SpacePen API working as before
We will eventually deprecate all access to views via
`atom.workspaceView`, which is the only way to get a reference to
instances of PaneView. Draining the swamp!
2014-09-24 15:28:33 -06:00
Nathan Sobo 4ba3162f3e Handle pane commands on PaneElement via command registry 2014-09-24 15:28:33 -06:00
Nathan Sobo 2710c06313 WIP: First stab at custom element for panes
Still need to create a SpacePen shim for access via `atom.workspaceView`
property so we’re backward compatible with packages, but it basically
works.
2014-09-24 15:28:33 -06:00
132 arquivos alterados com 4522 adições e 1997 exclusões
+1 -1
Ver Arquivo
@@ -6,6 +6,6 @@
"url": "https://github.com/atom/atom.git"
},
"dependencies": {
"atom-package-manager": "0.97.0"
"atom-package-manager": "0.102.0"
}
}
+1 -3
Ver Arquivo
@@ -71,9 +71,7 @@ elif [ $OS == 'Linux' ]; then
ATOM_PATH="$USR_DIRECTORY/share/atom/atom"
DOT_ATOM_DIR="$HOME/.atom"
if [ ! -d "$DOT_ATOM_DIR" ]; then
mkdir -p "$DOT_ATOM_DIR"
fi
mkdir -p "$DOT_ATOM_DIR"
: ${TMPDIR:=/tmp}
+4 -1
Ver Arquivo
@@ -120,7 +120,10 @@ module.exports = (grunt) ->
for child in fs.readdirSync('node_modules') when child isnt '.bin'
directory = path.join('node_modules', child)
{engines, theme} = grunt.file.readJSON(path.join(directory, 'package.json'))
metadataPath = path.join(directory, 'package.json')
continue unless grunt.file.isFile(metadataPath)
{engines, theme} = grunt.file.readJSON(metadataPath)
if engines?.atom?
coffeeConfig.glob_to_multiple.src.push("#{directory}/**/*.coffee")
lessConfig.glob_to_multiple.src.push("#{directory}/**/*.less")
+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"
+1 -1
Ver Arquivo
@@ -26,7 +26,7 @@ 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']}, ->
+16 -11
Ver Arquivo
@@ -12,6 +12,8 @@ module.exports = (grunt) ->
buildDir = grunt.config.get('atom.buildDir')
atomDir = path.join(buildDir, 'Atom')
releasesDir = path.join(buildDir, 'Releases')
atomGitHubToken = process.env.ATOM_ACCESS_TOKEN
packageInfo = grunt.file.readJSON(path.join(atomDir, 'resources', 'app', 'package.json'))
inputTemplate = grunt.file.read(path.join('build', 'windows', 'atom.nuspec.erb'))
@@ -22,20 +24,23 @@ module.exports = (grunt) ->
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]
# We use the previous releases to build deltas for the current release,
# sync down the existing releases directory by rolling through GitHub releases
cmd = 'build/windows/SyncGitHubReleases.exe'
args = ['-r', releasesDir, '-u', 'https://github.com/atom/atom', '-t', atomGitHubToken]
spawn {cmd, args}, (error, result, code) ->
return done(error) if error?
if error?
grunt.log.error "ATOM_ACCESS_TOKEN environment variable not set or invalid, can't download old releases; continuing anyways"
pkgs = pkg for pkg in fs.readdirSync(buildDir) when path.extname(pkg) is '.nupkg'
cmd = 'build/windows/nuget.exe'
args = ['pack', targetNuspecPath, '-BasePath', atomDir, '-OutputDirectory', buildDir]
releasesDir = path.join(buildDir, 'Releases')
spawn {cmd, args}, (error, result, code) ->
return done(error) if error?
# NB: Gonna clear Releases for now, in the future we need to pull down
# the existing version
rm(releasesDir)
pkgs = pkg for pkg in fs.readdirSync(buildDir) when path.extname(pkg) is '.nupkg'
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)
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)
+9 -4
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')
@@ -35,11 +40,11 @@ module.exports = (grunt) ->
mkdir path.dirname(shareDir)
cp shellAppDir, shareDir
# Create Atom.desktop if installation not in temporary folder
# Create atom.desktop if installation not in temporary folder
tmpDir = if process.env.TMPDIR? then process.env.TMPDIR else '/tmp'
if installDir.indexOf(tmpDir) isnt 0
desktopFile = path.join('resources', 'linux', 'Atom.desktop.in')
desktopInstallFile = path.join(installDir, 'share', 'applications', 'Atom.desktop')
desktopFile = path.join('resources', 'linux', 'atom.desktop.in')
desktopInstallFile = path.join(installDir, 'share', 'applications', 'atom.desktop')
{description} = grunt.file.readJSON('package.json')
iconName = path.join(shareDir, 'resources', 'app', 'resources', 'atom.png')
+1 -1
Ver Arquivo
@@ -39,7 +39,7 @@ module.exports = (grunt) ->
getInstalledSize buildDir, (error, installedSize) ->
data = {name, version, description, section, arch, maintainer, installDir, iconName, installedSize}
controlFilePath = fillTemplate(path.join('resources', 'linux', 'debian', 'control'), data)
desktopFilePath = fillTemplate(path.join('resources', 'linux', 'Atom.desktop'), data)
desktopFilePath = fillTemplate(path.join('resources', 'linux', 'atom.desktop'), data)
icon = path.join('resources', 'atom.png')
cmd = path.join('script', 'mkdeb')
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.
+3
Ver Arquivo
@@ -10,5 +10,8 @@
},
"no_interpolation_in_single_quotes": {
"level": "error"
},
"no_debugger": {
"level": "error"
}
}
-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.
+6 -6
Ver Arquivo
@@ -6,25 +6,25 @@ Keymap files are encoded as JSON or CSON files containing nested hashes. They
work much like stylesheets, but instead of applying style properties to elements
matching the selector, they specify the meaning of keystrokes on elements
matching the selector. Here is an example of some bindings that apply when
keystrokes pass through elements with the class `.editor`:
keystrokes pass through `atom-text-editor` elements:
```coffee
'.editor':
'atom-text-editor':
'cmd-delete': 'editor:delete-to-beginning-of-line'
'alt-backspace': 'editor:delete-to-beginning-of-word'
'ctrl-A': 'editor:select-to-first-character-of-line'
'ctrl-shift-e': 'editor:select-to-end-of-line'
'cmd-left': 'editor:move-to-first-character-of-line'
'.editor:not(.mini)'
'atom-text-editor:not(.mini)'
'cmd-alt-[': 'editor:fold-current-row'
'cmd-alt-]': 'editor:unfold-current-row'
```
Beneath the first selector are several bindings, mapping specific *keystroke
patterns* to *commands*. When an element with the `.editor` class is focused and
patterns* to *commands*. When an element with the `atom-text-editor` class is focused and
`cmd-delete` is pressed, an custom DOM event called
`editor:delete-to-beginning-of-line` is emitted on the `.editor` element.
`editor:delete-to-beginning-of-line` is emitted on the `atom-text-editor` element.
The second selector group also targets editors, but only if they don't have the
`.mini` class. In this example, the commands for code folding don't really make
@@ -91,7 +91,7 @@ the current keystroke sequence and continue searching from its parent. If you
want to remove a binding from a keymap you don't control, such as keymaps in
Atom core or in packages, use the `unset!` directive.
For example, the following code removes the keybinding for `a` in the Tree View,
For example, the following code removes the keybinding for `a` in the Tree View,
which is normally used to trigger the `tree-view:add-file` command:
```coffee
+2 -2
Ver Arquivo
@@ -11,7 +11,7 @@ have methods that are view-specific. For example, you could call both general
and view-specific on the global `atom.workspaceView` instance:
```coffeescript
atom.workspaceView.find('.editor.active') # standard jQuery method
atom.workspaceView.find('atom-text-editor.active') # standard jQuery method
atom.workspaceView.getActiveEditor() # view-specific method
```
@@ -20,7 +20,7 @@ If you retrieve a jQuery wrapper for an element associated with a view, use the
```coffeescript
# this is a plain jQuery object; you can't call view-specific methods
editorElement = atom.workspaceView.find('.editor.active')
editorElement = atom.workspaceView.find('atom-text-editor.active')
# get the view object by calling `.view()` to call view-specific methods
editorView = editorElement.view()
+1 -1
Ver Arquivo
@@ -16,7 +16,7 @@ Ubuntu LTS 12.04 64-bit is the recommended platform.
### Ubuntu / Debian
* `sudo apt-get install build-essential git libgnome-keyring-dev`
* `sudo apt-get install build-essential git libgnome-keyring-dev fakeroot`
* Instructions for [Node.js](https://github.com/joyent/node/wiki/Installing-Node.js-via-package-manager#ubuntu-mint-elementary-os).
### Fedora
+48 -17
Ver Arquivo
@@ -207,37 +207,44 @@ specific parts of the interface, like adding a file in the tree-view:
```coffeescript
'context-menu':
'.tree-view':
'Add file': 'tree-view:add-file'
'.workspace':
'Inspect Element': 'core:inspect'
'.tree-view': [
{label: 'Add file', command: 'tree-view:add-file'}
]
'atom-workspace': [
{label: 'Inspect Element', command: 'core:inspect'}
]
```
To add your own item to the application menu simply create a top level
`context-menu` key in any menu configuration file in _menus_. This can be a
JSON or [CSON] file.
Context menus are created by determining which element was selected and
then adding all of the menu items whose selectors match that element (in
the order which they were loaded). The process is then repeated for the
elements until reaching the top of the DOM tree.
Context menus are created by determining which element was selected and then
adding all of the menu items whose selectors match that element (in the order
which they were loaded). The process is then repeated for the elements until
reaching the top of the DOM tree.
In the example above, the `Add file` item will only appear when the focused item
or one of its parents has the `tree-view` class applied to it.
You can also add separators and submenus to your context menus. To add a
submenu, pass in another object instead of a command. To add a separator, use
`-` for the command of the item.
submenu, provide a `submenu` key instead of a command. To add a separator, add
an item with a single `type: 'separator'` key/value pair.
```coffeescript
'context-menu':
'.workspace':
'Inspect Element': 'core:inspect'
'Separator': '-'
'Text':
'Select All': 'core:select-all'
'Another Separator': '-'
'Deleted Selected Text': 'core:delete'
'atom-workspace': [
{
label: 'Text'
submenu: [
{label: 'Inspect Element', command: 'core:inspect'}
{type: 'separator'}
{label: 'Selector All', command: 'core:select-all'}
{type: 'separator'}
{label: 'Deleted Selected Text', command: 'core:delete'}
]
}
]
```
## Snippets
@@ -321,6 +328,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 +422,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/
+3 -3
Ver Arquivo
@@ -60,10 +60,10 @@ with events in specific contexts. Here's a small example, excerpted from Atom's
built-in keymaps:
```coffee
'.editor':
'atom-text-editor':
'enter': 'editor:newline'
'.mini.editor input':
'atom-text-editor.mini input':
'enter': 'core:confirm'
```
@@ -169,7 +169,7 @@ For example, to change the color of the cursor, you could add the following
rule to your _~/.atom/styles.less_ file:
```less
.editor.is-focused .cursor {
atom-text-editor.is-focused .cursor {
border-color: pink;
}
```
+3 -3
Ver Arquivo
@@ -91,13 +91,13 @@ _keymaps/ascii-art.cson_ and add a key binding linking `ctrl-alt-a` to the
you don't need it anymore. When finished, the file will look like this:
```coffeescript
'.editor':
'atom-text-editor':
'cmd-alt-a': 'ascii-art:convert'
```
Notice `.editor` on the first line. Just like CSS, keymap selectors *scope* key
Notice `atom-text-editor` on the first line. Just like CSS, keymap selectors *scope* key
bindings so they only apply to specific elements. In this case, our binding is
only active for elements matching the `.editor` selector. If the Tree View has
only active for elements matching the `atom-text-editor` selector. If the Tree View has
focus, pressing `cmd-alt-a` won't trigger the `ascii-art:convert` command. But
if the editor has focus, the `ascii-art:convert` method *will* be triggered.
More information on key bindings can be found in the
+1 -1
Ver Arquivo
@@ -9,7 +9,7 @@
#
# Here's an example taken from Atom's built-in keymap:
#
# '.editor':
# 'atom-text-editor':
# 'enter': 'editor:newline'
#
# '.workspace':
+2 -2
Ver Arquivo
@@ -12,10 +12,10 @@
}
.editor {
atom-text-editor {
}
.editor .cursor {
atom-text-editor .cursor {
}
+3 -3
Ver Arquivo
@@ -1,11 +1,11 @@
'.editor':
'atom-text-editor':
# Platform Bindings
'home': 'editor:move-to-first-character-of-line'
'end': 'editor:move-to-end-of-screen-line'
'shift-home': 'editor:select-to-first-character-of-line'
'shift-end': 'editor:select-to-end-of-line'
'.editor:not(.mini)':
'atom-text-editor:not(.mini)':
# Atom Specific
'ctrl-C': 'editor:copy-path'
@@ -18,7 +18,7 @@
'.tool-panel.panel-left, .tool-panel.panel-right':
'escape': 'tool-panel:unfocus'
'.editor !important, .editor.mini !important':
'atom-text-editor !important, atom-text-editor.mini !important':
'escape': 'editor:consolidate-selections'
# allow standard input fields to work correctly
+2 -2
Ver Arquivo
@@ -100,7 +100,7 @@
'cmd-8': 'pane:show-item-8'
'cmd-9': 'pane:show-item-9'
'.editor':
'atom-text-editor':
# Platform Bindings
'alt-left': 'editor:move-to-beginning-of-word'
'alt-right': 'editor:move-to-end-of-word'
@@ -134,7 +134,7 @@
'cmd-l': 'editor:select-line'
'ctrl-t': 'editor:transpose'
'.workspace .editor:not(.mini)':
'atom-workspace atom-text-editor:not(.mini)':
# Atom specific
'alt-cmd-z': 'editor:checkout-head-revision'
'cmd-<': 'editor:scroll-to-cursor'
+1 -1
Ver Arquivo
@@ -1,4 +1,4 @@
'.editor':
'atom-text-editor':
'alt-f': 'editor:move-to-end-of-word'
'alt-F': 'editor:select-to-end-of-word'
'alt-b': 'editor:move-to-beginning-of-word'
+2 -2
Ver Arquivo
@@ -79,7 +79,7 @@
'alt-8': 'pane:show-item-8'
'alt-9': 'pane:show-item-9'
'.workspace .editor':
'atom-workspace atom-text-editor':
# Platform Bindings
'ctrl-left': 'editor:move-to-beginning-of-word'
'ctrl-right': 'editor:move-to-end-of-word'
@@ -99,7 +99,7 @@
'ctrl-k ctrl-l': 'editor:lower-case'
'ctrl-l': 'editor:select-line'
'.workspace .editor:not(.mini)':
'atom-workspace atom-text-editor:not(.mini)':
# Atom specific
'alt-ctrl-z': 'editor:checkout-head-revision'
'ctrl-<': 'editor:scroll-to-cursor'
+2 -2
Ver Arquivo
@@ -74,7 +74,7 @@
'ctrl-k ctrl-left': 'window:focus-pane-on-left'
'ctrl-k ctrl-right': 'window:focus-pane-on-right'
'.workspace .editor':
'atom-workspace atom-text-editor':
# Platform Bindings
'ctrl-left': 'editor:move-to-beginning-of-word'
'ctrl-right': 'editor:move-to-end-of-word'
@@ -94,7 +94,7 @@
'ctrl-k ctrl-l': 'editor:lower-case'
'ctrl-l': 'editor:select-line'
'.workspace .editor:not(.mini)':
'atom-workspace atom-text-editor:not(.mini)':
# Atom specific
'alt-ctrl-z': 'editor:checkout-head-revision'
'ctrl-<': 'editor:scroll-to-cursor'
+24 -8
Ver Arquivo
@@ -196,11 +196,27 @@
]
'context-menu':
'.overlayer':
'Undo': 'core:undo'
'Redo': 'core:redo'
'Cut': 'core:cut'
'Copy': 'core:copy'
'Paste': 'core:paste'
'Delete': 'core:delete'
'Select All': 'core:select-all'
'.overlayer': [
{label: 'Undo', command: 'core:undo'}
{label: 'Redo', command: 'core:redo'}
{type: 'separator'}
{label: 'Cut', command: 'core:cut'}
{label: 'Copy', command: 'core:copy'}
{label: 'Paste', command: 'core:paste'}
{label: 'Delete', command: 'core:delete'}
{label: 'Select All', command: 'core:select-all'}
{type: 'separator'}
{label: 'Split Up', command: 'pane:split-up'}
{label: 'Split Down', command: 'pane:split-down'}
{label: 'Split Left', command: 'pane:split-left'}
{label: 'Split Right', command: 'pane:split-right'}
{type: 'separator'}
]
'atom-pane': [
{type: 'separator'}
{label: 'Split Up', command: 'pane:split-up'}
{label: 'Split Down', command: 'pane:split-down'}
{label: 'Split Left', command: 'pane:split-left'}
{label: 'Split Right', command: 'pane:split-right'}
{type: 'separator'}
]
+24 -8
Ver Arquivo
@@ -153,11 +153,27 @@
]
'context-menu':
'.overlayer':
'Undo': 'core:undo'
'Redo': 'core:redo'
'Cut': 'core:cut'
'Copy': 'core:copy'
'Paste': 'core:paste'
'Delete': 'core:delete'
'Select All': 'core:select-all'
'.overlayer': [
{label: 'Undo', command: 'core:undo'}
{label: 'Redo', command: 'core:redo'}
{type: 'separator'}
{label: 'Cut', command: 'core:cut'}
{label: 'Copy', command: 'core:copy'}
{label: 'Paste', command: 'core:paste'}
{label: 'Delete', command: 'core:delete'}
{label: 'Select All', command: 'core:select-all'}
{type: 'separator'}
{label: 'Split Up', command: 'pane:split-up'}
{label: 'Split Down', command: 'pane:split-down'}
{label: 'Split Left', command: 'pane:split-left'}
{label: 'Split Right', command: 'pane:split-right'}
{type: 'separator'}
]
'atom-pane': [
{type: 'separator'}
{label: 'Split Up', command: 'pane:split-up'}
{label: 'Split Down', command: 'pane:split-down'}
{label: 'Split Left', command: 'pane:split-left'}
{label: 'Split Right', command: 'pane:split-right'}
{type: 'separator'}
]
+24 -8
Ver Arquivo
@@ -171,11 +171,27 @@
]
'context-menu':
'.overlayer':
'Undo': 'core:undo'
'Redo': 'core:redo'
'Cut': 'core:cut'
'Copy': 'core:copy'
'Paste': 'core:paste'
'Delete': 'core:delete'
'Select All': 'core:select-all'
'.overlayer': [
{label: 'Undo', command: 'core:undo'}
{label: 'Redo', command: 'core:redo'}
{type: 'separator'}
{label: 'Cut', command: 'core:cut'}
{label: 'Copy', command: 'core:copy'}
{label: 'Paste', command: 'core:paste'}
{label: 'Delete', command: 'core:delete'}
{label: 'Select All', command: 'core:select-all'}
{type: 'separator'}
{label: 'Split Up', command: 'pane:split-up'}
{label: 'Split Down', command: 'pane:split-down'}
{label: 'Split Left', command: 'pane:split-left'}
{label: 'Split Right', command: 'pane:split-right'}
{type: 'separator'}
]
'atom-pane': [
{type: 'separator'}
{label: 'Split Up', command: 'pane:split-up'}
{label: 'Split Down', command: 'pane:split-down'}
{label: 'Split Left', command: 'pane:split-left'}
{label: 'Split Right', command: 'pane:split-right'}
{type: 'separator'}
]
+32 -31
Ver Arquivo
@@ -1,7 +1,7 @@
{
"name": "atom",
"productName": "Atom",
"version": "0.132.0",
"version": "0.137.0",
"description": "A hackable text editor for the 21st Century.",
"main": "./src/browser/main.js",
"repository": {
@@ -17,10 +17,10 @@
"url": "http://github.com/atom/atom/raw/master/LICENSE.md"
}
],
"atomShellVersion": "0.16.2",
"atomShellVersion": "0.18.0",
"dependencies": {
"async": "0.2.6",
"atom-keymap": "^2.1.3",
"atom-keymap": "^2.2.1",
"bootstrap": "git+https://github.com/atom/bootstrap.git#6af81906189f1747fd6c93479e3d998ebe041372",
"clear-cut": "0.4.0",
"coffee-script": "1.7.0",
@@ -28,13 +28,14 @@
"delegato": "^1",
"emissary": "^1.3.1",
"event-kit": "0.7.2",
"first-mate": "^2.1.2",
"fs-plus": "^2.2.6",
"first-mate": "^2.2.0",
"fs-plus": "^2.3.1",
"fstream": "0.1.24",
"fuzzaldrin": "^2.1",
"git-utils": "^2.1.4",
"git-utils": "^2.1.5",
"grim": "0.12.0",
"guid": "0.0.10",
"jasmine-json": "~0.0",
"jasmine-tagged": "^1.1.2",
"less-cache": "0.15.0",
"mixto": "^1",
@@ -50,14 +51,14 @@
"reactionary-atom-fork": "^1.0.0",
"runas": "1.0.1",
"scandal": "1.0.2",
"scoped-property-store": "^0.9.0",
"scoped-property-store": "^0.13.2",
"scrollbar-style": "^1.0.2",
"season": "^1.0.2",
"semver": "1.1.4",
"serializable": "^1",
"space-pen": "3.4.7",
"space-pen": "3.8.0",
"temp": "0.7.0",
"text-buffer": "^3.2.6",
"text-buffer": "^3.2.8",
"theorist": "^1.0.2",
"underscore-plus": "^1.5.1",
"vm-compatibility-layer": "0.1.0"
@@ -74,48 +75,48 @@
"archive-view": "0.37.0",
"autocomplete": "0.32.0",
"autoflow": "0.18.0",
"autosave": "0.17.0",
"autosave": "0.18.0",
"background-tips": "0.17.0",
"bookmarks": "0.28.0",
"bracket-matcher": "0.60.0",
"command-palette": "0.26.0",
"bracket-matcher": "0.61.0",
"command-palette": "0.27.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.140.0",
"fuzzy-finder": "0.58.0",
"git-diff": "0.39.0",
"go-to-line": "0.25.0",
"grammar-selector": "0.34.0",
"image-view": "0.36.0",
"image-view": "0.37.0",
"incompatible-packages": "0.9.0",
"keybinding-resolver": "0.20.0",
"link": "0.25.0",
"markdown-preview": "0.103.0",
"markdown-preview": "0.104.0",
"metrics": "0.36.0",
"open-on-github": "0.30.0",
"package-generator": "0.31.0",
"release-notes": "0.36.0",
"settings-view": "0.147.0",
"snippets": "0.53.0",
"settings-view": "0.151.0",
"snippets": "0.55.0",
"spell-check": "0.42.0",
"status-bar": "0.45.0",
"status-bar": "0.46.0",
"styleguide": "0.30.0",
"symbols-view": "0.66.0",
"tabs": "0.53.0",
"tabs": "0.54.0",
"timecop": "0.22.0",
"tree-view": "0.127.0",
"tree-view": "0.130.0",
"update-package-dependencies": "0.6.0",
"welcome": "0.18.0",
"welcome": "0.19.0",
"whitespace": "0.25.0",
"wrap-guide": "0.22.0",
"wrap-guide": "0.23.0",
"language-c": "0.28.0",
"language-coffee-script": "0.34.0",
"language-css": "0.17.0",
"language-gfm": "0.50.0",
"language-coffee-script": "0.35.0",
"language-css": "0.21.0",
"language-gfm": "0.51.0",
"language-git": "0.9.0",
"language-go": "0.17.0",
"language-go": "0.18.0",
"language-html": "0.26.0",
"language-hyperlink": "0.12.0",
"language-java": "0.11.0",
@@ -128,18 +129,18 @@
"language-perl": "0.9.0",
"language-php": "0.16.0",
"language-property-list": "0.7.0",
"language-python": "0.19.0",
"language-ruby": "0.38.0",
"language-python": "0.20.0",
"language-ruby": "0.39.0",
"language-ruby-on-rails": "0.18.0",
"language-sass": "0.22.0",
"language-shellscript": "0.8.0",
"language-source": "0.8.0",
"language-sql": "0.11.0",
"language-text": "0.6.0",
"language-todo": "0.12.0",
"language-todo": "0.13.0",
"language-toml": "0.12.0",
"language-xml": "0.21.0",
"language-yaml": "0.17.0"
"language-xml": "0.24.0",
"language-yaml": "0.18.0"
},
"private": true,
"scripts": {
+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
Ver Arquivo
@@ -47,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
+1 -1
Ver Arquivo
@@ -20,7 +20,7 @@ describe "install(commandPath, callback)", ->
installDone = false
installError = null
installer.install commandFilePath, false, (error) ->
installer.createSymlink commandFilePath, false, (error) ->
installDone = true
installError = error
+23 -4
Ver Arquivo
@@ -14,9 +14,12 @@ describe "CommandRegistry", ->
parent.appendChild(child)
document.querySelector('#jasmine-content').appendChild(parent)
registry = new CommandRegistry(parent)
registry = new CommandRegistry
describe "command dispatch", ->
afterEach ->
registry.destroy()
describe "when a command event is dispatched on an element", ->
it "invokes callbacks with selectors matching the target", ->
called = false
registry.add '.grandchild', 'command', (event) ->
@@ -48,6 +51,16 @@ describe "CommandRegistry", ->
grandchild.dispatchEvent(new CustomEvent('command', bubbles: true))
expect(calls).toEqual ['child', 'parent']
it "invokes inline listeners prior to listeners applied via selectors", ->
calls = []
registry.add '.grandchild', 'command', -> calls.push('grandchild')
registry.add child, 'command', -> calls.push('child-inline')
registry.add '.child', 'command', -> calls.push('child')
registry.add '.parent', 'command', -> calls.push('parent')
grandchild.dispatchEvent(new CustomEvent('command', bubbles: true))
expect(calls).toEqual ['grandchild', 'child-inline', 'child', 'parent']
it "orders multiple matching listeners for an element by selector specificity", ->
child.classList.add('foo', 'bar')
calls = []
@@ -86,8 +99,6 @@ describe "CommandRegistry", ->
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)
@@ -95,6 +106,14 @@ describe "CommandRegistry", ->
grandchild.dispatchEvent(dispatchedEvent)
expect(dispatchedEvent.preventDefault).toHaveBeenCalled()
it "forwards .abortKeyBinding() calls from the synthetic event to the original", ->
registry.add '.child', 'command', (event) -> event.abortKeyBinding()
dispatchedEvent = new CustomEvent('command', bubbles: true)
dispatchedEvent.abortKeyBinding = jasmine.createSpy('abortKeyBinding')
grandchild.dispatchEvent(dispatchedEvent)
expect(dispatchedEvent.abortKeyBinding).toHaveBeenCalled()
it "allows listeners to be removed via a disposable returned by ::add", ->
calls = []
+695 -24
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
@@ -194,7 +200,7 @@ describe "Config", ->
expect(CSON.writeFileSync.argsForCall[0][0]).toBe(path.join(atom.config.configDirPath, "atom.config.json"))
writtenConfig = CSON.writeFileSync.argsForCall[0][1]
expect(writtenConfig).toBe atom.config.settings
expect(writtenConfig).toEqual global: atom.config.settings
describe "when ~/.atom/config.json doesn't exist", ->
it "writes any non-default properties to ~/.atom/config.cson", ->
@@ -208,9 +214,29 @@ describe "Config", ->
atom.config.save()
expect(CSON.writeFileSync.argsForCall[0][0]).toBe(path.join(atom.config.configDirPath, "atom.config.cson"))
CoffeeScript = require 'coffee-script'
writtenConfig = CSON.writeFileSync.argsForCall[0][1]
expect(writtenConfig).toEqual atom.config.settings
expect(writtenConfig).toEqual global: atom.config.settings
describe "when scoped settings are defined", ->
it 'writes out explicitly set config settings', ->
atom.config.set('.source.ruby', 'foo.bar', 'ruby')
atom.config.set('.source.ruby', 'foo.omg', 'wow')
atom.config.set('.source.coffee', 'foo.bar', 'coffee')
CSON.writeFileSync.reset()
atom.config.save()
writtenConfig = CSON.writeFileSync.argsForCall[0][1]
expect(writtenConfig).toEqualJson
global:
atom.config.settings
'.ruby.source':
foo:
bar: 'ruby'
omg: 'wow'
'.coffee.source':
foo:
bar: 'coffee'
describe ".setDefaults(keyPath, defaults)", ->
it "assigns any previously-unassigned keys to the object at the key path", ->
@@ -226,11 +252,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 +314,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
@@ -272,6 +340,14 @@ describe "Config", ->
atom.config.set('foo.bar.baz', "value 2")
expect(observeHandler).not.toHaveBeenCalled()
it 'does not fire the callback for a similarly named keyPath', ->
bazCatHandler = jasmine.createSpy("bazCatHandler")
observeSubscription = atom.config.observe "foo.bar.bazCat", bazCatHandler
bazCatHandler.reset()
atom.config.set('foo.bar.baz', "value 10")
expect(bazCatHandler).not.toHaveBeenCalled()
describe ".initializeConfigDirectory()", ->
beforeEach ->
if fs.existsSync(dotAtomPath)
@@ -308,13 +384,38 @@ describe "Config", ->
afterEach ->
fs.removeSync(dotAtomPath)
describe "when the config file contains valid cson", ->
describe "when the config file contains scoped settings", ->
beforeEach ->
fs.writeFileSync(atom.config.configFilePath, "foo: bar: 'baz'")
fs.writeFileSync atom.config.configFilePath, """
global:
foo:
bar: 'baz'
'.source.ruby':
foo:
bar: 'more-specific'
"""
atom.config.loadUserConfig()
it "updates the config data based on the file contents", ->
expect(atom.config.get("foo.bar")).toBe 'baz'
expect(atom.config.get(['.source.ruby'], "foo.bar")).toBe 'more-specific'
describe "when the config file contains valid cson", ->
beforeEach ->
fs.writeFileSync(atom.config.configFilePath, "foo: bar: 'baz'")
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 ->
@@ -334,18 +435,59 @@ 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()
fs.writeFileSync(atom.config.configFilePath, "foo: bar: 'baz'")
fs.writeFileSync atom.config.configFilePath, """
global:
foo:
bar: 'baz'
scoped: false
'.source.ruby':
foo:
scoped: true
"""
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 +501,92 @@ describe "Config", ->
expect(atom.config.get('foo.bar')).toBe 'quux'
expect(atom.config.get('foo.baz')).toBe 'bar'
it "does not fire a change event for paths that did not change", ->
atom.config.onDidChange 'foo.bar', noChangeSpy = jasmine.createSpy()
fs.writeFileSync(atom.config.configFilePath, "foo: { bar: 'baz', omg: 'ok'}")
waitsFor 'update event', -> updatedHandler.callCount > 0
runs ->
expect(noChangeSpy).not.toHaveBeenCalled()
expect(atom.config.get('foo.bar')).toBe 'baz'
expect(atom.config.get('foo.omg')).toBe 'ok'
describe 'when the default value is a complex value', ->
beforeEach ->
fs.writeFileSync(atom.config.configFilePath, "foo: { bar: ['baz', 'ok']}")
waitsFor 'update event', -> updatedHandler.callCount > 0
runs -> updatedHandler.reset()
it "does not fire a change event for paths that did not change", ->
atom.config.onDidChange 'foo.bar', noChangeSpy = jasmine.createSpy()
fs.writeFileSync(atom.config.configFilePath, "foo: { bar: ['baz', 'ok'], omg: 'another'}")
waitsFor 'update event', -> updatedHandler.callCount > 0
runs ->
expect(noChangeSpy).not.toHaveBeenCalled()
expect(atom.config.get('foo.bar')).toEqual ['baz', 'ok']
expect(atom.config.get('foo.omg')).toBe 'another'
describe 'when scoped settings are used', ->
it "fires a change event for scoped settings that are removed", ->
atom.config.onDidChange ['.source.ruby'], 'foo.scoped', scopedSpy = jasmine.createSpy()
fs.writeFileSync atom.config.configFilePath, """
global:
foo:
scoped: false
"""
waitsFor 'update event', -> updatedHandler.callCount > 0
runs ->
expect(scopedSpy).toHaveBeenCalled()
expect(atom.config.get(['.source.ruby'], 'foo.scoped')).toBe false
it "does not fire a change event for paths that did not change", ->
atom.config.onDidChange ['.source.ruby'], 'foo.scoped', noChangeSpy = jasmine.createSpy()
fs.writeFileSync atom.config.configFilePath, """
global:
foo:
bar: 'baz'
'.source.ruby':
foo:
scoped: true
"""
waitsFor 'update event', -> updatedHandler.callCount > 0
runs ->
expect(noChangeSpy).not.toHaveBeenCalled()
expect(atom.config.get(['.source.ruby'], 'foo.bar')).toBe 'baz'
expect(atom.config.get(['.source.ruby'], 'foo.scoped')).toBe true
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 +601,452 @@ 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']
describe "scoped settings", ->
describe ".get(scopeDescriptor, keyPath)", ->
it "returns the property with the most specific scope selector", ->
atom.config.addScopedSettings("config", ".source.coffee .string.quoted.double.coffee", foo: bar: baz: 42)
atom.config.addScopedSettings("config", ".source .string.quoted.double", foo: bar: baz: 22)
atom.config.addScopedSettings("config", ".source", foo: bar: baz: 11)
expect(atom.config.get([".source.coffee", ".string.quoted.double.coffee"], "foo.bar.baz")).toBe 42
expect(atom.config.get([".source.js", ".string.quoted.double.js"], "foo.bar.baz")).toBe 22
expect(atom.config.get([".source.js", ".variable.assignment.js"], "foo.bar.baz")).toBe 11
expect(atom.config.get([".text"], "foo.bar.baz")).toBeUndefined()
it "favors the most recently added properties in the event of a specificity tie", ->
atom.config.addScopedSettings("config", ".source.coffee .string.quoted.single", foo: bar: baz: 42)
atom.config.addScopedSettings("config", ".source.coffee .string.quoted.double", foo: bar: baz: 22)
expect(atom.config.get([".source.coffee", ".string.quoted.single"], "foo.bar.baz")).toBe 42
expect(atom.config.get([".source.coffee", ".string.quoted.single.double"], "foo.bar.baz")).toBe 22
describe 'when there are global defaults', ->
it 'falls back to the global when there is no scoped property specified', ->
atom.config.setDefaults("foo", hasDefault: 'ok')
expect(atom.config.get([".source.coffee", ".string.quoted.single"], "foo.hasDefault")).toBe 'ok'
describe ".set(scope, keyPath, value)", ->
it "sets the value and overrides the others", ->
atom.config.addScopedSettings("config", ".source.coffee .string.quoted.double.coffee", foo: bar: baz: 42)
atom.config.addScopedSettings("config", ".source .string.quoted.double", foo: bar: baz: 22)
atom.config.addScopedSettings("config", ".source", foo: bar: baz: 11)
expect(atom.config.get([".source.coffee", ".string.quoted.double.coffee"], "foo.bar.baz")).toBe 42
expect(atom.config.set(".source.coffee .string.quoted.double.coffee", "foo.bar.baz", 100)).toBe true
expect(atom.config.get([".source.coffee", ".string.quoted.double.coffee"], "foo.bar.baz")).toBe 100
describe ".removeScopedSettingsForName(name)", ->
it "allows properties to be removed by name", ->
disposable1 = atom.config.addScopedSettings("a", ".source.coffee .string.quoted.double.coffee", foo: bar: baz: 42)
disposable2 = atom.config.addScopedSettings("b", ".source .string.quoted.double", foo: bar: baz: 22)
disposable2.dispose()
expect(atom.config.get([".source.js", ".string.quoted.double.js"], "foo.bar.baz")).toBeUndefined()
expect(atom.config.get([".source.coffee", ".string.quoted.double.coffee"], "foo.bar.baz")).toBe 42
describe ".observe(scopeDescriptor, keyPath)", ->
it 'calls the supplied callback when the value at the descriptor/keypath changes', ->
atom.config.observe [".source.coffee", ".string.quoted.double.coffee"], "foo.bar.baz", changeSpy = jasmine.createSpy()
expect(changeSpy).toHaveBeenCalledWith(undefined)
changeSpy.reset()
atom.config.set("foo.bar.baz", 12)
expect(changeSpy).toHaveBeenCalledWith(12)
changeSpy.reset()
disposable1 = atom.config.addScopedSettings("a", ".source .string.quoted.double", foo: bar: baz: 22)
expect(changeSpy).toHaveBeenCalledWith(22)
changeSpy.reset()
disposable2 = atom.config.addScopedSettings("b", ".source.coffee .string.quoted.double.coffee", foo: bar: baz: 42)
expect(changeSpy).toHaveBeenCalledWith(42)
changeSpy.reset()
disposable2.dispose()
expect(changeSpy).toHaveBeenCalledWith(22)
changeSpy.reset()
disposable1.dispose()
expect(changeSpy).toHaveBeenCalledWith(12)
changeSpy.reset()
atom.config.set("foo.bar.baz", undefined)
expect(changeSpy).toHaveBeenCalledWith(undefined)
changeSpy.reset()
describe ".onDidChange(scopeDescriptor, keyPath)", ->
it 'calls the supplied callback when the value at the descriptor/keypath changes', ->
keyPath = "foo.bar.baz"
atom.config.onDidChange [".source.coffee", ".string.quoted.double.coffee"], keyPath, changeSpy = jasmine.createSpy()
atom.config.set("foo.bar.baz", 12)
expect(changeSpy).toHaveBeenCalledWith({oldValue: undefined, newValue: 12, keyPath})
changeSpy.reset()
disposable1 = atom.config.addScopedSettings("a", ".source .string.quoted.double", foo: bar: baz: 22)
expect(changeSpy).toHaveBeenCalledWith({oldValue: 12, newValue: 22, keyPath})
changeSpy.reset()
disposable2 = atom.config.addScopedSettings("b", ".source.coffee .string.quoted.double.coffee", foo: bar: baz: 42)
expect(changeSpy).toHaveBeenCalledWith({oldValue: 22, newValue: 42, keyPath})
changeSpy.reset()
disposable2.dispose()
expect(changeSpy).toHaveBeenCalledWith({oldValue: 42, newValue: 22, keyPath})
changeSpy.reset()
disposable1.dispose()
expect(changeSpy).toHaveBeenCalledWith({oldValue: 22, newValue: 12, keyPath})
changeSpy.reset()
atom.config.set("foo.bar.baz", undefined)
expect(changeSpy).toHaveBeenCalledWith({oldValue: 12, newValue: undefined, keyPath})
changeSpy.reset()
+148 -149
Ver Arquivo
@@ -3,173 +3,172 @@
ContextMenuManager = require '../src/context-menu-manager'
describe "ContextMenuManager", ->
[contextMenu] = []
[contextMenu, parent, child, grandchild] = []
beforeEach ->
{resourcePath} = atom.getLoadSettings()
contextMenu = new ContextMenuManager({resourcePath})
describe "adding definitions", ->
it 'loads', ->
contextMenu.add 'file-path',
'.selector':
'label': 'command'
parent = document.createElement("div")
child = document.createElement("div")
grandchild = document.createElement("div")
parent.classList.add('parent')
child.classList.add('child')
grandchild.classList.add('grandchild')
child.appendChild(grandchild)
parent.appendChild(child)
expect(contextMenu.definitions['.selector'][0].label).toEqual 'label'
expect(contextMenu.definitions['.selector'][0].command).toEqual 'command'
describe "::add(itemsBySelector)", ->
it "can add top-level menu items that can be removed with the returned disposable", ->
disposable = contextMenu.add
'.parent': [{label: 'A', command: 'a'}]
'.child': [{label: 'B', command: 'b'}]
'.grandchild': [{label: 'C', command: 'c'}]
it 'does not add duplicate menu items', ->
contextMenu.add 'file-path',
'.selector':
'label': 'command'
expect(contextMenu.templateForElement(grandchild)).toEqual [
{label: 'C', command: 'c'}
{label: 'B', command: 'b'}
{label: 'A', command: 'a'}
]
contextMenu.add 'file-path',
'.selector':
'label': 'command'
disposable.dispose()
expect(contextMenu.templateForElement(grandchild)).toEqual []
expect(contextMenu.definitions['.selector'][0].label).toEqual 'label'
expect(contextMenu.definitions['.selector'][0].command).toEqual 'command'
expect(contextMenu.definitions['.selector'].length).toBe 1
it "can add submenu items to existing menus that can be removed with the returned disposable", ->
disposable1 = contextMenu.add
'.grandchild': [{label: 'A', submenu: [{label: 'B', command: 'b'}]}]
disposable2 = contextMenu.add
'.grandchild': [{label: 'A', submenu: [{label: 'C', command: 'c'}]}]
it 'allows multiple separators', ->
contextMenu.add 'file-path',
'.selector':
'separator1': '-'
'separator2': '-'
expect(contextMenu.definitions['.selector'].length).toBe 2
expect(contextMenu.definitions['.selector'][0].type).toEqual 'separator'
expect(contextMenu.definitions['.selector'][1].type).toEqual 'separator'
it 'allows duplicate commands with different labels', ->
contextMenu.add 'file-path',
'.selector':
'label': 'command'
contextMenu.add 'file-path',
'.selector':
'another label': 'command'
expect(contextMenu.definitions['.selector'][0].label).toEqual 'label'
expect(contextMenu.definitions['.selector'][0].command).toEqual 'command'
expect(contextMenu.definitions['.selector'][1].label).toEqual 'another label'
expect(contextMenu.definitions['.selector'][1].command).toEqual 'command'
it "loads submenus", ->
contextMenu.add 'file-path',
'.selector':
'parent':
'child-1': 'child-1:trigger'
'child-2': 'child-2:trigger'
'parent-2': 'parent-2:trigger'
expect(contextMenu.definitions['.selector'].length).toBe 2
expect(contextMenu.definitions['.selector'][0].label).toEqual 'parent'
expect(contextMenu.definitions['.selector'][0].submenu.length).toBe 2
expect(contextMenu.definitions['.selector'][0].submenu[0].label).toBe 'child-1'
expect(contextMenu.definitions['.selector'][0].submenu[0].command).toBe 'child-1:trigger'
expect(contextMenu.definitions['.selector'][0].submenu[1].label).toBe 'child-2'
expect(contextMenu.definitions['.selector'][0].submenu[1].command).toBe 'child-2:trigger'
describe 'dev mode', ->
it 'loads', ->
contextMenu.add 'file-path',
'.selector':
'label': 'command'
, devMode: true
expect(contextMenu.devModeDefinitions['.selector'][0].label).toEqual 'label'
expect(contextMenu.devModeDefinitions['.selector'][0].command).toEqual 'command'
describe "building a menu template", ->
beforeEach ->
contextMenu.definitions = {
'.parent':[
label: 'parent'
command: 'command-p'
]
'.child': [
label: 'child'
command: 'command-c'
expect(contextMenu.templateForElement(grandchild)).toEqual [{
label: 'A',
submenu: [
{label: 'B', command: 'b'}
{label: 'C', command: 'c'}
]
}]
disposable2.dispose()
expect(contextMenu.templateForElement(grandchild)).toEqual [{
label: 'A',
submenu: [
{label: 'B', command: 'b'}
]
}]
disposable1.dispose()
expect(contextMenu.templateForElement(grandchild)).toEqual []
it "favors the most specific / recently added item in the case of a duplicate label", ->
grandchild.classList.add('foo')
disposable1 = contextMenu.add
'.grandchild': [{label: 'A', command: 'a'}]
disposable2 = contextMenu.add
'.grandchild.foo': [{label: 'A', command: 'b'}]
disposable3 = contextMenu.add
'.grandchild': [{label: 'A', command: 'c'}]
disposable4 = contextMenu.add
'.child': [{label: 'A', command: 'd'}]
expect(contextMenu.templateForElement(grandchild)).toEqual [{label: 'A', command: 'b'}]
disposable2.dispose()
expect(contextMenu.templateForElement(grandchild)).toEqual [{label: 'A', command: 'c'}]
disposable3.dispose()
expect(contextMenu.templateForElement(grandchild)).toEqual [{label: 'A', command: 'a'}]
disposable1.dispose()
expect(contextMenu.templateForElement(grandchild)).toEqual [{label: 'A', command: 'd'}]
it "allows multiple separators, but not adjacent to each other", ->
contextMenu.add
'.grandchild': [
{label: 'A', command: 'a'},
{type: 'separator'},
{type: 'separator'},
{label: 'B', command: 'b'},
{type: 'separator'},
{type: 'separator'},
{label: 'C', command: 'c'}
]
expect(contextMenu.templateForElement(grandchild)).toEqual [
{label: 'A', command: 'a'},
{type: 'separator'},
{label: 'B', command: 'b'},
{type: 'separator'},
{label: 'C', command: 'c'}
]
it "excludes items marked for display in devMode unless in dev mode", ->
disposable1 = contextMenu.add
'.grandchild': [{label: 'A', command: 'a', devMode: true}, {label: 'B', command: 'b', devMode: false}]
expect(contextMenu.templateForElement(grandchild)).toEqual [{label: 'B', command: 'b'}]
contextMenu.devMode = true
expect(contextMenu.templateForElement(grandchild)).toEqual [{label: 'A', command: 'a'}, {label: 'B', command: 'b'}]
it "allows items to be associated with `created` hooks which are invoked on template construction with the item and event", ->
createdEvent = null
item = {
label: 'A',
command: 'a',
created: (event) ->
@command = 'b'
createdEvent = event
}
contextMenu.devModeDefinitions =
'.parent': [
label: 'dev-label'
command: 'dev-command'
]
contextMenu.add('.grandchild': [item])
describe "on a single element", ->
[element] = []
dispatchedEvent = {target: grandchild}
expect(contextMenu.templateForEvent(dispatchedEvent)).toEqual [{label: 'A', command: 'b'}]
expect(item.command).toBe 'a' # doesn't modify original item template
expect(createdEvent).toBe dispatchedEvent
beforeEach ->
element = ($$ -> @div class: 'parent')[0]
it "allows items to be associated with `shouldDisplay` hooks which are invoked on construction to determine whether the item should be included", ->
shouldDisplayEvent = null
shouldDisplay = true
it "creates a menu with a single item", ->
menu = contextMenu.combinedMenuTemplateForElement(element)
item = {
label: 'A',
command: 'a',
shouldDisplay: (event) ->
@foo = 'bar'
shouldDisplayEvent = event
shouldDisplay
}
contextMenu.add('.grandchild': [item])
expect(menu[0].label).toEqual 'parent'
expect(menu[0].command).toEqual 'command-p'
expect(menu[1]).toBeUndefined()
dispatchedEvent = {target: grandchild}
expect(contextMenu.templateForEvent(dispatchedEvent)).toEqual [{label: 'A', command: 'a'}]
expect(item.foo).toBeUndefined() # doesn't modify original item template
expect(shouldDisplayEvent).toBe dispatchedEvent
describe "in devMode", ->
beforeEach -> contextMenu.devMode = true
shouldDisplay = false
expect(contextMenu.templateForEvent(dispatchedEvent)).toEqual []
it "creates a menu with development items", ->
menu = contextMenu.combinedMenuTemplateForElement(element)
it "allows items to be specified in the legacy format for now", ->
contextMenu.add '.parent':
'A': 'a'
'Separator 1': '-'
'B':
'C': 'c'
'Separator 2': '-'
'D': 'd'
expect(menu[0].label).toEqual 'parent'
expect(menu[0].command).toEqual 'command-p'
expect(menu[1].type).toEqual 'separator'
expect(menu[2].label).toEqual 'dev-label'
expect(menu[2].command).toEqual 'dev-command'
describe "on multiple elements", ->
[element] = []
beforeEach ->
element = $$ ->
@div class: 'parent', =>
@div class: 'child'
element = element.find('.child')[0]
it "creates a menu with a two items", ->
menu = contextMenu.combinedMenuTemplateForElement(element)
expect(menu[0].label).toEqual 'child'
expect(menu[0].command).toEqual 'command-c'
expect(menu[1].label).toEqual 'parent'
expect(menu[1].command).toEqual 'command-p'
expect(menu[2]).toBeUndefined()
describe "in devMode", ->
beforeEach -> contextMenu.devMode = true
xit "creates a menu with development items", ->
menu = contextMenu.combinedMenuTemplateForElement(element)
expect(menu[0].label).toEqual 'child'
expect(menu[0].command).toEqual 'command-c'
expect(menu[1].label).toEqual 'parent'
expect(menu[1].command).toEqual 'command-p'
expect(menu[2].label).toEqual 'dev-label'
expect(menu[2].command).toEqual 'dev-command'
expect(menu[3]).toBeUndefined()
describe "executeBuildHandlers", ->
menuTemplate = [
label: 'label'
executeAtBuild: ->
expect(contextMenu.templateForElement(parent)).toEqual [
{label: 'A', command: 'a'}
{type: 'separator'}
{
label: 'B'
submenu: [
{label: 'C', command: 'c'}
{type: 'separator'}
{label: 'D', command: 'd'}
]
}
]
event =
target: null
it 'should invoke the executeAtBuild fn', ->
buildFn = spyOn(menuTemplate[0], 'executeAtBuild')
contextMenu.executeBuildHandlers(event, menuTemplate)
expect(buildFn).toHaveBeenCalled()
expect(buildFn.mostRecentCall.args[0]).toBe event
+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()
@@ -6,7 +6,7 @@ module.exports =
activate: ->
@activateCallCount++
atom.commands.add '.workspace', 'activation-command', =>
atom.commands.add 'atom-workspace', 'activation-command', =>
@activationCommandCallCount++
atom.workspaceView.getActiveView()?.command 'activation-command', =>
@@ -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",
"activationCommands": {".workspace": []}
"activationCommands": {"atom-workspace": []}
}
+4 -3
Ver Arquivo
@@ -1,7 +1,8 @@
'menu': [
{ 'label': 'Second to Last' }
{'label': 'Second to Last'}
]
'context-menu':
'.test-1':
'Menu item 1': 'command-1'
'.test-1': [
{label: 'Menu item 1', command: 'command-1'}
]
+3 -2
Ver Arquivo
@@ -3,5 +3,6 @@
]
'context-menu':
'.test-1':
'Menu item 2': 'command-2'
'.test-1': [
{label: 'Menu item 2', command: 'command-2'}
]
+3 -2
Ver Arquivo
@@ -3,5 +3,6 @@
]
'context-menu':
'.test-1':
'Menu item 3': 'command-3'
'.test-1': [
{label: 'Menu item 3', command: 'command-3'}
]
@@ -1,6 +1,6 @@
@import "ui-variables";
.editor {
atom-text-editor {
padding-top: @component-padding;
padding-right: @component-padding;
padding-bottom: @component-padding;
+1 -1
Ver Arquivo
@@ -1,3 +1,3 @@
.editor {
atom-text-editor {
padding-top: 1234px;
}
+1 -1
Ver Arquivo
@@ -1,5 +1,5 @@
@padding: 4321px;
.editor {
atom-text-editor {
padding-top: @padding;
}
@@ -1,4 +1,4 @@
.editor {
atom-text-editor {
padding-top: 101px;
padding-right: 101px;
padding-bottom: 101px;
@@ -1,4 +1,4 @@
.editor {
atom-text-editor {
/* padding-top: 103px;
padding-right: 103px;*/
padding-bottom: 103px;
@@ -1,6 +1,6 @@
@number: 102px;
.editor {
atom-text-editor {
/* padding-top: 102px;*/
padding-right: @number;
padding-bottom: @number;
@@ -1,6 +1,6 @@
@import "ui-variables";
.editor {
atom-text-editor {
padding-top: @component-padding;
padding-right: @component-padding;
padding-bottom: @component-padding;
@@ -1,4 +1,4 @@
.editor {
atom-text-editor {
padding-top: 10px;
padding-right: 10px;
padding-bottom: 10px;
@@ -1,4 +1,4 @@
.editor {
atom-text-editor {
padding-right: 20px;
padding-bottom: 20px;
}
@@ -1,5 +1,5 @@
@number: 30px;
.editor {
atom-text-editor {
padding-bottom: @number;
}
@@ -1,4 +1,4 @@
.editor {
atom-text-editor {
padding-top: 100px;
padding-right: 100px;
padding-bottom: 100px;
1 .editor { atom-text-editor {
2 padding-top: 100px; padding-top: 100px;
3 padding-right: 100px; padding-right: 100px;
4 padding-bottom: 100px; padding-bottom: 100px;
+6 -6
Ver Arquivo
@@ -223,7 +223,7 @@ describe "GitRepository", ->
[editor] = []
beforeEach ->
atom.project.setPath(copyRepository())
atom.project.setPaths([copyRepository()])
waitsForPromise ->
atom.workspace.open('other.txt').then (o) -> editor = o
@@ -232,7 +232,7 @@ describe "GitRepository", ->
editor.insertNewline()
statusHandler = jasmine.createSpy('statusHandler')
atom.project.getRepo().onDidChangeStatus statusHandler
atom.project.getRepositories()[0].onDidChangeStatus statusHandler
editor.save()
expect(statusHandler.callCount).toBe 1
expect(statusHandler).toHaveBeenCalledWith {path: editor.getPath(), pathStatus: 256}
@@ -241,7 +241,7 @@ describe "GitRepository", ->
fs.writeFileSync(editor.getPath(), 'changed')
statusHandler = jasmine.createSpy('statusHandler')
atom.project.getRepo().onDidChangeStatus statusHandler
atom.project.getRepositories()[0].onDidChangeStatus statusHandler
editor.getBuffer().reload()
expect(statusHandler.callCount).toBe 1
expect(statusHandler).toHaveBeenCalledWith {path: editor.getPath(), pathStatus: 256}
@@ -252,7 +252,7 @@ describe "GitRepository", ->
fs.writeFileSync(editor.getPath(), 'changed')
statusHandler = jasmine.createSpy('statusHandler')
atom.project.getRepo().onDidChangeStatus statusHandler
atom.project.getRepositories()[0].onDidChangeStatus statusHandler
editor.getBuffer().emitter.emit 'did-change-path'
expect(statusHandler.callCount).toBe 1
expect(statusHandler).toHaveBeenCalledWith {path: editor.getPath(), pathStatus: 256}
@@ -266,7 +266,7 @@ describe "GitRepository", ->
project2?.destroy()
it "subscribes to all the serialized buffers in the project", ->
atom.project.setPath(copyRepository())
atom.project.setPaths([copyRepository()])
waitsForPromise ->
atom.workspace.open('file.txt')
@@ -283,7 +283,7 @@ describe "GitRepository", ->
buffer.append('changes')
statusHandler = jasmine.createSpy('statusHandler')
project2.getRepo().onDidChangeStatus statusHandler
project2.getRepositories()[0].onDidChangeStatus statusHandler
buffer.save()
expect(statusHandler.callCount).toBe 1
expect(statusHandler).toHaveBeenCalledWith {path: buffer.getPath(), pathStatus: 256}
+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"}]}
+34 -17
Ver Arquivo
@@ -3,7 +3,7 @@ Package = require '../src/package'
describe "PackageManager", ->
beforeEach ->
atom.workspaceView = new WorkspaceView
atom.workspaceView = atom.workspace.getView(atom.workspace).__spacePenView
describe "::loadPackage(name)", ->
it "continues if the package has an invalid package.json", ->
@@ -82,7 +82,21 @@ describe "PackageManager", ->
expect(indexModule.activate).toHaveBeenCalled()
expect(pack.mainModule).toBe indexModule
it "assigns config defaults from the module", ->
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 ->
@@ -124,7 +138,7 @@ describe "PackageManager", ->
legacyCommandListener = jasmine.createSpy("legacyCommandListener")
editorView.command 'activation-command', legacyCommandListener
editorCommandListener = jasmine.createSpy("editorCommandListener")
atom.commands.add '.editor', 'activation-command', editorCommandListener
atom.commands.add 'atom-text-editor', 'activation-command', editorCommandListener
editorView[0].dispatchEvent(new CustomEvent('activation-command', bubbles: true))
expect(mainModule.activate.callCount).toBe 1
expect(mainModule.legacyActivationCommandCallCount).toBe 1
@@ -216,30 +230,30 @@ describe "PackageManager", ->
it "loads all the .cson/.json files in the menus directory", ->
element = ($$ -> @div class: 'test-1')[0]
expect(atom.contextMenu.definitionsForElement(element)).toEqual []
expect(atom.contextMenu.templateForElement(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"
expect(atom.contextMenu.templateForElement(element)[0].label).toBe "Menu item 1"
expect(atom.contextMenu.templateForElement(element)[1].label).toBe "Menu item 2"
expect(atom.contextMenu.templateForElement(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 []
expect(atom.contextMenu.templateForElement(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()
expect(atom.contextMenu.templateForElement(element)[0].label).toBe "Menu item 2"
expect(atom.contextMenu.templateForElement(element)[1].label).toBe "Menu item 1"
expect(atom.contextMenu.templateForElement(element)[2]).toBeUndefined()
describe "stylesheet loading", ->
describe "when the metadata contains a 'stylesheets' manifest", ->
@@ -299,7 +313,7 @@ describe "PackageManager", ->
atom.packages.activatePackage("package-with-scoped-properties")
runs ->
expect(atom.syntax.getProperty ['.source.omg'], 'editor.increaseIndentPattern').toBe '^a'
expect(atom.config.get ['.source.omg'], 'editor.increaseIndentPattern').toBe '^a'
describe "converted textmate packages", ->
it "loads the package's grammars", ->
@@ -312,15 +326,18 @@ describe "PackageManager", ->
expect(atom.syntax.selectGrammar("file.rb").name).toBe "Ruby"
it "loads the translated scoped properties", ->
expect(atom.syntax.getProperty(['.source.ruby'], 'editor.commentStart')).toBeUndefined()
expect(atom.config.get(['.source.ruby'], 'editor.commentStart')).toBeUndefined()
waitsForPromise ->
atom.packages.activatePackage('language-ruby')
runs ->
expect(atom.syntax.getProperty(['.source.ruby'], 'editor.commentStart')).toBe '# '
expect(atom.config.get(['.source.ruby'], 'editor.commentStart')).toBe '# '
describe "::deactivatePackage(id)", ->
afterEach ->
atom.packages.unloadPackages()
describe "atom packages", ->
it "calls `deactivate` on the package's main module if activate was successful", ->
pack = null
@@ -422,9 +439,9 @@ describe "PackageManager", ->
atom.packages.activatePackage("package-with-scoped-properties")
runs ->
expect(atom.syntax.getProperty ['.source.omg'], 'editor.increaseIndentPattern').toBe '^a'
expect(atom.config.get ['.source.omg'], 'editor.increaseIndentPattern').toBe '^a'
atom.packages.deactivatePackage("package-with-scoped-properties")
expect(atom.syntax.getProperty ['.source.omg'], 'editor.increaseIndentPattern').toBeUndefined()
expect(atom.config.get ['.source.omg'], 'editor.increaseIndentPattern').toBeUndefined()
describe "textmate packages", ->
it "removes the package's grammars", ->
@@ -444,7 +461,7 @@ describe "PackageManager", ->
runs ->
atom.packages.deactivatePackage('language-ruby')
expect(atom.syntax.getProperty(['.source.ruby'], 'editor.commentStart')).toBeUndefined()
expect(atom.config.get(['.source.ruby'], 'editor.commentStart')).toBeUndefined()
describe "::activate()", ->
packageActivator = null
+17 -17
Ver Arquivo
@@ -38,51 +38,51 @@ describe "Package", ->
theme = null
beforeEach ->
$("#jasmine-content").append $("<div class='editor'></div>")
$("#jasmine-content").append $("<atom-text-editor></atom-text-editor>")
afterEach ->
theme.deactivate() if theme?
describe "when the theme contains a single style file", ->
it "loads and applies css", ->
expect($(".editor").css("padding-bottom")).not.toBe "1234px"
expect($("atom-text-editor").css("padding-bottom")).not.toBe "1234px"
themePath = atom.project.resolve('packages/theme-with-index-css')
theme = new ThemePackage(themePath)
theme.activate()
expect($(".editor").css("padding-top")).toBe "1234px"
expect($("atom-text-editor").css("padding-top")).toBe "1234px"
it "parses, loads and applies less", ->
expect($(".editor").css("padding-bottom")).not.toBe "1234px"
expect($("atom-text-editor").css("padding-bottom")).not.toBe "1234px"
themePath = atom.project.resolve('packages/theme-with-index-less')
theme = new ThemePackage(themePath)
theme.activate()
expect($(".editor").css("padding-top")).toBe "4321px"
expect($("atom-text-editor").css("padding-top")).toBe "4321px"
describe "when the theme contains a package.json file", ->
it "loads and applies stylesheets from package.json in the correct order", ->
expect($(".editor").css("padding-top")).not.toBe("101px")
expect($(".editor").css("padding-right")).not.toBe("102px")
expect($(".editor").css("padding-bottom")).not.toBe("103px")
expect($("atom-text-editor").css("padding-top")).not.toBe("101px")
expect($("atom-text-editor").css("padding-right")).not.toBe("102px")
expect($("atom-text-editor").css("padding-bottom")).not.toBe("103px")
themePath = atom.project.resolve('packages/theme-with-package-file')
theme = new ThemePackage(themePath)
theme.activate()
expect($(".editor").css("padding-top")).toBe("101px")
expect($(".editor").css("padding-right")).toBe("102px")
expect($(".editor").css("padding-bottom")).toBe("103px")
expect($("atom-text-editor").css("padding-top")).toBe("101px")
expect($("atom-text-editor").css("padding-right")).toBe("102px")
expect($("atom-text-editor").css("padding-bottom")).toBe("103px")
describe "when the theme does not contain a package.json file and is a directory", ->
it "loads all stylesheet files in the directory", ->
expect($(".editor").css("padding-top")).not.toBe "10px"
expect($(".editor").css("padding-right")).not.toBe "20px"
expect($(".editor").css("padding-bottom")).not.toBe "30px"
expect($("atom-text-editor").css("padding-top")).not.toBe "10px"
expect($("atom-text-editor").css("padding-right")).not.toBe "20px"
expect($("atom-text-editor").css("padding-bottom")).not.toBe "30px"
themePath = atom.project.resolve('packages/theme-without-package-file')
theme = new ThemePackage(themePath)
theme.activate()
expect($(".editor").css("padding-top")).toBe "10px"
expect($(".editor").css("padding-right")).toBe "20px"
expect($(".editor").css("padding-bottom")).toBe "30px"
expect($("atom-text-editor").css("padding-top")).toBe "10px"
expect($("atom-text-editor").css("padding-right")).toBe "20px"
expect($("atom-text-editor").css("padding-bottom")).toBe "30px"
describe "reloading a theme", ->
beforeEach ->
+26
Ver Arquivo
@@ -115,3 +115,29 @@ describe "PaneContainer", ->
pane3.addItems([new Object, new Object])
expect(observed).toEqual container.getPaneItems()
describe "::confirmClose()", ->
[container, pane1, pane2] = []
beforeEach ->
class TestItem
shouldPromptToSave: -> true
getUri: -> 'test'
container = new PaneContainer
container.getRoot().splitRight()
[pane1, pane2] = container.getPanes()
pane1.addItem(new TestItem)
pane2.addItem(new TestItem)
it "returns true if the user saves all modified files when prompted", ->
spyOn(atom, "confirm").andReturn(0)
saved = container.confirmClose()
expect(saved).toBeTruthy()
expect(atom.confirm).toHaveBeenCalled()
it "returns false if the user cancels saving any modified file", ->
spyOn(atom, "confirm").andReturn(1)
saved = container.confirmClose()
expect(saved).toBeFalsy()
expect(atom.confirm).toHaveBeenCalled()
+18 -40
Ver Arquivo
@@ -1,15 +1,16 @@
path = require 'path'
temp = require 'temp'
PaneContainer = require '../src/pane-container'
PaneContainerView = require '../src/pane-container-view'
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)
@@ -18,14 +19,14 @@ describe "PaneContainerView", ->
save: -> @saved = true
isEqual: (other) -> @name is other?.name
container = new PaneContainerView
container = atom.workspace.getView(atom.workspace.paneContainer).__spacePenView
pane1 = container.getRoot()
pane1.activateItem(new TestView('1'))
pane2 = pane1.splitRight(new TestView('2'))
pane3 = pane2.splitDown(new TestView('3'))
afterEach ->
atom.deserializers.remove(TestView)
deserializerDisposable.dispose()
describe ".getActivePaneView()", ->
it "returns the most-recently focused pane", ->
@@ -70,39 +71,16 @@ describe "PaneContainerView", ->
for item in pane.getItems()
expect(item.saved).toBeTruthy()
describe ".confirmClose()", ->
it "returns true after modified files are saved", ->
pane1.itemAtIndex(0).shouldPromptToSave = -> true
pane2.itemAtIndex(0).shouldPromptToSave = -> true
spyOn(atom, "confirm").andReturn(0)
saved = container.confirmClose()
runs ->
expect(saved).toBeTruthy()
expect(atom.confirm).toHaveBeenCalled()
it "returns false if the user cancels saving", ->
pane1.itemAtIndex(0).shouldPromptToSave = -> true
pane2.itemAtIndex(0).shouldPromptToSave = -> true
spyOn(atom, "confirm").andReturn(1)
saved = container.confirmClose()
runs ->
expect(saved).toBeFalsy()
expect(atom.confirm).toHaveBeenCalled()
describe "serialization", ->
it "can be serialized and deserialized, and correctly adjusts dimensions of deserialized panes after attach", ->
newContainer = new PaneContainerView(container.model.testSerialization())
expect(newContainer.find('.pane-row > :contains(1)')).toExist()
expect(newContainer.find('.pane-row > .pane-column > :contains(2)')).toExist()
expect(newContainer.find('.pane-row > .pane-column > :contains(3)')).toExist()
newContainer = atom.workspace.getView(container.model.testSerialization()).__spacePenView
expect(newContainer.find('atom-pane-axis.horizontal > :contains(1)')).toExist()
expect(newContainer.find('atom-pane-axis.horizontal > atom-pane-axis.vertical > :contains(2)')).toExist()
expect(newContainer.find('atom-pane-axis.horizontal > atom-pane-axis.vertical > :contains(3)')).toExist()
newContainer.height(200).width(300).attachToDom()
expect(newContainer.find('.pane-row > :contains(1)').width()).toBe 150
expect(newContainer.find('.pane-row > .pane-column > :contains(2)').height()).toBe 100
expect(newContainer.find('atom-pane-axis.horizontal > :contains(1)').width()).toBe 150
expect(newContainer.find('atom-pane-axis.horizontal > atom-pane-axis.vertical > :contains(2)').height()).toBe 100
describe "if there are empty panes after deserialization", ->
beforeEach ->
@@ -111,15 +89,15 @@ describe "PaneContainerView", ->
describe "if the 'core.destroyEmptyPanes' config option is false (the default)", ->
it "leaves the empty panes intact", ->
newContainer = new PaneContainerView(container.model.testSerialization())
expect(newContainer.find('.pane-row > :contains(1)')).toExist()
expect(newContainer.find('.pane-row > .pane-column > .pane').length).toBe 2
newContainer = atom.workspace.getView(container.model.testSerialization()).__spacePenView
expect(newContainer.find('atom-pane-axis.horizontal > :contains(1)')).toExist()
expect(newContainer.find('atom-pane-axis.horizontal > atom-pane-axis.vertical > atom-pane').length).toBe 2
describe "if the 'core.destroyEmptyPanes' config option is true", ->
it "removes empty panes on deserialization", ->
atom.config.set('core.destroyEmptyPanes', true)
newContainer = new PaneContainerView(container.model.testSerialization())
expect(newContainer.find('.pane-row, .pane-column')).not.toExist()
newContainer = atom.workspace.getView(container.model.testSerialization()).__spacePenView
expect(newContainer.find('atom-pane-axis.horizontal, atom-pane-axis.vertical')).not.toExist()
expect(newContainer.find('> :contains(1)')).toExist()
describe "pane-container:active-pane-item-changed", ->
@@ -131,7 +109,7 @@ describe "PaneContainerView", ->
item2b = new TestView('2b')
item3a = new TestView('3a')
container = new PaneContainerView
container = atom.workspace.getView(new PaneContainer).__spacePenView
pane1 = container.getRoot()
pane1.activateItem(item1a)
container.attachToDom()
@@ -281,7 +259,7 @@ describe "PaneContainerView", ->
# |7|8|9|
# -------
container = new PaneContainerView
container = atom.workspace.getView(new PaneContainer).__spacePenView
pane1 = container.getRoot()
pane1.activateItem(new TestView('1'))
pane4 = pane1.splitDown(new TestView('4'))
+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", ->
+13 -13
Ver Arquivo
@@ -1,4 +1,4 @@
PaneContainerView = require '../src/pane-container-view'
PaneContainer = require '../src/pane-container'
PaneView = require '../src/pane-view'
fs = require 'fs-plus'
{Emitter} = require 'event-kit'
@@ -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,8 +23,8 @@ describe "PaneView", ->
@emitter.on 'did-change-title', callback
beforeEach ->
atom.deserializers.add(TestView)
container = new PaneContainerView
deserializerDisposable = atom.deserializers.add(TestView)
container = atom.workspace.getView(new PaneContainer).__spacePenView
containerModel = container.model
view1 = new TestView(id: 'view-1', text: 'View 1')
view2 = new TestView(id: 'view-2', text: 'View 2')
@@ -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", ->
@@ -131,9 +131,9 @@ describe "PaneView", ->
describe "when the destroyed item is a model", ->
it "removes the associated view", ->
paneModel.activateItem(editor1)
expect(pane.itemViews.find('.editor').length).toBe 1
expect(pane.itemViews.find('atom-text-editor').length).toBe 1
pane.destroyItem(editor1)
expect(pane.itemViews.find('.editor').length).toBe 0
expect(pane.itemViews.find('atom-text-editor').length).toBe 0
describe "when an item is moved within the same pane", ->
it "emits a 'pane:item-moved' event with the item and the new index", ->
@@ -289,7 +289,7 @@ describe "PaneView", ->
expect(paneModel.isActive()).toBe true
describe "when a pane is split", ->
it "builds the appropriate pane-row and pane-column views", ->
it "builds the appropriateatom-pane-axis.horizontal and pane-column views", ->
pane1 = pane
pane1Model = pane.getModel()
pane.activateItem(editor1)
@@ -300,24 +300,24 @@ describe "PaneView", ->
pane2 = containerModel.getView(pane2Model).__spacePenView
pane3 = containerModel.getView(pane3Model).__spacePenView
expect(container.find('> .pane-row > .pane').toArray()).toEqual [pane1[0]]
expect(container.find('> .pane-row > .pane-column > .pane').toArray()).toEqual [pane2[0], pane3[0]]
expect(container.find('> atom-pane-axis.horizontal > atom-pane').toArray()).toEqual [pane1[0]]
expect(container.find('> atom-pane-axis.horizontal > atom-pane-axis.vertical > atom-pane').toArray()).toEqual [pane2[0], pane3[0]]
pane1Model.destroy()
expect(container.find('> .pane-column > .pane').toArray()).toEqual [pane2[0], pane3[0]]
expect(container.find('> atom-pane-axis.vertical > atom-pane').toArray()).toEqual [pane2[0], pane3[0]]
describe "serialization", ->
it "focuses the pane after attach only if had focus when serialized", ->
container.attachToDom()
pane.focus()
container2 = new PaneContainerView(container.model.testSerialization())
container2 = atom.workspace.getView(container.model.testSerialization()).__spacePenView
pane2 = container2.getRoot()
container2.attachToDom()
expect(pane2).toMatchSelector(':has(:focus)')
$(document.activeElement).blur()
container3 = new PaneContainerView(container.model.testSerialization())
container3 = atom.workspace.getView(container.model.testSerialization()).__spacePenView
pane3 = container3.getRoot()
container3.attachToDom()
expect(pane3).not.toMatchSelector(':has(:focus)')
+18 -18
Ver Arquivo
@@ -9,7 +9,7 @@ BufferedProcess = require '../src/buffered-process'
describe "Project", ->
beforeEach ->
atom.project.setPath(atom.project.resolve('dir'))
atom.project.setPaths([atom.project.resolve('dir')])
describe "serialization", ->
deserializedProject = null
@@ -41,8 +41,8 @@ describe "Project", ->
describe "when an editor is saved and the project has no path", ->
it "sets the project's path to the saved file's parent directory", ->
tempFile = temp.openSync().path
atom.project.setPath(undefined)
expect(atom.project.getPath()).toBeUndefined()
atom.project.setPaths([])
expect(atom.project.getPaths()[0]).toBeUndefined()
editor = null
waitsForPromise ->
@@ -50,7 +50,7 @@ describe "Project", ->
runs ->
editor.saveAs(tempFile)
expect(atom.project.getPath()).toBe path.dirname(tempFile)
expect(atom.project.getPaths()[0]).toBe path.dirname(tempFile)
describe ".open(path)", ->
[absolutePath, newBufferHandler] = []
@@ -164,7 +164,7 @@ describe "Project", ->
describe "when the project has no path", ->
it "returns undefined for relative URIs", ->
atom.project.setPath()
atom.project.setPaths([])
expect(atom.project.resolve('test.txt')).toBeUndefined()
expect(atom.project.resolve('http://github.com')).toBe 'http://github.com'
absolutePath = fs.absolute(__dirname)
@@ -173,33 +173,33 @@ describe "Project", ->
describe ".setPath(path)", ->
describe "when path is a file", ->
it "sets its path to the files parent directory and updates the root directory", ->
atom.project.setPath(require.resolve('./fixtures/dir/a'))
expect(atom.project.getPath()).toEqual path.dirname(require.resolve('./fixtures/dir/a'))
atom.project.setPaths([require.resolve('./fixtures/dir/a')])
expect(atom.project.getPaths()[0]).toEqual path.dirname(require.resolve('./fixtures/dir/a'))
expect(atom.project.getRootDirectory().path).toEqual path.dirname(require.resolve('./fixtures/dir/a'))
describe "when path is a directory", ->
it "sets its path to the directory and updates the root directory", ->
directory = fs.absolute(path.join(__dirname, 'fixtures', 'dir', 'a-dir'))
atom.project.setPath(directory)
expect(atom.project.getPath()).toEqual directory
atom.project.setPaths([directory])
expect(atom.project.getPaths()[0]).toEqual directory
expect(atom.project.getRootDirectory().path).toEqual directory
describe "when path is null", ->
it "sets its path and root directory to null", ->
atom.project.setPath(null)
expect(atom.project.getPath()?).toBeFalsy()
atom.project.setPaths([])
expect(atom.project.getPaths()[0]?).toBeFalsy()
expect(atom.project.getRootDirectory()?).toBeFalsy()
it "normalizes the path to remove consecutive slashes, ., and .. segments", ->
atom.project.setPath("#{require.resolve('./fixtures/dir/a')}#{path.sep}b#{path.sep}#{path.sep}..")
expect(atom.project.getPath()).toEqual path.dirname(require.resolve('./fixtures/dir/a'))
atom.project.setPaths(["#{require.resolve('./fixtures/dir/a')}#{path.sep}b#{path.sep}#{path.sep}.."])
expect(atom.project.getPaths()[0]).toEqual path.dirname(require.resolve('./fixtures/dir/a'))
expect(atom.project.getRootDirectory().path).toEqual path.dirname(require.resolve('./fixtures/dir/a'))
describe ".replace()", ->
[filePath, commentFilePath, sampleContent, sampleCommentContent] = []
beforeEach ->
atom.project.setPath(atom.project.resolve('../'))
atom.project.setPaths([atom.project.resolve('../')])
filePath = atom.project.resolve('sample.js')
commentFilePath = atom.project.resolve('sample-with-comments.js')
@@ -332,7 +332,7 @@ describe "Project", ->
it "works on evil filenames", ->
platform.generateEvilFiles()
atom.project.setPath(path.join(__dirname, 'fixtures', 'evil-files'))
atom.project.setPaths([path.join(__dirname, 'fixtures', 'evil-files')])
paths = []
matches = []
waitsForPromise ->
@@ -387,7 +387,7 @@ describe "Project", ->
fs.removeSync(projectPath) if fs.existsSync(projectPath)
it "excludes ignored files", ->
atom.project.setPath(projectPath)
atom.project.setPaths([projectPath])
atom.config.set('core.excludeVcsIgnoredPaths', true)
resultHandler = jasmine.createSpy("result found")
waitsForPromise ->
@@ -399,7 +399,7 @@ describe "Project", ->
it "includes only files when a directory filter is specified", ->
projectPath = path.join(path.join(__dirname, 'fixtures', 'dir'))
atom.project.setPath(projectPath)
atom.project.setPaths([projectPath])
filePath = path.join(projectPath, 'a-dir', 'oh-git')
@@ -419,7 +419,7 @@ describe "Project", ->
projectPath = temp.mkdirSync()
filePath = path.join(projectPath, '.text')
fs.writeFileSync(filePath, 'match this')
atom.project.setPath(projectPath)
atom.project.setPaths([projectPath])
paths = []
matches = []
waitsForPromise ->
+17 -10
Ver Arquivo
@@ -2,6 +2,7 @@ require '../src/window'
atom.initialize()
atom.restoreWindowDimensions()
require 'jasmine-json'
require '../vendor/jasmine-jquery'
path = require 'path'
_ = require 'underscore-plus'
@@ -29,12 +30,18 @@ atom.keymaps.loadBundledKeymaps()
keyBindingsToRestore = atom.keymaps.getKeyBindings()
commandsToRestore = atom.commands.getSnapshot()
$(window).on 'core:close', -> window.close()
$(window).on 'beforeunload', ->
window.addEventListener 'core:close', -> window.close()
window.addEventListener 'beforeunload', ->
atom.storeWindowDimensions()
atom.saveSync()
$('html,body').css('overflow', 'auto')
# Allow document.title to be assigned in specs without screwing up spec window title
documentTitle = null
Object.defineProperty document, 'title',
get: -> documentTitle
set: (title) -> documentTitle = title
jasmine.getEnv().addEqualityTester(_.isEqual) # Use underscore's definition of equality for toEqual assertions
if process.platform is 'win32' and process.env.JANKY_SHA1
@@ -61,11 +68,11 @@ isCoreSpec = specDirectory == fs.realpathSync(__dirname)
beforeEach ->
Grim.clearDeprecations() if isCoreSpec
$.fx.off = true
documentTitle = null
projectPath = specProjectPath ? path.join(@specDirectory, 'fixtures')
atom.project = new Project(path: projectPath)
atom.project = new Project(paths: [projectPath])
atom.workspace = new Workspace()
atom.keymaps.keyBindings = _.clone(keyBindingsToRestore)
atom.commands.setRootNode(document.body)
atom.commands.restoreSnapshot(commandsToRestore)
window.resetTimeouts()
@@ -75,7 +82,6 @@ beforeEach ->
spyOn(atom, 'saveSync')
atom.syntax.clearGrammarOverrides()
atom.syntax.clearProperties()
spy = spyOn(atom.packages, 'resolvePackagePath').andCallFake (packageName) ->
if specPackageName and packageName is specPackageName
@@ -91,22 +97,22 @@ beforeEach ->
config = new Config({resourcePath, configDirPath: atom.getConfigDirPath()})
spyOn(config, 'load')
spyOn(config, 'save')
config.setDefaults('core', WorkspaceView.configDefaults)
config.setDefaults('editor', TextEditorView.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(TextEditorView.prototype, 'requestDisplayUpdate').andCallFake -> @updateDisplay()
TextEditorComponent.performSyncUpdates = true
spyOn(WorkspaceView.prototype, 'setTitle').andCallFake (@title) ->
spyOn(atom, "setRepresentedFilename")
spyOn(window, "setTimeout").andCallFake window.fakeSetTimeout
spyOn(window, "clearTimeout").andCallFake window.fakeClearTimeout
spyOn(pathwatcher.File.prototype, "detectResurrectionAfterDelay").andCallFake -> @detectResurrection()
@@ -125,6 +131,7 @@ beforeEach ->
afterEach ->
atom.packages.deactivatePackages()
atom.menu.template = []
atom.contextMenu.clear()
atom.workspaceView?.remove?()
atom.workspaceView = null
@@ -350,7 +357,7 @@ $.fn.enableKeymap = ->
not e.originalEvent.defaultPrevented
$.fn.attachToDom = ->
@appendTo($('#jasmine-content'))
@appendTo($('#jasmine-content')) unless @isOnDom()
$.fn.simulateDomAttachment = ->
$('<html>').append(this)
+147 -10
Ver Arquivo
@@ -277,7 +277,7 @@ describe "TextEditorComponent", ->
expect(leafNodes[0].classList.contains('invisible-character')).toBe true
expect(leafNodes[leafNodes.length - 1].classList.contains('invisible-character')).toBe true
it "displays newlines as their own token outside of the other tokens' scopes", ->
it "displays newlines as their own token outside of the other tokens' scopeDescriptor", ->
editor.setText "var\n"
nextAnimationFrame()
expect(component.lineNodeForScreenRow(0).innerHTML).toBe "<span class=\"source js\"><span class=\"storage modifier js\">var</span></span><span class=\"invisible-character\">#{invisibles.eol}</span>"
@@ -446,12 +446,6 @@ describe "TextEditorComponent", ->
foldedLineNode = component.lineNodeForScreenRow(4)
expect(foldedLineNode.querySelector('.fold-marker')).toBeFalsy()
getLeafNodes = (node) ->
if node.children.length > 0
flatten(toArray(node.children).map(getLeafNodes))
else
[node]
describe "gutter rendering", ->
[gutter] = []
@@ -1734,11 +1728,11 @@ describe "TextEditorComponent", ->
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", ->
@@ -2214,7 +2208,6 @@ describe "TextEditorComponent", ->
it "does not render invisible characters", ->
atom.config.set('editor.invisibles', eol: 'E')
atom.config.set('editor.showInvisibles', true)
nextAnimationFrame()
expect(component.lineNodeForScreenRow(0).textContent).toBe 'var quicksort = function () {'
it "does not assign an explicit line-height on the editor contents", ->
@@ -2264,6 +2257,144 @@ describe "TextEditorComponent", ->
wrapperView.detach()
wrapperView.attachToDom()
wrapperView.trigger('core:move-right')
expect(editor.getCursorBufferPosition()).toEqual [0, 1]
describe 'scoped config settings', ->
[coffeeEditor, coffeeComponent] = []
beforeEach ->
waitsForPromise ->
atom.packages.activatePackage('language-coffee-script')
waitsForPromise ->
atom.project.open('coffee.coffee', autoIndent: false).then (o) -> coffeeEditor = o
afterEach: ->
atom.packages.deactivatePackages()
atom.packages.unloadPackages()
describe 'soft wrap settings', ->
beforeEach ->
atom.config.set '.source.coffee', 'editor.softWrap', true
atom.config.set '.source.coffee', 'editor.preferredLineLength', 17
atom.config.set '.source.coffee', 'editor.softWrapAtPreferredLineLength', true
editor.setEditorWidthInChars(20)
coffeeEditor.setEditorWidthInChars(20)
it "wraps lines when editor.softWrap is true for a matching scope", ->
expect(editor.lineTextForScreenRow(2)).toEqual ' if (items.length <= 1) return items;'
expect(coffeeEditor.lineTextForScreenRow(3)).toEqual ' return items '
it 'updates the wrapped lines when editor.preferredLineLength changes', ->
atom.config.set '.source.coffee', 'editor.preferredLineLength', 20
expect(coffeeEditor.lineTextForScreenRow(2)).toEqual ' return items if '
it 'updates the wrapped lines when editor.softWrapAtPreferredLineLength changes', ->
atom.config.set '.source.coffee', 'editor.softWrapAtPreferredLineLength', false
expect(coffeeEditor.lineTextForScreenRow(2)).toEqual ' return items if '
it 'updates the wrapped lines when editor.softWrap changes', ->
atom.config.set '.source.coffee', 'editor.softWrap', false
expect(coffeeEditor.lineTextForScreenRow(2)).toEqual ' return items if items.length <= 1'
atom.config.set '.source.coffee', 'editor.softWrap', true
expect(coffeeEditor.lineTextForScreenRow(3)).toEqual ' return items '
it 'updates the wrapped lines when the grammar changes', ->
editor.setGrammar(coffeeEditor.getGrammar())
expect(editor.isSoftWrapped()).toBe true
expect(editor.lineTextForScreenRow(0)).toEqual 'var quicksort = '
describe '::isSoftWrapped()', ->
it 'returns the correct value based on the scoped settings', ->
expect(editor.isSoftWrapped()).toBe false
expect(coffeeEditor.isSoftWrapped()).toBe true
describe 'invisibles settings', ->
[jsInvisibles, coffeeInvisibles] = []
beforeEach ->
jsInvisibles =
eol: 'J'
space: 'A'
tab: 'V'
cr: 'A'
coffeeInvisibles =
eol: 'C'
space: 'O'
tab: 'F'
cr: 'E'
atom.config.set '.source.js', 'editor.showInvisibles', true
atom.config.set '.source.js', 'editor.invisibles', jsInvisibles
atom.config.set '.source.coffee', 'editor.showInvisibles', false
atom.config.set '.source.coffee', 'editor.invisibles', coffeeInvisibles
editor.setText " a line with tabs\tand spaces \n"
nextAnimationFrame()
it "renders the invisibles when editor.showInvisibles is true for a given grammar", ->
expect(component.lineNodeForScreenRow(0).textContent).toBe "#{jsInvisibles.space}a line with tabs#{jsInvisibles.tab}and spaces#{jsInvisibles.space}#{jsInvisibles.eol}"
it "does not render the invisibles when editor.showInvisibles is false for a given grammar", ->
editor.setGrammar(coffeeEditor.getGrammar())
nextAnimationFrame()
expect(component.lineNodeForScreenRow(0).textContent).toBe " a line with tabs and spaces "
it "re-renders the invisibles when the invisible settings change", ->
jsGrammar = editor.getGrammar()
editor.setGrammar(coffeeEditor.getGrammar())
atom.config.set '.source.coffee', 'editor.showInvisibles', true
nextAnimationFrame()
expect(component.lineNodeForScreenRow(0).textContent).toBe "#{coffeeInvisibles.space}a line with tabs#{coffeeInvisibles.tab}and spaces#{coffeeInvisibles.space}#{coffeeInvisibles.eol}"
newInvisibles =
eol: 'N'
space: 'E'
tab: 'W'
cr: 'I'
atom.config.set '.source.coffee', 'editor.invisibles', newInvisibles
nextAnimationFrame()
expect(component.lineNodeForScreenRow(0).textContent).toBe "#{newInvisibles.space}a line with tabs#{newInvisibles.tab}and spaces#{newInvisibles.space}#{newInvisibles.eol}"
editor.setGrammar(jsGrammar)
nextAnimationFrame()
expect(component.lineNodeForScreenRow(0).textContent).toBe "#{jsInvisibles.space}a line with tabs#{jsInvisibles.tab}and spaces#{jsInvisibles.space}#{jsInvisibles.eol}"
describe 'editor.showIndentGuide', ->
beforeEach ->
atom.config.set '.source.js', 'editor.showIndentGuide', true
atom.config.set '.source.coffee', 'editor.showIndentGuide', false
it "has an 'indent-guide' class when scoped editor.showIndentGuide is true, but not when scoped editor.showIndentGuide is false", ->
line1LeafNodes = getLeafNodes(component.lineNodeForScreenRow(1))
expect(line1LeafNodes[0].textContent).toBe ' '
expect(line1LeafNodes[0].classList.contains('indent-guide')).toBe true
expect(line1LeafNodes[1].classList.contains('indent-guide')).toBe false
editor.setGrammar(coffeeEditor.getGrammar())
line1LeafNodes = getLeafNodes(component.lineNodeForScreenRow(1))
expect(line1LeafNodes[0].textContent).toBe ' '
expect(line1LeafNodes[0].classList.contains('indent-guide')).toBe false
expect(line1LeafNodes[1].classList.contains('indent-guide')).toBe false
it "removes the 'indent-guide' class when editor.showIndentGuide to false", ->
line1LeafNodes = getLeafNodes(component.lineNodeForScreenRow(1))
expect(line1LeafNodes[0].textContent).toBe ' '
expect(line1LeafNodes[0].classList.contains('indent-guide')).toBe true
expect(line1LeafNodes[1].classList.contains('indent-guide')).toBe false
atom.config.set '.source.js', 'editor.showIndentGuide', false
line1LeafNodes = getLeafNodes(component.lineNodeForScreenRow(1))
expect(line1LeafNodes[0].textContent).toBe ' '
expect(line1LeafNodes[0].classList.contains('indent-guide')).toBe false
expect(line1LeafNodes[1].classList.contains('indent-guide')).toBe false
buildMouseEvent = (type, properties...) ->
properties = extend({bubbles: true, cancelable: true}, properties...)
properties.detail ?= 1
@@ -2300,3 +2431,9 @@ describe "TextEditorComponent", ->
lineHasClass = (screenRow, klass) ->
component.lineNodeForScreenRow(screenRow).classList.contains(klass)
getLeafNodes = (node) ->
if node.children.length > 0
flatten(toArray(node.children).map(getLeafNodes))
else
[node]
+36
Ver Arquivo
@@ -0,0 +1,36 @@
TextEditorElement = require '../src/text-editor-element'
# The rest of text-editor-component-spec will be moved to this file when React
# is eliminated. This covers only concerns related to the wrapper element for now
describe "TextEditorElement", ->
jasmineContent = null
beforeEach ->
jasmineContent = document.body.querySelector('#jasmine-content')
describe "instantiation", ->
it "honors the mini attribute", ->
jasmineContent.innerHTML = "<atom-text-editor mini>"
element = jasmineContent.firstChild
expect(element.getModel().isMini()).toBe true
it "honors the placeholder-text attribute", ->
jasmineContent.innerHTML = "<atom-text-editor placeholder-text='testing'>"
element = jasmineContent.firstChild
expect(element.getModel().getPlaceholderText()).toBe 'testing'
describe "::focus()", ->
it "transfers focus to the hidden text area and does not emit 'focusout' or 'blur' events", ->
element = new TextEditorElement
jasmineContent.appendChild(element)
focusoutCalled = false
element.addEventListener 'focusout', -> focusoutCalled = true
blurCalled = false
element.addEventListener 'blur', -> blurCalled = true
element.focus()
expect(focusoutCalled).toBe false
expect(blurCalled).toBe false
expect(element.hasFocus()).toBe true
expect(element.querySelector('input')).toBe document.activeElement
+149 -20
Ver Arquivo
@@ -113,7 +113,7 @@ describe "TextEditor", ->
expect(editor1.isSoftWrapped()).toBe true
expect(editor1.getSoftTabs()).toBe false
atom.config.set('editor.tabLength', 100)
atom.config.set('editor.tabLength', 8)
atom.config.set('editor.softWrap', false)
atom.config.set('editor.softTabs', true)
@@ -121,7 +121,7 @@ describe "TextEditor", ->
atom.workspace.open('b').then (o) -> editor2 = o
runs ->
expect(editor2.getTabLength()).toBe 100
expect(editor2.getTabLength()).toBe 8
expect(editor2.isSoftWrapped()).toBe false
expect(editor2.getSoftTabs()).toBe true
@@ -1259,7 +1259,6 @@ describe "TextEditor", ->
editor.selectWordsContainingCursors()
expect(editor.getSelectedText()).toBe 'var'
describe "when the cursor is inside a region of whitespace", ->
it "selects the whitespace region", ->
editor.setCursorScreenPosition([5, 2])
@@ -1277,6 +1276,29 @@ describe "TextEditor", ->
editor.selectWordsContainingCursors()
expect(editor.getSelectedBufferRange()).toEqual [[12, 2], [12, 6]]
describe 'when editor.nonWordCharacters is set scoped to a grammar', ->
coffeeEditor = null
beforeEach ->
waitsForPromise ->
atom.packages.activatePackage('language-coffee-script')
waitsForPromise ->
atom.project.open('coffee.coffee', autoIndent: false).then (o) -> coffeeEditor = o
it 'selects the correct surrounding word for the given scoped setting', ->
coffeeEditor.setCursorBufferPosition [0, 9] # in the middle of quicksort
coffeeEditor.selectWordsContainingCursors()
expect(coffeeEditor.getSelectedBufferRange()).toEqual [[0, 6], [0, 15]]
atom.config.set '.source.coffee', 'editor.nonWordCharacters', 'qusort'
coffeeEditor.setCursorBufferPosition [0, 9]
coffeeEditor.selectWordsContainingCursors()
expect(coffeeEditor.getSelectedBufferRange()).toEqual [[0, 8], [0, 11]]
editor.setCursorBufferPosition [0, 7]
editor.selectWordsContainingCursors()
expect(editor.getSelectedBufferRange()).toEqual [[0, 4], [0, 13]]
describe ".selectToFirstCharacterOfLine()", ->
it "moves to the first character of the current line or the beginning of the line if it's already on the first character", ->
editor.setCursorScreenPosition [0,5]
@@ -3038,6 +3060,51 @@ describe "TextEditor", ->
atom.workspace.open(null, softTabs: false).then (editor) ->
expect(editor.getSoftTabs()).toBeFalsy()
describe '.getTabLength()', ->
describe 'when scoped settings are used', ->
coffeeEditor = null
beforeEach ->
waitsForPromise ->
atom.packages.activatePackage('language-coffee-script')
waitsForPromise ->
atom.project.open('coffee.coffee', autoIndent: false).then (o) -> coffeeEditor = o
afterEach: ->
atom.packages.deactivatePackages()
atom.packages.unloadPackages()
it 'returns correct values based on the scope of the set grammars', ->
atom.config.set '.source.coffee', 'editor.tabLength', 6
expect(editor.getTabLength()).toBe 2
expect(coffeeEditor.getTabLength()).toBe 6
it 'retokenizes when the tab length is updated via .setTabLength()', ->
expect(editor.getTabLength()).toBe 2
expect(editor.tokenizedLineForScreenRow(5).tokens[0].firstNonWhitespaceIndex).toBe 2
editor.setTabLength(6)
expect(editor.getTabLength()).toBe 6
expect(editor.tokenizedLineForScreenRow(5).tokens[0].firstNonWhitespaceIndex).toBe 6
it 'retokenizes when the editor.tabLength setting is updated', ->
expect(editor.getTabLength()).toBe 2
expect(editor.tokenizedLineForScreenRow(5).tokens[0].firstNonWhitespaceIndex).toBe 2
atom.config.set '.source.js', 'editor.tabLength', 6
expect(editor.getTabLength()).toBe 6
expect(editor.tokenizedLineForScreenRow(5).tokens[0].firstNonWhitespaceIndex).toBe 6
it 'updates the tab length when the grammar changes', ->
atom.config.set '.source.coffee', 'editor.tabLength', 6
expect(editor.getTabLength()).toBe 2
expect(editor.tokenizedLineForScreenRow(5).tokens[0].firstNonWhitespaceIndex).toBe 2
editor.setGrammar(coffeeEditor.getGrammar())
expect(editor.getTabLength()).toBe 6
expect(editor.tokenizedLineForScreenRow(5).tokens[0].firstNonWhitespaceIndex).toBe 6
describe ".indentLevelForLine(line)", ->
it "returns the indent level when the line has only leading whitespace", ->
expect(editor.indentLevelForLine(" hello")).toBe(2)
@@ -3077,14 +3144,15 @@ describe "TextEditor", ->
expect(editor.tokenizedLineForScreenRow(0).tokens.length).toBeGreaterThan 1
describe "auto-indent", ->
copyText = (text, {startColumn}={}) ->
copyText = (text, {startColumn, textEditor}={}) ->
startColumn ?= 0
editor.setCursorBufferPosition([0, 0])
editor.insertText(text)
textEditor ?= editor
textEditor.setCursorBufferPosition([0, 0])
textEditor.insertText(text)
numberOfNewlines = text.match(/\n/g)?.length
endColumn = text.match(/[^\n]*$/)[0]?.length
editor.getLastSelection().setBufferRange([[0,startColumn], [numberOfNewlines,endColumn]])
editor.cutSelectedText()
textEditor.getLastSelection().setBufferRange([[0,startColumn], [numberOfNewlines,endColumn]])
textEditor.cutSelectedText()
describe "editor.autoIndent", ->
describe "when editor.autoIndent is false (default)", ->
@@ -3191,6 +3259,31 @@ describe "TextEditor", ->
editor.insertText('foo')
expect(editor.indentationForBufferRow(2)).toBe editor.indentationForBufferRow(1) + 1
describe 'when scoped settings are used', ->
coffeeEditor = null
beforeEach ->
waitsForPromise ->
atom.packages.activatePackage('language-coffee-script')
waitsForPromise ->
atom.project.open('coffee.coffee', autoIndent: false).then (o) -> coffeeEditor = o
runs ->
atom.config.set('.source.js', 'editor.autoIndent', true)
atom.config.set('.source.coffee', 'editor.autoIndent', false)
afterEach: ->
atom.packages.deactivatePackages()
atom.packages.unloadPackages()
it "does not auto-indent the line for javascript files", ->
editor.setCursorBufferPosition([1, 30])
editor.insertText("\n")
expect(editor.lineTextForBufferRow(2)).toBe " "
coffeeEditor.setCursorBufferPosition([1, 18])
coffeeEditor.insertText("\n")
expect(coffeeEditor.lineTextForBufferRow(2)).toBe ""
describe "editor.normalizeIndentOnPaste", ->
beforeEach ->
atom.config.set('editor.normalizeIndentOnPaste', true)
@@ -3240,6 +3333,37 @@ describe "TextEditor", ->
expect(editor.lineTextForBufferRow(3)).toBe " }"
expect(editor.lineTextForBufferRow(4)).toBe ""
describe 'when scoped settings are used', ->
coffeeEditor = null
beforeEach ->
waitsForPromise ->
atom.packages.activatePackage('language-coffee-script')
waitsForPromise ->
atom.project.open('coffee.coffee', autoIndent: false).then (o) -> coffeeEditor = o
runs ->
atom.config.set('.source.js', 'editor.normalizeIndentOnPaste', true)
atom.config.set('.source.coffee', 'editor.normalizeIndentOnPaste', false)
afterEach: ->
atom.packages.deactivatePackages()
atom.packages.unloadPackages()
it "normalizes the indentation level based on scoped settings", ->
copyText(" while (true) {\n foo();\n }\n", {startColumn: 2, textEditor: coffeeEditor})
coffeeEditor.setCursorBufferPosition([4, 4])
coffeeEditor.pasteText()
expect(coffeeEditor.lineTextForBufferRow(4)).toBe " while (true) {"
expect(coffeeEditor.lineTextForBufferRow(5)).toBe " foo();"
expect(coffeeEditor.lineTextForBufferRow(6)).toBe " }"
copyText(" while (true) {\n foo();\n }\n", {startColumn: 2})
editor.setCursorBufferPosition([3, 4])
editor.pasteText()
expect(editor.lineTextForBufferRow(3)).toBe " while (true) {"
expect(editor.lineTextForBufferRow(4)).toBe " foo();"
expect(editor.lineTextForBufferRow(5)).toBe " }"
it "autoIndentSelectedRows auto-indents the selection", ->
editor.setCursorBufferPosition([2, 0])
editor.insertText("function() {\ninside=true\n}\n i=1\n")
@@ -3252,10 +3376,18 @@ describe "TextEditor", ->
expect(editor.lineTextForBufferRow(5)).toBe " i=1"
describe "soft and hard tabs", ->
afterEach ->
atom.packages.deactivatePackages()
atom.packages.unloadPackages()
it "resets the tab style when tokenization is complete", ->
editor.destroy()
atom.project.open('sample-with-tabs-and-leading-comment.coffee').then (o) -> editor = o
expect(editor.softTabs).toBe true
waitsForPromise ->
atom.project.open('sample-with-tabs-and-leading-comment.coffee').then (o) -> editor = o
runs ->
expect(editor.softTabs).toBe true
waitsForPromise ->
atom.packages.activatePackage('language-coffee-script')
@@ -3263,9 +3395,6 @@ describe "TextEditor", ->
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
@@ -3521,10 +3650,10 @@ describe "TextEditor", ->
{tokens} = grammar.tokenizeLine("var i; // http://github.com")
expect(tokens[0].value).toBe "var"
expect(tokens[0].scopes).toEqual ["source.js", "storage.modifier.js"]
expect(tokens[0].scopeDescriptor).toEqual ["source.js", "storage.modifier.js"]
expect(tokens[6].value).toBe "http://github.com"
expect(tokens[6].scopes).toEqual ["source.js", "comment.line.double-slash.js", "markup.underline.link.http.hyperlink"]
expect(tokens[6].scopeDescriptor).toEqual ["source.js", "comment.line.double-slash.js", "markup.underline.link.http.hyperlink"]
describe "when the grammar is added", ->
it "retokenizes existing buffers that contain tokens that match the injection selector", ->
@@ -3536,7 +3665,7 @@ describe "TextEditor", ->
{tokens} = editor.tokenizedLineForScreenRow(0)
expect(tokens[1].value).toBe " http://github.com"
expect(tokens[1].scopes).toEqual ["source.js", "comment.line.double-slash.js"]
expect(tokens[1].scopeDescriptor).toEqual ["source.js", "comment.line.double-slash.js"]
waitsForPromise ->
atom.packages.activatePackage('language-hyperlink')
@@ -3544,7 +3673,7 @@ describe "TextEditor", ->
runs ->
{tokens} = editor.tokenizedLineForScreenRow(0)
expect(tokens[2].value).toBe "http://github.com"
expect(tokens[2].scopes).toEqual ["source.js", "comment.line.double-slash.js", "markup.underline.link.http.hyperlink"]
expect(tokens[2].scopeDescriptor).toEqual ["source.js", "comment.line.double-slash.js", "markup.underline.link.http.hyperlink"]
describe "when the grammar is updated", ->
it "retokenizes existing buffers that contain tokens that match the injection selector", ->
@@ -3556,7 +3685,7 @@ describe "TextEditor", ->
{tokens} = editor.tokenizedLineForScreenRow(0)
expect(tokens[1].value).toBe " SELECT * FROM OCTOCATS"
expect(tokens[1].scopes).toEqual ["source.js", "comment.line.double-slash.js"]
expect(tokens[1].scopeDescriptor).toEqual ["source.js", "comment.line.double-slash.js"]
waitsForPromise ->
atom.packages.activatePackage('package-with-injection-selector')
@@ -3564,7 +3693,7 @@ describe "TextEditor", ->
runs ->
{tokens} = editor.tokenizedLineForScreenRow(0)
expect(tokens[1].value).toBe " SELECT * FROM OCTOCATS"
expect(tokens[1].scopes).toEqual ["source.js", "comment.line.double-slash.js"]
expect(tokens[1].scopeDescriptor).toEqual ["source.js", "comment.line.double-slash.js"]
waitsForPromise ->
atom.packages.activatePackage('language-sql')
@@ -3572,7 +3701,7 @@ describe "TextEditor", ->
runs ->
{tokens} = editor.tokenizedLineForScreenRow(0)
expect(tokens[2].value).toBe "SELECT"
expect(tokens[2].scopes).toEqual ["source.js", "comment.line.double-slash.js", "keyword.other.DML.sql"]
expect(tokens[2].scopeDescriptor).toEqual ["source.js", "comment.line.double-slash.js", "keyword.other.DML.sql"]
describe ".normalizeTabsInBufferRange()", ->
it "normalizes tabs depending on the editor's soft tab/tab length settings", ->
+10 -11
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")
@@ -210,7 +209,7 @@ describe "ThemeManager", ->
describe "base stylesheet loading", ->
beforeEach ->
atom.workspaceView = atom.workspace.getView(atom.workspace).__spacePenView
atom.workspaceView.append $$ -> @div class: 'editor'
atom.workspaceView.append $('<atom-text-editor>')
atom.workspaceView.attachToDom()
waitsForPromise ->
@@ -228,9 +227,9 @@ describe "ThemeManager", ->
expect(atom.workspaceView.css("background-color")).toBe "rgb(0, 0, 255)"
# from within the theme itself
expect($(".editor").css("padding-top")).toBe "150px"
expect($(".editor").css("padding-right")).toBe "150px"
expect($(".editor").css("padding-bottom")).toBe "150px"
expect($("atom-text-editor").css("padding-top")).toBe "150px"
expect($("atom-text-editor").css("padding-right")).toBe "150px"
expect($("atom-text-editor").css("padding-bottom")).toBe "150px"
describe "when there is a theme with incomplete variables", ->
it "loads the correct values from the fallback ui-variables", ->
@@ -245,7 +244,7 @@ describe "ThemeManager", ->
expect(atom.workspaceView.css("background-color")).toBe "rgb(0, 0, 255)"
# from within the theme itself
expect($(".editor").css("background-color")).toBe "rgb(0, 152, 255)"
expect($("atom-text-editor").css("background-color")).toBe "rgb(0, 152, 255)"
describe "theme classes on the workspace", ->
it 'adds theme-* classes to the workspace for each active theme', ->
+43 -43
Ver Arquivo
@@ -51,12 +51,12 @@ describe "TokenizedBuffer", ->
it "initially creates un-tokenized screen lines, then tokenizes lines chunk at a time in the background", ->
line0 = tokenizedBuffer.tokenizedLineForRow(0)
expect(line0.tokens.length).toBe 1
expect(line0.tokens[0]).toEqual(value: line0.text, scopes: ['source.js'])
expect(line0.tokens[0]).toEqual(value: line0.text, scopeDescriptor: ['source.js'])
line11 = tokenizedBuffer.tokenizedLineForRow(11)
expect(line11.tokens.length).toBe 2
expect(line11.tokens[0]).toEqual(value: " ", scopes: ['source.js'], isAtomic: true)
expect(line11.tokens[1]).toEqual(value: "return sort(Array.apply(this, arguments));", scopes: ['source.js'])
expect(line11.tokens[0]).toEqual(value: " ", scopeDescriptor: ['source.js'], isAtomic: true)
expect(line11.tokens[1]).toEqual(value: "return sort(Array.apply(this, arguments));", scopeDescriptor: ['source.js'])
# background tokenization has not begun
expect(tokenizedBuffer.tokenizedLineForRow(0).ruleStack).toBeUndefined()
@@ -149,10 +149,10 @@ describe "TokenizedBuffer", ->
it "updates tokens to reflect the change", ->
buffer.setTextInRange([[0, 0], [2, 0]], "foo()\n7\n")
expect(tokenizedBuffer.tokenizedLineForRow(0).tokens[1]).toEqual(value: '(', scopes: ['source.js', 'meta.brace.round.js'])
expect(tokenizedBuffer.tokenizedLineForRow(1).tokens[0]).toEqual(value: '7', scopes: ['source.js', 'constant.numeric.js'])
expect(tokenizedBuffer.tokenizedLineForRow(0).tokens[1]).toEqual(value: '(', scopeDescriptor: ['source.js', 'meta.brace.round.js'])
expect(tokenizedBuffer.tokenizedLineForRow(1).tokens[0]).toEqual(value: '7', scopeDescriptor: ['source.js', 'constant.numeric.js'])
# line 2 is unchanged
expect(tokenizedBuffer.tokenizedLineForRow(2).tokens[2]).toEqual(value: 'if', scopes: ['source.js', 'keyword.control.js'])
expect(tokenizedBuffer.tokenizedLineForRow(2).tokens[2]).toEqual(value: 'if', scopeDescriptor: ['source.js', 'keyword.control.js'])
expect(changeHandler).toHaveBeenCalled()
[event] = changeHandler.argsForCall[0]
@@ -164,7 +164,7 @@ describe "TokenizedBuffer", ->
buffer.insert([5, 30], '/* */')
changeHandler.reset()
buffer.insert([2, 0], '/*')
expect(tokenizedBuffer.tokenizedLineForRow(3).tokens[0].scopes).toEqual ['source.js']
expect(tokenizedBuffer.tokenizedLineForRow(3).tokens[0].scopeDescriptor).toEqual ['source.js']
expect(changeHandler).toHaveBeenCalled()
[event] = changeHandler.argsForCall[0]
delete event.bufferChange
@@ -172,9 +172,9 @@ describe "TokenizedBuffer", ->
changeHandler.reset()
advanceClock()
expect(tokenizedBuffer.tokenizedLineForRow(3).tokens[0].scopes).toEqual ['source.js', 'comment.block.js']
expect(tokenizedBuffer.tokenizedLineForRow(4).tokens[0].scopes).toEqual ['source.js', 'comment.block.js']
expect(tokenizedBuffer.tokenizedLineForRow(5).tokens[0].scopes).toEqual ['source.js', 'comment.block.js']
expect(tokenizedBuffer.tokenizedLineForRow(3).tokens[0].scopeDescriptor).toEqual ['source.js', 'comment.block.js']
expect(tokenizedBuffer.tokenizedLineForRow(4).tokens[0].scopeDescriptor).toEqual ['source.js', 'comment.block.js']
expect(tokenizedBuffer.tokenizedLineForRow(5).tokens[0].scopeDescriptor).toEqual ['source.js', 'comment.block.js']
expect(changeHandler).toHaveBeenCalled()
[event] = changeHandler.argsForCall[0]
delete event.bufferChange
@@ -185,23 +185,23 @@ describe "TokenizedBuffer", ->
buffer.insert([5, 0], '*/')
buffer.insert([1, 0], 'var ')
expect(tokenizedBuffer.tokenizedLineForRow(1).tokens[0].scopes).toEqual ['source.js', 'comment.block.js']
expect(tokenizedBuffer.tokenizedLineForRow(1).tokens[0].scopeDescriptor).toEqual ['source.js', 'comment.block.js']
describe "when lines are both updated and removed", ->
it "updates tokens to reflect the change", ->
buffer.setTextInRange([[1, 0], [3, 0]], "foo()")
# previous line 0 remains
expect(tokenizedBuffer.tokenizedLineForRow(0).tokens[0]).toEqual(value: 'var', scopes: ['source.js', 'storage.modifier.js'])
expect(tokenizedBuffer.tokenizedLineForRow(0).tokens[0]).toEqual(value: 'var', scopeDescriptor: ['source.js', 'storage.modifier.js'])
# previous line 3 should be combined with input to form line 1
expect(tokenizedBuffer.tokenizedLineForRow(1).tokens[0]).toEqual(value: 'foo', scopes: ['source.js'])
expect(tokenizedBuffer.tokenizedLineForRow(1).tokens[6]).toEqual(value: '=', scopes: ['source.js', 'keyword.operator.js'])
expect(tokenizedBuffer.tokenizedLineForRow(1).tokens[0]).toEqual(value: 'foo', scopeDescriptor: ['source.js'])
expect(tokenizedBuffer.tokenizedLineForRow(1).tokens[6]).toEqual(value: '=', scopeDescriptor: ['source.js', 'keyword.operator.js'])
# lines below deleted regions should be shifted upward
expect(tokenizedBuffer.tokenizedLineForRow(2).tokens[2]).toEqual(value: 'while', scopes: ['source.js', 'keyword.control.js'])
expect(tokenizedBuffer.tokenizedLineForRow(3).tokens[4]).toEqual(value: '=', scopes: ['source.js', 'keyword.operator.js'])
expect(tokenizedBuffer.tokenizedLineForRow(4).tokens[4]).toEqual(value: '<', scopes: ['source.js', 'keyword.operator.js'])
expect(tokenizedBuffer.tokenizedLineForRow(2).tokens[2]).toEqual(value: 'while', scopeDescriptor: ['source.js', 'keyword.control.js'])
expect(tokenizedBuffer.tokenizedLineForRow(3).tokens[4]).toEqual(value: '=', scopeDescriptor: ['source.js', 'keyword.operator.js'])
expect(tokenizedBuffer.tokenizedLineForRow(4).tokens[4]).toEqual(value: '<', scopeDescriptor: ['source.js', 'keyword.operator.js'])
expect(changeHandler).toHaveBeenCalled()
[event] = changeHandler.argsForCall[0]
@@ -214,8 +214,8 @@ describe "TokenizedBuffer", ->
changeHandler.reset()
buffer.setTextInRange([[2, 0], [3, 0]], '/*')
expect(tokenizedBuffer.tokenizedLineForRow(2).tokens[0].scopes).toEqual ['source.js', 'comment.block.js', 'punctuation.definition.comment.js']
expect(tokenizedBuffer.tokenizedLineForRow(3).tokens[0].scopes).toEqual ['source.js']
expect(tokenizedBuffer.tokenizedLineForRow(2).tokens[0].scopeDescriptor).toEqual ['source.js', 'comment.block.js', 'punctuation.definition.comment.js']
expect(tokenizedBuffer.tokenizedLineForRow(3).tokens[0].scopeDescriptor).toEqual ['source.js']
expect(changeHandler).toHaveBeenCalled()
[event] = changeHandler.argsForCall[0]
delete event.bufferChange
@@ -223,8 +223,8 @@ describe "TokenizedBuffer", ->
changeHandler.reset()
advanceClock()
expect(tokenizedBuffer.tokenizedLineForRow(3).tokens[0].scopes).toEqual ['source.js', 'comment.block.js']
expect(tokenizedBuffer.tokenizedLineForRow(4).tokens[0].scopes).toEqual ['source.js', 'comment.block.js']
expect(tokenizedBuffer.tokenizedLineForRow(3).tokens[0].scopeDescriptor).toEqual ['source.js', 'comment.block.js']
expect(tokenizedBuffer.tokenizedLineForRow(4).tokens[0].scopeDescriptor).toEqual ['source.js', 'comment.block.js']
expect(changeHandler).toHaveBeenCalled()
[event] = changeHandler.argsForCall[0]
delete event.bufferChange
@@ -235,19 +235,19 @@ describe "TokenizedBuffer", ->
buffer.setTextInRange([[1, 0], [2, 0]], "foo()\nbar()\nbaz()\nquux()")
# previous line 0 remains
expect(tokenizedBuffer.tokenizedLineForRow(0).tokens[0]).toEqual( value: 'var', scopes: ['source.js', 'storage.modifier.js'])
expect(tokenizedBuffer.tokenizedLineForRow(0).tokens[0]).toEqual( value: 'var', scopeDescriptor: ['source.js', 'storage.modifier.js'])
# 3 new lines inserted
expect(tokenizedBuffer.tokenizedLineForRow(1).tokens[0]).toEqual(value: 'foo', scopes: ['source.js'])
expect(tokenizedBuffer.tokenizedLineForRow(2).tokens[0]).toEqual(value: 'bar', scopes: ['source.js'])
expect(tokenizedBuffer.tokenizedLineForRow(3).tokens[0]).toEqual(value: 'baz', scopes: ['source.js'])
expect(tokenizedBuffer.tokenizedLineForRow(1).tokens[0]).toEqual(value: 'foo', scopeDescriptor: ['source.js'])
expect(tokenizedBuffer.tokenizedLineForRow(2).tokens[0]).toEqual(value: 'bar', scopeDescriptor: ['source.js'])
expect(tokenizedBuffer.tokenizedLineForRow(3).tokens[0]).toEqual(value: 'baz', scopeDescriptor: ['source.js'])
# previous line 2 is joined with quux() on line 4
expect(tokenizedBuffer.tokenizedLineForRow(4).tokens[0]).toEqual(value: 'quux', scopes: ['source.js'])
expect(tokenizedBuffer.tokenizedLineForRow(4).tokens[4]).toEqual(value: 'if', scopes: ['source.js', 'keyword.control.js'])
expect(tokenizedBuffer.tokenizedLineForRow(4).tokens[0]).toEqual(value: 'quux', scopeDescriptor: ['source.js'])
expect(tokenizedBuffer.tokenizedLineForRow(4).tokens[4]).toEqual(value: 'if', scopeDescriptor: ['source.js', 'keyword.control.js'])
# previous line 3 is pushed down to become line 5
expect(tokenizedBuffer.tokenizedLineForRow(5).tokens[4]).toEqual(value: '=', scopes: ['source.js', 'keyword.operator.js'])
expect(tokenizedBuffer.tokenizedLineForRow(5).tokens[4]).toEqual(value: '=', scopeDescriptor: ['source.js', 'keyword.operator.js'])
expect(changeHandler).toHaveBeenCalled()
[event] = changeHandler.argsForCall[0]
@@ -264,17 +264,17 @@ describe "TokenizedBuffer", ->
[event] = changeHandler.argsForCall[0]
delete event.bufferChange
expect(event).toEqual(start: 2, end: 2, delta: 2)
expect(tokenizedBuffer.tokenizedLineForRow(2).tokens[0].scopes).toEqual ['source.js', 'comment.block.js', 'punctuation.definition.comment.js']
expect(tokenizedBuffer.tokenizedLineForRow(3).tokens[0].scopes).toEqual ['source.js', 'comment.block.js']
expect(tokenizedBuffer.tokenizedLineForRow(4).tokens[0].scopes).toEqual ['source.js', 'comment.block.js']
expect(tokenizedBuffer.tokenizedLineForRow(5).tokens[0].scopes).toEqual ['source.js']
expect(tokenizedBuffer.tokenizedLineForRow(2).tokens[0].scopeDescriptor).toEqual ['source.js', 'comment.block.js', 'punctuation.definition.comment.js']
expect(tokenizedBuffer.tokenizedLineForRow(3).tokens[0].scopeDescriptor).toEqual ['source.js', 'comment.block.js']
expect(tokenizedBuffer.tokenizedLineForRow(4).tokens[0].scopeDescriptor).toEqual ['source.js', 'comment.block.js']
expect(tokenizedBuffer.tokenizedLineForRow(5).tokens[0].scopeDescriptor).toEqual ['source.js']
changeHandler.reset()
advanceClock() # tokenize invalidated lines in background
expect(tokenizedBuffer.tokenizedLineForRow(5).tokens[0].scopes).toEqual ['source.js', 'comment.block.js']
expect(tokenizedBuffer.tokenizedLineForRow(6).tokens[0].scopes).toEqual ['source.js', 'comment.block.js']
expect(tokenizedBuffer.tokenizedLineForRow(7).tokens[0].scopes).toEqual ['source.js', 'comment.block.js']
expect(tokenizedBuffer.tokenizedLineForRow(8).tokens[0].scopes).not.toBe ['source.js', 'comment.block.js']
expect(tokenizedBuffer.tokenizedLineForRow(5).tokens[0].scopeDescriptor).toEqual ['source.js', 'comment.block.js']
expect(tokenizedBuffer.tokenizedLineForRow(6).tokens[0].scopeDescriptor).toEqual ['source.js', 'comment.block.js']
expect(tokenizedBuffer.tokenizedLineForRow(7).tokens[0].scopeDescriptor).toEqual ['source.js', 'comment.block.js']
expect(tokenizedBuffer.tokenizedLineForRow(8).tokens[0].scopeDescriptor).not.toBe ['source.js', 'comment.block.js']
expect(changeHandler).toHaveBeenCalled()
[event] = changeHandler.argsForCall[0]
@@ -343,7 +343,7 @@ describe "TokenizedBuffer", ->
expect(tokens[0].value).toBe "#"
expect(tokens[1].value).toBe " Econ 101"
expect(tokens[2].value).toBe tabAsSpaces
expect(tokens[2].scopes).toEqual tokens[1].scopes
expect(tokens[2].scopeDescriptor).toEqual tokens[1].scopeDescriptor
expect(tokens[2].isAtomic).toBeTruthy()
expect(tokens[3].value).toBe ""
@@ -526,7 +526,7 @@ describe "TokenizedBuffer", ->
fullyTokenize(tokenizedBuffer)
{tokens} = tokenizedBuffer.tokenizedLineForRow(0)
expect(tokens[0]).toEqual value: "<div class='name'>", scopes: ["text.html.ruby"]
expect(tokens[0]).toEqual value: "<div class='name'>", scopeDescriptor: ["text.html.ruby"]
waitsForPromise ->
atom.packages.activatePackage('language-html')
@@ -534,7 +534,7 @@ describe "TokenizedBuffer", ->
runs ->
fullyTokenize(tokenizedBuffer)
{tokens} = tokenizedBuffer.tokenizedLineForRow(0)
expect(tokens[0]).toEqual value: '<', scopes: ["text.html.ruby","meta.tag.block.any.html","punctuation.definition.tag.begin.html"]
expect(tokens[0]).toEqual value: '<', scopeDescriptor: ["text.html.ruby","meta.tag.block.any.html","punctuation.definition.tag.begin.html"]
describe ".tokenForPosition(position)", ->
afterEach ->
@@ -545,9 +545,9 @@ describe "TokenizedBuffer", ->
buffer = atom.project.bufferForPathSync('sample.js')
tokenizedBuffer = new TokenizedBuffer({buffer})
fullyTokenize(tokenizedBuffer)
expect(tokenizedBuffer.tokenForPosition([1,0]).scopes).toEqual ["source.js"]
expect(tokenizedBuffer.tokenForPosition([1,1]).scopes).toEqual ["source.js"]
expect(tokenizedBuffer.tokenForPosition([1,2]).scopes).toEqual ["source.js", "storage.modifier.js"]
expect(tokenizedBuffer.tokenForPosition([1,0]).scopeDescriptor).toEqual ["source.js"]
expect(tokenizedBuffer.tokenForPosition([1,1]).scopeDescriptor).toEqual ["source.js"]
expect(tokenizedBuffer.tokenForPosition([1,2]).scopeDescriptor).toEqual ["source.js", "storage.modifier.js"]
describe ".bufferRangeForScopeAtPosition(selector, position)", ->
beforeEach ->
@@ -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 ->
+4 -4
Ver Arquivo
@@ -19,16 +19,16 @@ describe "TokenizedLine", ->
expect(editor.tokenizedLineForScreenRow(2).isOnlyWhitespace()).toBe false
describe "::getScopeTree()", ->
it "returns a tree whose inner nodes are scopes and whose leaf nodes are tokens in those scopes", ->
it "returns a tree whose inner nodes are scopeDescriptor and whose leaf nodes are tokens in those scopeDescriptor", ->
[tokens, tokenIndex] = []
ensureValidScopeTree = (scopeTree, scopes=[]) ->
ensureValidScopeTree = (scopeTree, scopeDescriptor=[]) ->
if scopeTree.children?
for child in scopeTree.children
ensureValidScopeTree(child, scopes.concat([scopeTree.scope]))
ensureValidScopeTree(child, scopeDescriptor.concat([scopeTree.scope]))
else
expect(scopeTree).toBe tokens[tokenIndex++]
expect(scopes).toEqual scopeTree.scopes
expect(scopeDescriptor).toEqual scopeTree.scopeDescriptor
waitsForPromise ->
atom.project.open('coffee.coffee').then (o) -> editor = o
+9 -17
Ver Arquivo
@@ -8,7 +8,7 @@ describe "Window", ->
beforeEach ->
spyOn(atom, 'hide')
initialPath = atom.project.getPath()
initialPath = atom.project.getPaths()[0]
spyOn(atom, 'getLoadSettings').andCallFake ->
loadSettings = atom.getLoadSettings.originalValue.call(atom)
loadSettings.initialPath = initialPath
@@ -16,7 +16,7 @@ describe "Window", ->
atom.project.destroy()
windowEventHandler = new WindowEventHandler()
atom.deserializeEditorWindow()
projectPath = atom.project.getPath()
projectPath = atom.project.getPaths()[0]
afterEach ->
windowEventHandler.unsubscribe()
@@ -47,14 +47,6 @@ describe "Window", ->
$(window).trigger 'window:close'
expect(atom.close).toHaveBeenCalled()
it "emits the beforeunload event", ->
$(window).off 'beforeunload'
beforeunload = jasmine.createSpy('beforeunload').andReturn(false)
$(window).on 'beforeunload', beforeunload
$(window).trigger 'window:close'
expect(beforeunload).toHaveBeenCalled()
describe "beforeunload event", ->
[beforeUnloadEvent] = []
@@ -63,9 +55,9 @@ describe "Window", ->
beforeUnloadEvent = $.Event(new Event('beforeunload'))
describe "when pane items are are modified", ->
it "prompts user to save and and calls workspaceView.confirmClose", ->
it "prompts user to save and calls atom.workspace.confirmClose", ->
editor = null
spyOn(atom.workspaceView, 'confirmClose').andCallThrough()
spyOn(atom.workspace, 'confirmClose').andCallThrough()
spyOn(atom, "confirm").andReturn(2)
waitsForPromise ->
@@ -74,7 +66,7 @@ describe "Window", ->
runs ->
editor.insertText("I look different, I feel different.")
$(window).trigger(beforeUnloadEvent)
expect(atom.workspaceView.confirmClose).toHaveBeenCalled()
expect(atom.workspace.confirmClose).toHaveBeenCalled()
expect(atom.confirm).toHaveBeenCalled()
it "prompts user to save and handler returns true if don't save", ->
@@ -122,7 +114,7 @@ describe "Window", ->
buffer = atom.workspace.getActivePaneItem().buffer
pane = atom.workspaceView.getActivePaneView()
pane.splitRight(pane.copyActiveItem())
expect(atom.workspaceView.find('.editor').length).toBe 2
expect(atom.workspaceView.find('atom-text-editor').length).toBe 2
atom.removeEditorWindow()
@@ -263,19 +255,19 @@ describe "Window", ->
describe "when the project does not have a path", ->
beforeEach ->
atom.project.setPath()
atom.project.setPaths([])
describe "when the opened path exists", ->
it "sets the project path to the opened path", ->
$(window).trigger('window:open-path', [{pathToOpen: __filename}])
expect(atom.project.getPath()).toBe __dirname
expect(atom.project.getPaths()[0]).toBe __dirname
describe "when the opened path does not exist but its parent directory does", ->
it "sets the project path to the opened path's parent directory", ->
$(window).trigger('window:open-path', [{pathToOpen: path.join(__dirname, 'this-path-does-not-exist.txt')}])
expect(atom.project.getPath()).toBe __dirname
expect(atom.project.getPaths()[0]).toBe __dirname
describe "when the opened path is a file", ->
it "opens it in the workspace", ->
+90 -3
Ver Arquivo
@@ -1,3 +1,5 @@
path = require 'path'
temp = require 'temp'
Workspace = require '../src/workspace'
{View} = require '../src/space-pen-extensions'
@@ -5,7 +7,7 @@ describe "Workspace", ->
workspace = null
beforeEach ->
atom.project.setPath(atom.project.resolve('dir'))
atom.project.setPaths([atom.project.resolve('dir')])
atom.workspace = workspace = new Workspace
describe "::open(uri, options)", ->
@@ -220,8 +222,8 @@ describe "Workspace", ->
it "returns the resource returned by the custom opener", ->
fooOpener = (pathToOpen, options) -> { foo: pathToOpen, options } if pathToOpen?.match(/\.foo/)
barOpener = (pathToOpen) -> { bar: pathToOpen } if pathToOpen?.match(/^bar:\/\//)
workspace.registerOpener(fooOpener)
workspace.registerOpener(barOpener)
workspace.addOpener(fooOpener)
workspace.addOpener(barOpener)
waitsForPromise ->
pathToOpen = atom.project.resolve('a.foo')
@@ -369,3 +371,88 @@ describe "Workspace", ->
workspace2 = Workspace.deserialize(state)
expect(jsPackage.loadGrammarsSync.callCount).toBe 1
expect(coffeePackage.loadGrammarsSync.callCount).toBe 1
describe "document.title", ->
describe "when the project has no path", ->
it "sets the title to 'untitled'", ->
atom.project.setPath(undefined)
expect(document.title).toBe 'untitled - Atom'
describe "when the project has a path", ->
beforeEach ->
waitsForPromise ->
atom.workspace.open('b')
describe "when there is an active pane item", ->
it "sets the title to the pane item's title plus the project path", ->
item = atom.workspace.getActivePaneItem()
expect(document.title).toBe "#{item.getTitle()} - #{atom.project.getPaths()[0]} - Atom"
describe "when the title of the active pane item changes", ->
it "updates the window title based on the item's new title", ->
editor = atom.workspace.getActivePaneItem()
editor.buffer.setPath(path.join(temp.dir, 'hi'))
expect(document.title).toBe "#{editor.getTitle()} - #{atom.project.getPaths()[0]} - Atom"
describe "when the active pane's item changes", ->
it "updates the title to the new item's title plus the project path", ->
atom.workspace.getActivePane().activateNextItem()
item = atom.workspace.getActivePaneItem()
expect(document.title).toBe "#{item.getTitle()} - #{atom.project.getPaths()[0]} - Atom"
describe "when the last pane item is removed", ->
it "updates the title to contain the project's path", ->
atom.workspace.getActivePane().destroy()
expect(atom.workspace.getActivePaneItem()).toBeUndefined()
expect(document.title).toBe "#{atom.project.getPaths()[0]} - Atom"
describe "when an inactive pane's item changes", ->
it "does not update the title", ->
pane = atom.workspace.getActivePane()
pane.splitRight()
initialTitle = document.title
pane.activateNextItem()
expect(document.title).toBe initialTitle
describe "when the workspace is deserialized", ->
beforeEach ->
waitsForPromise -> atom.workspace.open('a')
it "updates the title to contain the project's path", ->
document.title = null
workspace2 = atom.workspace.testSerialization()
item = atom.workspace.getActivePaneItem()
expect(document.title).toBe "#{item.getTitle()} - #{atom.project.getPaths()[0]} - Atom"
workspace2.destroy()
describe "document edited status", ->
[item1, item2] = []
beforeEach ->
waitsForPromise -> atom.workspace.open('a')
waitsForPromise -> atom.workspace.open('b')
runs ->
[item1, item2] = atom.workspace.getPaneItems()
spyOn(atom, 'setDocumentEdited')
it "calls atom.setDocumentEdited when the active item changes", ->
expect(atom.workspace.getActivePaneItem()).toBe item2
item1.insertText('a')
expect(item1.isModified()).toBe true
atom.workspace.getActivePane().activateNextItem()
expect(atom.setDocumentEdited).toHaveBeenCalledWith(true)
it "calls atom.setDocumentEdited when the active item's modified status changes", ->
expect(atom.workspace.getActivePaneItem()).toBe item2
item2.insertText('a')
advanceClock(item2.getBuffer().getStoppedChangingDelay())
expect(item2.isModified()).toBe true
expect(atom.setDocumentEdited).toHaveBeenCalledWith(true)
item2.undo()
advanceClock(item2.getBuffer().getStoppedChangingDelay())
expect(item2.isModified()).toBe false
expect(atom.setDocumentEdited).toHaveBeenCalledWith(false)
+12 -66
Ver Arquivo
@@ -10,7 +10,7 @@ describe "WorkspaceView", ->
pathToOpen = null
beforeEach ->
atom.project.setPath(atom.project.resolve('dir'))
atom.project.setPaths([atom.project.resolve('dir')])
pathToOpen = atom.project.resolve('a')
atom.workspace = new Workspace
atom.workspaceView = atom.workspace.getView(atom.workspace).__spacePenView
@@ -49,7 +49,7 @@ describe "WorkspaceView", ->
expect(atom.workspaceView.getEditorViews().length).toBe 2
expect(atom.workspaceView.getActivePaneView()).toBe atom.workspaceView.getPaneViews()[1]
expect(atom.workspaceView.title).toBe "untitled - #{atom.project.getPath()}"
expect(document.title).toBe "untitled - #{atom.project.getPaths()[0]} - Atom"
describe "when there are open editors", ->
it "constructs the view with the same panes", ->
@@ -82,10 +82,10 @@ describe "WorkspaceView", ->
simulateReload()
expect(atom.workspaceView.getEditorViews().length).toBe 4
editorView1 = atom.workspaceView.panes.find('.pane-row > .pane .editor:eq(0)').view()
editorView3 = atom.workspaceView.panes.find('.pane-row > .pane .editor:eq(1)').view()
editorView2 = atom.workspaceView.panes.find('.pane-row > .pane-column > .pane .editor:eq(0)').view()
editorView4 = atom.workspaceView.panes.find('.pane-row > .pane-column > .pane .editor:eq(1)').view()
editorView1 = atom.workspaceView.panes.find('atom-pane-axis.horizontal > atom-pane atom-text-editor:eq(0)').view()
editorView3 = atom.workspaceView.panes.find('atom-pane-axis.horizontal > atom-pane atom-text-editor:eq(1)').view()
editorView2 = atom.workspaceView.panes.find('atom-pane-axis.horizontal > atom-pane-axis.vertical > atom-pane atom-text-editor:eq(0)').view()
editorView4 = atom.workspaceView.panes.find('atom-pane-axis.horizontal > atom-pane-axis.vertical > atom-pane atom-text-editor:eq(1)').view()
expect(editorView1.getEditor().getPath()).toBe atom.project.resolve('a')
expect(editorView2.getEditor().getPath()).toBe atom.project.resolve('b')
@@ -106,7 +106,7 @@ describe "WorkspaceView", ->
expect(editorView3).not.toHaveFocus()
expect(editorView4).not.toHaveFocus()
expect(atom.workspaceView.title).toBe "#{path.basename(editorView2.getEditor().getPath())} - #{atom.project.getPath()}"
expect(document.title).toBe "#{path.basename(editorView2.getEditor().getPath())} - #{atom.project.getPaths()[0]} - Atom"
describe "where there are no open editors", ->
it "constructs the view with no open editors", ->
@@ -127,70 +127,16 @@ describe "WorkspaceView", ->
expect(activePane).toHaveFocus()
describe "keymap wiring", ->
commandHandler = null
beforeEach ->
commandHandler = jasmine.createSpy('commandHandler')
atom.workspaceView.on('foo-command', commandHandler)
atom.keymaps.add('name', '*': {'x': 'foo-command'})
describe "when a keydown event is triggered in the WorkspaceView", ->
it "triggers matching keybindings for that event", ->
commandHandler = jasmine.createSpy('commandHandler')
atom.workspaceView.on('foo-command', commandHandler)
atom.keymaps.add('name', '*': {'x': 'foo-command'})
event = keydownEvent 'x', target: atom.workspaceView[0]
atom.workspaceView.trigger(event)
expect(commandHandler).toHaveBeenCalled()
describe "window title", ->
describe "when the project has no path", ->
it "sets the title to 'untitled'", ->
atom.project.setPath(undefined)
expect(atom.workspaceView.title).toBe 'untitled'
describe "when the project has a path", ->
beforeEach ->
waitsForPromise ->
atom.workspace.open('b')
describe "when there is an active pane item", ->
it "sets the title to the pane item's title plus the project path", ->
item = atom.workspace.getActivePaneItem()
expect(atom.workspaceView.title).toBe "#{item.getTitle()} - #{atom.project.getPath()}"
describe "when the title of the active pane item changes", ->
it "updates the window title based on the item's new title", ->
editor = atom.workspace.getActivePaneItem()
editor.buffer.setPath(path.join(temp.dir, 'hi'))
expect(atom.workspaceView.title).toBe "#{editor.getTitle()} - #{atom.project.getPath()}"
describe "when the active pane's item changes", ->
it "updates the title to the new item's title plus the project path", ->
atom.workspaceView.getActivePaneView().activateNextItem()
item = atom.workspace.getActivePaneItem()
expect(atom.workspaceView.title).toBe "#{item.getTitle()} - #{atom.project.getPath()}"
describe "when the last pane item is removed", ->
it "updates the title to contain the project's path", ->
atom.workspaceView.getActivePaneView().remove()
expect(atom.workspace.getActivePaneItem()).toBeUndefined()
expect(atom.workspaceView.title).toBe atom.project.getPath()
describe "when an inactive pane's item changes", ->
it "does not update the title", ->
pane = atom.workspaceView.getActivePaneView()
pane.splitRight()
initialTitle = atom.workspaceView.title
pane.activateNextItem()
expect(atom.workspaceView.title).toBe initialTitle
describe "when the root view is deserialized", ->
it "updates the title to contain the project's path", ->
workspace2 = atom.workspace.testSerialization()
workspaceView2 = workspace2.getView(workspace2).__spacePenView
item = atom.workspace.getActivePaneItem()
expect(workspaceView2.title).toBe "#{item.getTitle()} - #{atom.project.getPath()}"
workspaceView2.remove()
describe "window:toggle-invisibles event", ->
it "shows/hides invisibles in all open and future editors", ->
atom.workspaceView.height(200)
@@ -302,8 +248,8 @@ describe "WorkspaceView", ->
beforeEach ->
atom.workspaceView.attachToDom()
editorNode = atom.workspaceView.find('.editor')[0]
editor = atom.workspaceView.find('.editor').view().getEditor()
editorNode = atom.workspaceView.find('atom-text-editor')[0]
editor = atom.workspaceView.find('atom-text-editor').view().getEditor()
it "updates the font-size based on the 'editor.fontSize' config value", ->
initialCharWidth = editor.getDefaultCharWidth()
+8 -6
Ver Arquivo
@@ -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('./text-editor-view').configDefaults)
@loadConfig()
@keymaps.loadBundledKeymaps()
@themes.loadBaseStylesheets()
@packages.loadPackages()
@@ -579,7 +577,7 @@ class Atom extends Model
Project = require './project'
startTime = Date.now()
@project ?= @deserializers.deserialize(@state.project) ? new Project(path: @getLoadSettings().initialPath)
@project ?= @deserializers.deserialize(@state.project) ? new Project(paths: [@getLoadSettings().initialPath])
@deserializeTimings.project = Date.now() - startTime
deserializeWorkspaceView: ->
@@ -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()
@@ -617,8 +619,8 @@ class Atom extends Model
# Notify the browser project of the window's current project path
watchProjectPath: ->
onProjectPathChanged = =>
ipc.send('window-command', 'project-path-changed', @project.getPath())
@subscribe @project, 'path-changed', onProjectPathChanged
ipc.send('window-command', 'project-path-changed', @project.getPaths()[0])
@subscribe @project.onDidChangePaths(onProjectPathChanged)
onProjectPathChanged()
exit: (status) ->
+3 -2
Ver Arquivo
@@ -376,10 +376,11 @@ class AtomApplication
# Kill the process with the given pid.
killProcess: (pid) ->
try
process.kill(pid)
parsedPid = parseInt(pid)
process.kill(parsedPid) if isFinite(parsedPid)
catch error
if error.code isnt 'ESRCH'
console.log("Killing process #{pid} failed: #{error.code}")
console.log("Killing process #{pid} failed: #{error.code ? error.message}")
delete @pidsToOpenWindows[pid]
# Open an atom:// url.
+1
Ver Arquivo
@@ -28,6 +28,7 @@ class AtomWindow
title: 'Atom'
icon: @constructor.iconPath
'web-preferences':
'direct-write': false
'subpixel-font-scaling': false
global.atomApplication.addWindow(this)
+4 -4
Ver Arquivo
@@ -13,12 +13,12 @@ class ContextMenu
createClickHandlers: (template) ->
for item in template
if item.command
item.commandOptions ?= {}
item.commandOptions.contextCommand = true
item.commandOptions.atomWindow = @atomWindow
item.commandDetail ?= {}
item.commandDetail.contextCommand = true
item.commandDetail.atomWindow = @atomWindow
do (item) =>
item.click = =>
global.atomApplication.sendCommandToWindow(item.command, @atomWindow, item.commandOptions)
global.atomApplication.sendCommandToWindow(item.command, @atomWindow, item.commandDetail)
else if item.submenu
@createClickHandlers(item.submenu)
item
+29 -10
Ver Arquivo
@@ -30,14 +30,41 @@ module.exports =
getInstallDirectory: ->
"/usr/local/bin"
install: (commandPath, askForPrivilege, callback) ->
installShellCommandsInteractively: ->
showErrorDialog = (error) ->
atom.confirm
message: "Failed to install shell commands"
detailedMessage: error.message
resourcePath = atom.getLoadSettings().resourcePath
@installAtomCommand resourcePath, true, (error) =>
if error?
showErrorDialog(error)
else
@installApmCommand resourcePath, true, (error) ->
if error?
showErrorDialog(error)
else
atom.confirm
message: "Commands installed."
detailedMessage: "The shell commands `atom` and `apm` are installed."
installAtomCommand: (resourcePath, askForPrivilege, callback) ->
commandPath = path.join(resourcePath, 'atom.sh')
@createSymlink commandPath, askForPrivilege, callback
installApmCommand: (resourcePath, askForPrivilege, callback) ->
commandPath = path.join(resourcePath, 'apm', 'node_modules', '.bin', 'apm')
@createSymlink commandPath, askForPrivilege, callback
createSymlink: (commandPath, askForPrivilege, callback) ->
return unless process.platform is 'darwin'
commandName = path.basename(commandPath, path.extname(commandPath))
destinationPath = path.join(@getInstallDirectory(), commandName)
fs.readlink destinationPath, (error, realpath) ->
if realpath == commandPath
if realpath is commandPath
callback()
return
@@ -49,11 +76,3 @@ module.exports =
catch error
callback?(error)
installAtomCommand: (resourcePath, askForPrivilege, callback) ->
commandPath = path.join(resourcePath, 'atom.sh')
@install commandPath, askForPrivilege, callback
installApmCommand: (resourcePath, askForPrivilege, callback) ->
commandPath = path.join(resourcePath, 'apm', 'node_modules', '.bin', 'apm')
@install commandPath, askForPrivilege, callback
+78 -63
Ver Arquivo
@@ -1,4 +1,4 @@
{Disposable, CompositeDisposable} = require 'event-kit'
{Emitter, Disposable, CompositeDisposable} = require 'event-kit'
{specificity} = require 'clear-cut'
_ = require 'underscore-plus'
{$} = require './space-pen-extensions'
@@ -35,7 +35,7 @@ module.exports =
# Here is a command that inserts the current date in an editor:
#
# ```coffee
# atom.commands.add '.editor',
# atom.commands.add 'atom-text-editor',
# 'user:insert-date': (event) ->
# editor = $(this).view().getModel()
# # soon the above above line will be:
@@ -44,17 +44,14 @@ module.exports =
# ```
class CommandRegistry
constructor: (@rootNode) ->
@listenersByCommandName = {}
@registeredCommands = {}
@selectorBasedListenersByCommandName = {}
@inlineListenersByCommandName = {}
@emitter = new Emitter
getRootNode: -> @rootNode
setRootNode: (newRootNode) ->
oldRootNode = @rootNode
@rootNode = newRootNode
for commandName of @listenersByCommandName
@removeCommandListener(oldRootNode, commandName)
@addCommandListener(newRootNode, commandName)
destroy: ->
for commandName of @registeredCommands
window.removeEventListener(commandName, @handleCommandEvent, true)
# Public: Add one or more command listeners associated with a selector.
#
@@ -81,27 +78,46 @@ class CommandRegistry
#
# Returns a {Disposable} on which `.dispose()` can be called to remove the
# added command handler(s).
add: (selector, commandName, callback) ->
add: (target, commandName, callback) ->
if typeof commandName is 'object'
commands = commandName
disposable = new CompositeDisposable
for commandName, callback of commands
disposable.add @add(selector, commandName, callback)
disposable.add @add(target, commandName, callback)
return disposable
unless @listenersByCommandName[commandName]?
@addCommandListener(@rootNode, commandName)
@listenersByCommandName[commandName] = []
if typeof target is 'string'
@addSelectorBasedListener(target, commandName, callback)
else
@addInlineListener(target, commandName, callback)
listener = new CommandListener(selector, callback)
listenersForCommand = @listenersByCommandName[commandName]
addSelectorBasedListener: (selector, commandName, callback) ->
@selectorBasedListenersByCommandName[commandName] ?= []
listenersForCommand = @selectorBasedListenersByCommandName[commandName]
listener = new SelectorBasedListener(selector, callback)
listenersForCommand.push(listener)
@commandRegistered(commandName)
new Disposable =>
listenersForCommand.splice(listenersForCommand.indexOf(listener), 1)
if listenersForCommand.length is 0
delete @listenersByCommandName[commandName]
@removeCommandListener(@rootNode, commandName)
delete @selectorBasedListenersByCommandName[commandName] if listenersForCommand.length is 0
addInlineListener: (element, commandName, callback) ->
@inlineListenersByCommandName[commandName] ?= new WeakMap
listenersForCommand = @inlineListenersByCommandName[commandName]
unless listenersForElement = listenersForCommand.get(element)
listenersForElement = []
listenersForCommand.set(element, listenersForElement)
listener = new InlineListener(callback)
listenersForElement.push(listener)
@commandRegistered(commandName)
new Disposable =>
listenersForElement.splice(listenersForElement.indexOf(listener), 1)
listenersForCommand.delete(element) if listenersForElement.length is 0
# Public: Find all registered commands matching a query.
#
@@ -116,12 +132,11 @@ class CommandRegistry
# `$::command` method.
findCommands: ({target}) ->
commands = []
target = @rootNode unless @rootNode.contains(target)
currentTarget = target
loop
for commandName, listeners of @listenersByCommandName
for commandName, listeners of @selectorBasedListenersByCommandName
for listener in listeners
if currentTarget.webkitMatchesSelector(listener.selector)
if currentTarget.webkitMatchesSelector?(listener.selector)
commands.push
name: commandName
displayName: _.humanizeEventName(commandName)
@@ -147,37 +162,40 @@ class CommandRegistry
#
# * `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)
dispatch: (target, commandName, detail) ->
event = new CustomEvent(commandName, {bubbles: true, detail})
eventWithTarget = Object.create event,
target: value: target
preventDefault: value: ->
stopPropagation: value: ->
stopImmediatePropagation: value: ->
@handleCommandEvent(eventWithTarget)
onWillDispatch: (callback) ->
@emitter.on 'will-dispatch', callback
getSnapshot: ->
snapshot = {}
for commandName, listeners of @listenersByCommandName
for commandName, listeners of @selectorBasedListenersByCommandName
snapshot[commandName] = listeners.slice()
snapshot
restoreSnapshot: (snapshot) ->
rootNode = @getRootNode()
@setRootNode(null) # clear listeners for current commands
@listenersByCommandName = {}
@selectorBasedListenersByCommandName = {}
for commandName, listeners of snapshot
@listenersByCommandName[commandName] = listeners.slice()
@setRootNode(rootNode) # restore listeners for commands in snapshot
@selectorBasedListenersByCommandName[commandName] = listeners.slice()
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
preventDefault: value: ->
originalEvent.preventDefault()
stopPropagation: value: ->
originalEvent.stopPropagation()
propagationStopped = true
@@ -185,44 +203,38 @@ class CommandRegistry
originalEvent.stopImmediatePropagation()
propagationStopped = true
immediatePropagationStopped = true
disableInvokedListeners: value: ->
listener.enabled = false for listener in invokedListeners
-> listener.enabled = true for listener in invokedListeners
abortKeyBinding: value: ->
originalEvent.abortKeyBinding?()
@emitter.emit 'will-dispatch', syntheticEvent
loop
matchingListeners =
(@listenersByCommandName[originalEvent.type] ? [])
.filter (listener) -> currentTarget.webkitMatchesSelector(listener.selector)
.sort (a, b) -> a.compare(b)
listeners = @inlineListenersByCommandName[originalEvent.type]?.get(currentTarget) ? []
if currentTarget.webkitMatchesSelector?
selectorBasedListeners =
(@selectorBasedListenersByCommandName[originalEvent.type] ? [])
.filter (listener) -> currentTarget.webkitMatchesSelector(listener.selector)
.sort (a, b) -> a.compare(b)
listeners = listeners.concat(selectorBasedListeners)
matched = true if matchingListeners.length > 0
matched = true if listeners.length > 0
for listener in matchingListeners when listener.enabled
for listener in listeners
break if immediatePropagationStopped
invokedListeners.push(listener)
listener.callback.call(currentTarget, syntheticEvent)
break if currentTarget is @rootNode
break if currentTarget is window
break if propagationStopped
currentTarget = currentTarget.parentNode
break unless currentTarget?
currentTarget = currentTarget.parentNode ? window
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
commandRegistered: (commandName) ->
unless @registeredCommands[commandName]
window.addEventListener(commandName, @handleCommandEvent, true)
@registeredCommands[commandName] = true
class SelectorBasedListener
constructor: (@selector, @callback) ->
@specificity = (SpecificityCache[@selector] ?= specificity(@selector))
@sequenceNumber = SequenceCount++
@@ -230,3 +242,6 @@ class CommandListener
compare: (other) ->
other.specificity - @specificity or
other.sequenceNumber - @sequenceNumber
class InlineListener
constructor: (@callback) ->
+130
Ver Arquivo
@@ -0,0 +1,130 @@
path = require 'path'
fs = require 'fs-plus'
# This is loaded by atom.coffee. See https://atom.io/docs/api/latest/Config for
# more information about config schemas.
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
title: 'Exclude VCS Ignored Paths'
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:
# These settings are used in scoped fashion only. No defaults.
commentStart:
type: ['string', 'null']
commentEnd:
type: ['string', 'null']
increaseIndentPattern:
type: ['string', 'null']
decreaseIndentPattern:
type: ['string', 'null']
foldEndPattern:
type: ['string', 'null']
# These can be used as globals or scoped, thus defaults.
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
enum: [1, 2, 3, 4, 6, 8]
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
description: 'Disabling will improve editor font rendering but reduce scrolling performance.'
confirmCheckoutHeadRevision:
type: 'boolean'
default: true
title: 'Confirm Checkout HEAD Revision'
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'
+874 -179
Ver Arquivo
Diferenças do arquivo suprimidas por serem muito extensas Carregar Diff
+139 -95
Ver Arquivo
@@ -4,6 +4,12 @@ remote = require 'remote'
path = require 'path'
CSON = require 'season'
fs = require 'fs-plus'
{specificity} = require 'clear-cut'
{Disposable} = require 'event-kit'
Grim = require 'grim'
MenuHelpers = require './menu-helpers'
SpecificityCache = {}
# Extended: Provides a registry for commands that you'd like to appear in the
# context menu.
@@ -13,16 +19,8 @@ fs = require 'fs-plus'
module.exports =
class ContextMenuManager
constructor: ({@resourcePath, @devMode}) ->
@definitions = {}
@devModeDefinitions = {}
@activeElement = null
@devModeDefinitions['.workspace'] = [
label: 'Inspect Element'
command: 'application:inspect'
executeAtBuild: (e) ->
@commandOptions = x: e.pageX, y: e.pageY
]
@definitions = {'.overlayer': []} # TODO: Remove once color picker package stops touching private data
@clear()
atom.keymaps.onDidLoadBundledKeymaps => @loadPlatformItems()
@@ -30,102 +28,148 @@ class ContextMenuManager
menusDirPath = path.join(@resourcePath, 'menus')
platformMenuPath = fs.resolve(menusDirPath, process.platform, ['cson', 'json'])
map = CSON.readFileSync(platformMenuPath)
atom.contextMenu.add(platformMenuPath, map['context-menu'])
atom.contextMenu.add(map['context-menu'])
# Public: Creates menu definitions from the object specified by the menu
# JSON API.
# Public: Add context menu items scoped by CSS selectors.
#
# * `name` The path of the file that contains the menu definitions.
# * `object` The 'context-menu' object specified in the menu JSON API.
# * `options` An optional {Object} with the following keys:
# * `devMode` Determines whether the entries should only be shown when
# the window is in dev mode.
add: (name, object, {devMode}={}) ->
for selector, items of object
for label, commandOrSubmenu of items
if typeof commandOrSubmenu is 'object'
submenu = []
for submenuLabel, command of commandOrSubmenu
submenu.push(@buildMenuItem(submenuLabel, command))
@addBySelector(selector, {label: label, submenu: submenu}, {devMode})
else
menuItem = @buildMenuItem(label, commandOrSubmenu)
@addBySelector(selector, menuItem, {devMode})
undefined
buildMenuItem: (label, command) ->
if command is '-'
{type: 'separator'}
else
{label, command}
# Registers a command to be displayed when the relevant item is right
# clicked.
# ## Examples
#
# * `selector` The css selector for the active element which should include
# the given command in its context menu.
# * `definition` The object containing keys which match the menu template API.
# * `options` An optional {Object} with the following keys:
# * `devMode` Indicates whether this command should only appear while the
# editor is in dev mode.
addBySelector: (selector, definition, {devMode}={}) ->
definitions = if devMode then @devModeDefinitions else @definitions
if not _.findWhere(definitions[selector], definition) or _.isEqual(definition, {type: 'separator'})
(definitions[selector] ?= []).push(definition)
# Returns definitions which match the element and devMode.
definitionsForElement: (element, {devMode}={}) ->
definitions = if devMode then @devModeDefinitions else @definitions
matchedDefinitions = []
for selector, items of definitions when element.webkitMatchesSelector(selector)
matchedDefinitions.push(_.clone(item)) for item in items
matchedDefinitions
# Used to generate the context menu for a specific element and it's
# parents.
# To add a context menu, pass a selector matching the elements to which you
# want the menu to apply as the top level key, followed by a menu descriptor.
# The invocation below adds a global 'Help' context menu item and a 'History'
# submenu on the editor supporting undo/redo. This is just for example
# purposes and not the way the menu is actually configured in Atom by default.
#
# The menu items are sorted such that menu items that match closest to the
# active element are listed first. The further down the list you go, the higher
# up the ancestor hierarchy they match.
# ```coffee
# atom.contextMenu.add {
# 'atom-workspace': [{label: 'Help', command: 'application:open-documentation'}]
# 'atom-text-editor': [{
# label: 'History',
# submenu: [
# {label: 'Undo': command:'core:undo'}
# {label: 'Redo': command:'core:redo'}
# ]
# }]
# }
# ```
#
# * `element` The DOM element to generate the menu template for.
menuTemplateForMostSpecificElement: (element, {devMode}={}) ->
menuTemplate = @definitionsForElement(element, {devMode})
if element.parentElement
menuTemplate.concat(@menuTemplateForMostSpecificElement(element.parentElement, {devMode}))
else
menuTemplate
# Returns a menu template for both normal entries as well as
# development mode entries.
combinedMenuTemplateForElement: (element) ->
normalItems = @menuTemplateForMostSpecificElement(element)
devItems = if @devMode then @menuTemplateForMostSpecificElement(element, devMode: true) else []
menuTemplate = normalItems
menuTemplate.push({ type: 'separator' }) if normalItems.length > 0 and devItems.length > 0
menuTemplate.concat(devItems)
# Executes `executeAtBuild` if defined for each menu item with
# the provided event and then removes the `executeAtBuild` property from
# the menu item.
# ## Arguments
#
# This is useful for commands that need to provide data about the event
# to the command.
executeBuildHandlers: (event, menuTemplate) ->
for template in menuTemplate
template?.executeAtBuild?.call(template, event)
delete template.executeAtBuild
# * `itemsBySelector` An {Object} whose keys are CSS selectors and whose
# values are {Array}s of item {Object}s containing the following keys:
# * `label` (Optional) A {String} containing the menu item's label.
# * `command` (Optional) A {String} containing the command to invoke on the
# target of the right click that invoked the context menu.
# * `submenu` (Optional) An {Array} of additional items.
# * `type` (Optional) If you want to create a separator, provide an item
# with `type: 'separator'` and no other keys.
# * `created` (Optional) A {Function} that is called on the item each time a
# context menu is created via a right click. You can assign properties to
# `this` to dynamically compute the command, label, etc. This method is
# actually called on a clone of the original item template to prevent state
# from leaking across context menu deployments. Called with the following
# argument:
# * `event` The click event that deployed the context menu.
# * `shouldDisplay` (Optional) A {Function} that is called to determine
# whether to display this item on a given context menu deployment. Called
# with the following argument:
# * `event` The click event that deployed the context menu.
add: (itemsBySelector) ->
# Detect deprecated file path as first argument
unless typeof itemsBySelector is 'object'
Grim.deprecate("ContextMenuManage::add has changed to take a single object as its argument. Please consult the documentation.")
itemsBySelector = arguments[1]
devMode = arguments[2]?.devMode
# Detect deprecated format for items object
for key, value of itemsBySelector
unless _.isArray(value)
Grim.deprecate("The format for declaring context menu items has changed. Please consult the documentation.")
itemsBySelector = @convertLegacyItemsBySelector(itemsBySelector, devMode)
addedItemSets = []
for selector, items of itemsBySelector
itemSet = new ContextMenuItemSet(selector, items)
addedItemSets.push(itemSet)
@itemSets.push(itemSet)
new Disposable =>
for itemSet in addedItemSets
@itemSets.splice(@itemSets.indexOf(itemSet), 1)
templateForElement: (target) ->
@templateForEvent({target})
templateForEvent: (event) ->
template = []
currentTarget = event.target
while currentTarget?
currentTargetItems = []
matchingItemSets =
@itemSets.filter (itemSet) -> currentTarget.webkitMatchesSelector(itemSet.selector)
for itemSet in matchingItemSets
for item in itemSet.items
continue if item.devMode and not @devMode
item = Object.create(item)
if typeof item.shouldDisplay is 'function'
continue unless item.shouldDisplay(event)
item.created?(event)
MenuHelpers.merge(currentTargetItems, item, itemSet.specificity)
for item in currentTargetItems
MenuHelpers.merge(template, item, false)
currentTarget = currentTarget.parentElement
template
convertLegacyItemsBySelector: (legacyItemsBySelector, devMode) ->
itemsBySelector = {}
for selector, commandsByLabel of legacyItemsBySelector
itemsBySelector[selector] = @convertLegacyItems(commandsByLabel, devMode)
itemsBySelector
convertLegacyItems: (legacyItems, devMode) ->
items = []
for label, commandOrSubmenu of legacyItems
if typeof commandOrSubmenu is 'object'
items.push({label, submenu: @convertLegacyItems(commandOrSubmenu, devMode), devMode})
else if commandOrSubmenu is '-'
items.push({type: 'separator'})
else
items.push({label, command: commandOrSubmenu, devMode})
items
# Public: Request a context menu to be displayed.
#
# * `event` A DOM event.
showForEvent: (event) ->
@activeElement = event.target
menuTemplate = @combinedMenuTemplateForElement(event.target)
menuTemplate = @templateForEvent(event)
return unless menuTemplate?.length > 0
@executeBuildHandlers(event, menuTemplate)
remote.getCurrentWindow().emit('context-menu', menuTemplate)
undefined
return
clear: ->
@activeElement = null
@itemSets = []
@add 'atom-workspace': [{
label: 'Inspect Element'
command: 'application:inspect'
devMode: true
created: (event) ->
{pageX, pageY} = event
@commandDetail = {x: pageX, y: pageY}
}]
class ContextMenuItemSet
constructor: (@selector, @items) ->
@specificity = (SpecificityCache[@selector] ?= specificity(@selector))
+7 -4
Ver Arquivo
@@ -198,7 +198,7 @@ class Cursor extends Model
[before, after] = @editor.getTextInBufferRange(range)
return false if /\s/.test(before) or /\s/.test(after)
nonWordCharacters = atom.config.get('editor.nonWordCharacters').split('')
nonWordCharacters = atom.config.get(@getScopeDescriptor(), 'editor.nonWordCharacters').split('')
_.contains(nonWordCharacters, before) isnt _.contains(nonWordCharacters, after)
# Public: Returns whether this cursor is between a word's start and end.
@@ -214,11 +214,14 @@ class Cursor extends Model
else
@getBufferColumn()
# Public: Retrieves the grammar's token scopes for the line.
# Public: Retrieves the scope descriptor for the cursor's current position.
#
# Returns an {Array} of {String}s.
getScopeDescriptor: ->
@editor.scopeDescriptorForBufferPosition(@getBufferPosition())
getScopes: ->
@editor.scopesForBufferPosition(@getBufferPosition())
Grim.deprecate 'Use Cursor::getScopeDescriptor() instead'
@getScopeDescriptor()
# Public: Returns true if this cursor has no non-whitespace characters before
# its current position.
@@ -617,7 +620,7 @@ class Cursor extends Model
# Returns a {RegExp}.
wordRegExp: ({includeNonWordCharacters}={}) ->
includeNonWordCharacters ?= true
nonWordCharacters = atom.config.get('editor.nonWordCharacters')
nonWordCharacters = atom.config.get(@getScopeDescriptor(), 'editor.nonWordCharacters')
segments = ["^[\t ]*$"]
segments.push("[^\\s#{_.escapeRegExp(nonWordCharacters)}]+")
if includeNonWordCharacters
+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.
+49 -20
Ver Arquivo
@@ -3,7 +3,7 @@ EmitterMixin = require('emissary').Emitter
guid = require 'guid'
Serializable = require 'serializable'
{Model} = require 'theorist'
{Emitter} = require 'event-kit'
{CompositeDisposable, Emitter} = require 'event-kit'
{Point, Range} = require 'text-buffer'
TokenizedBuffer = require './tokenized-buffer'
RowMap = require './row-map'
@@ -45,7 +45,6 @@ class DisplayBuffer extends Model
@emitter = new Emitter
@softWrapped ?= atom.config.get('editor.softWrap') ? false
@tokenizedBuffer ?= new TokenizedBuffer({tabLength, buffer, @invisibles})
@buffer = @tokenizedBuffer.buffer
@charWidthsByScope = {}
@@ -53,19 +52,42 @@ class DisplayBuffer extends Model
@foldsByMarkerId = {}
@decorationsById = {}
@decorationsByMarkerId = {}
@updateAllScreenLines()
@createFoldForMarker(marker) for marker in @buffer.findMarkers(@getFoldMarkerAttributes())
@subscribe @tokenizedBuffer.observeGrammar @subscribeToScopedConfigSettings
@subscribe @tokenizedBuffer.onDidChange @handleTokenizedBufferChange
@subscribe @buffer.onDidUpdateMarkers @handleBufferMarkersUpdated
@subscribe @buffer.onDidCreateMarker @handleBufferMarkerCreated
@updateAllScreenLines()
@createFoldForMarker(marker) for marker in @buffer.findMarkers(@getFoldMarkerAttributes())
@subscribe atom.config.observe 'editor.preferredLineLength', callNow: false, =>
@updateWrappedScreenLines() if @isSoftWrapped() and atom.config.get('editor.softWrapAtPreferredLineLength')
subscribeToScopedConfigSettings: =>
@scopedConfigSubscriptions?.dispose()
@scopedConfigSubscriptions = subscriptions = new CompositeDisposable
@subscribe atom.config.observe 'editor.softWrapAtPreferredLineLength', callNow: false, =>
scopeDescriptor = @getRootScopeDescriptor()
oldConfigSettings = @configSettings
@configSettings =
scrollPastEnd: atom.config.get(scopeDescriptor, 'editor.scrollPastEnd')
softWrap: atom.config.get(scopeDescriptor, 'editor.softWrap')
softWrapAtPreferredLineLength: atom.config.get(scopeDescriptor, 'editor.softWrapAtPreferredLineLength')
preferredLineLength: atom.config.get(scopeDescriptor, 'editor.preferredLineLength')
subscriptions.add atom.config.onDidChange scopeDescriptor, 'editor.softWrap', ({newValue}) =>
@configSettings.softWrap = newValue
@updateWrappedScreenLines()
subscriptions.add atom.config.onDidChange scopeDescriptor, 'editor.softWrapAtPreferredLineLength', ({newValue}) =>
@configSettings.softWrapAtPreferredLineLength = newValue
@updateWrappedScreenLines() if @isSoftWrapped()
@updateAllScreenLines()
subscriptions.add atom.config.onDidChange scopeDescriptor, 'editor.preferredLineLength', ({newValue}) =>
@configSettings.preferredLineLength = newValue
@updateWrappedScreenLines() if @isSoftWrapped() and atom.config.get(scopeDescriptor, 'editor.softWrapAtPreferredLineLength')
subscriptions.add atom.config.observe scopeDescriptor, 'editor.scrollPastEnd', (value) =>
@configSettings.scrollPastEnd = value
@updateWrappedScreenLines() if oldConfigSettings? and not _.isEqual(oldConfigSettings, @configSettings)
serializeParams: ->
id: @id
@@ -319,7 +341,7 @@ class DisplayBuffer extends Model
return 0 unless lineHeight > 0
scrollHeight = @getLineCount() * lineHeight
if @height? and atom.config.get('editor.scrollPastEnd')
if @height? and @configSettings.scrollPastEnd
scrollHeight = scrollHeight + @height - (lineHeight * 3)
scrollHeight
@@ -412,11 +434,15 @@ class DisplayBuffer extends Model
if softWrapped isnt @softWrapped
@softWrapped = softWrapped
@updateWrappedScreenLines()
@emit 'soft-wrap-changed', @softWrapped
@emitter.emit 'did-change-soft-wrapped', @softWrapped
@softWrapped
softWrapped = @isSoftWrapped()
@emit 'soft-wrap-changed', softWrapped
@emitter.emit 'did-change-soft-wrapped', softWrapped
softWrapped
else
@isSoftWrapped()
isSoftWrapped: -> @softWrapped
isSoftWrapped: ->
@softWrapped ? @configSettings.softWrap ? false
# Set the number of characters that fit horizontally in the editor.
#
@@ -438,8 +464,8 @@ class DisplayBuffer extends Model
@editorWidthInChars
getSoftWrapColumn: ->
if atom.config.get('editor.softWrapAtPreferredLineLength')
Math.min(@getEditorWidthInChars(), atom.config.getPositiveInt('editor.preferredLineLength', @getEditorWidthInChars()))
if @configSettings.softWrapAtPreferredLineLength
Math.min(@getEditorWidthInChars(), @configSettings.preferredLineLength)
else
@getEditorWidthInChars()
@@ -624,7 +650,7 @@ class DisplayBuffer extends Model
left = 0
column = 0
for token in @tokenizedLineForScreenRow(targetRow).tokens
charWidths = @getScopedCharWidths(token.scopes)
charWidths = @getScopedCharWidths(token.scopeDescriptor)
for char in token.value
return {top, left} if column is targetColumn
left += charWidths[char] ? defaultCharWidth unless char is '\0'
@@ -642,7 +668,7 @@ class DisplayBuffer extends Model
left = 0
column = 0
for token in @tokenizedLineForScreenRow(row).tokens
charWidths = @getScopedCharWidths(token.scopes)
charWidths = @getScopedCharWidths(token.scopeDescriptor)
for char in token.value
charWidth = charWidths[char] ? defaultCharWidth
break if targetLeft <= left + (charWidth / 2)
@@ -726,13 +752,13 @@ class DisplayBuffer extends Model
[bufferRow] = @rowMap.bufferRowRangeForScreenRow(row)
new Point(bufferRow, @screenLines[row].bufferColumnForScreenColumn(column))
# Retrieves the grammar's token scopes for a buffer position.
# Retrieves the grammar's token scopeDescriptor for a buffer position.
#
# bufferPosition - A {Point} in the {TextBuffer}
#
# Returns an {Array} of {String}s.
scopesForBufferPosition: (bufferPosition) ->
@tokenizedBuffer.scopesForPosition(bufferPosition)
scopeDescriptorForBufferPosition: (bufferPosition) ->
@tokenizedBuffer.scopeDescriptorForPosition(bufferPosition)
bufferRangeForScopeAtPosition: (selector, position) ->
@tokenizedBuffer.bufferRangeForScopeAtPosition(selector, position)
@@ -1034,6 +1060,9 @@ class DisplayBuffer extends Model
line = @tokenizedLineForScreenRow(row).text
console.log row, @bufferRowForScreenRow(row), line, line.length
getRootScopeDescriptor: ->
@tokenizedBuffer.rootScopeDescriptor
handleTokenizedBufferChange: (tokenizedBufferChange) =>
{start, end, delta, bufferChange} = tokenizedBufferChange
@updateScreenLines(start, end + 1, delta, delayChangeEvent: bufferChange?)
+20 -20
Ver Arquivo
@@ -29,12 +29,12 @@ class LanguageMode
#
# Returns an {Array} of the commented {Ranges}.
toggleLineCommentsForBufferRows: (start, end) ->
scopes = @editor.scopesForBufferPosition([start, 0])
properties = atom.syntax.propertiesForScope(scopes, "editor.commentStart")[0]
scopeDescriptor = @editor.scopeDescriptorForBufferPosition([start, 0])
properties = atom.config.settingsForScopeDescriptor(scopeDescriptor, 'editor.commentStart')[0]
return unless properties
commentStartString = _.valueForKeyPath(properties, "editor.commentStart")
commentEndString = _.valueForKeyPath(properties, "editor.commentEnd")
commentStartString = _.valueForKeyPath(properties, 'editor.commentStart')
commentEndString = _.valueForKeyPath(properties, 'editor.commentEnd')
return unless commentStartString
@@ -168,12 +168,12 @@ class LanguageMode
return null unless @isFoldableAtBufferRow(bufferRow)
startIndentLevel = @editor.indentationForBufferRow(bufferRow)
scopes = @editor.scopesForBufferPosition([bufferRow, 0])
scopeDescriptor = @editor.scopeDescriptorForBufferPosition([bufferRow, 0])
for row in [(bufferRow + 1)..@editor.getLastBufferRow()]
continue if @editor.isBufferRowBlank(row)
indentation = @editor.indentationForBufferRow(row)
if indentation <= startIndentLevel
includeRowInFold = indentation == startIndentLevel and @foldEndRegexForScopes(scopes)?.searchSync(@editor.lineTextForBufferRow(row))
includeRowInFold = indentation == startIndentLevel and @foldEndRegexForScopeDescriptor(scopeDescriptor)?.searchSync(@editor.lineTextForBufferRow(row))
foldEndRow = row if includeRowInFold
break
@@ -246,8 +246,8 @@ class LanguageMode
# Returns a {Number}.
suggestedIndentForBufferRow: (bufferRow) ->
currentIndentLevel = @editor.indentationForBufferRow(bufferRow)
scopes = @editor.scopesForBufferPosition([bufferRow, 0])
return currentIndentLevel unless increaseIndentRegex = @increaseIndentRegexForScopes(scopes)
scopeDescriptor = @editor.scopeDescriptorForBufferPosition([bufferRow, 0])
return currentIndentLevel unless increaseIndentRegex = @increaseIndentRegexForScopeDescriptor(scopeDescriptor)
currentLine = @buffer.lineForRow(bufferRow)
precedingRow = if bufferRow > 0 then bufferRow - 1 else null
@@ -257,7 +257,7 @@ class LanguageMode
desiredIndentLevel = @editor.indentationForBufferRow(precedingRow)
desiredIndentLevel += 1 if increaseIndentRegex.testSync(precedingLine) and not @editor.isBufferRowCommented(precedingRow)
return desiredIndentLevel unless decreaseIndentRegex = @decreaseIndentRegexForScopes(scopes)
return desiredIndentLevel unless decreaseIndentRegex = @decreaseIndentRegexForScopeDescriptor(scopeDescriptor)
desiredIndentLevel -= 1 if decreaseIndentRegex.testSync(currentLine)
Math.max(desiredIndentLevel, 0)
@@ -292,9 +292,9 @@ class LanguageMode
#
# bufferRow - The row {Number}
autoDecreaseIndentForBufferRow: (bufferRow) ->
scopes = @editor.scopesForBufferPosition([bufferRow, 0])
increaseIndentRegex = @increaseIndentRegexForScopes(scopes)
decreaseIndentRegex = @decreaseIndentRegexForScopes(scopes)
scopeDescriptor = @editor.scopeDescriptorForBufferPosition([bufferRow, 0])
increaseIndentRegex = @increaseIndentRegexForScopeDescriptor(scopeDescriptor)
decreaseIndentRegex = @decreaseIndentRegexForScopeDescriptor(scopeDescriptor)
return unless increaseIndentRegex and decreaseIndentRegex
line = @buffer.lineForRow(bufferRow)
@@ -311,15 +311,15 @@ class LanguageMode
if desiredIndentLevel >= 0 and desiredIndentLevel < currentIndentLevel
@editor.setIndentationForBufferRow(bufferRow, desiredIndentLevel)
getRegexForProperty: (scopes, property) ->
if pattern = atom.syntax.getProperty(scopes, property)
getRegexForProperty: (scopeDescriptor, property) ->
if pattern = atom.config.get(scopeDescriptor, property)
new OnigRegExp(pattern)
increaseIndentRegexForScopes: (scopes) ->
@getRegexForProperty(scopes, 'editor.increaseIndentPattern')
increaseIndentRegexForScopeDescriptor: (scopeDescriptor) ->
@getRegexForProperty(scopeDescriptor, 'editor.increaseIndentPattern')
decreaseIndentRegexForScopes: (scopes) ->
@getRegexForProperty(scopes, 'editor.decreaseIndentPattern')
decreaseIndentRegexForScopeDescriptor: (scopeDescriptor) ->
@getRegexForProperty(scopeDescriptor, 'editor.decreaseIndentPattern')
foldEndRegexForScopes: (scopes) ->
@getRegexForProperty(scopes, 'editor.foldEndPattern')
foldEndRegexForScopeDescriptor: (scopeDescriptor) ->
@getRegexForProperty(scopeDescriptor, 'editor.foldEndPattern')
+11 -11
Ver Arquivo
@@ -200,7 +200,7 @@ LinesComponent = React.createClass
firstTrailingWhitespacePosition = text.search(/\s*$/)
lineIsWhitespaceOnly = firstTrailingWhitespacePosition is 0
for token in tokens
innerHTML += @updateScopeStack(scopeStack, token.scopes)
innerHTML += @updateScopeStack(scopeStack, token.scopeDescriptor)
hasIndentGuide = not mini and showIndentGuide and (token.hasLeadingWhitespace() or (token.hasTrailingWhitespace() and lineIsWhitespaceOnly))
innerHTML += token.getValueAsHtml({hasIndentGuide})
@@ -217,20 +217,20 @@ LinesComponent = React.createClass
html += "<span class='invisible-character'>#{invisible}</span>"
html
updateScopeStack: (scopeStack, desiredScopes) ->
updateScopeStack: (scopeStack, desiredScopeDescriptor) ->
html = ""
# Find a common prefix
for scope, i in desiredScopes
break unless scopeStack[i] is desiredScopes[i]
for scope, i in desiredScopeDescriptor
break unless scopeStack[i] is desiredScopeDescriptor[i]
# Pop scopes until we're at the common prefx
# Pop scopeDescriptor until we're at the common prefx
until scopeStack.length is i
html += @popScope(scopeStack)
# Push onto common prefix until scopeStack equals desiredScopes
for j in [i...desiredScopes.length]
html += @pushScope(scopeStack, desiredScopes[j])
# Push onto common prefix until scopeStack equals desiredScopeDescriptor
for j in [i...desiredScopeDescriptor.length]
html += @pushScope(scopeStack, desiredScopeDescriptor[j])
html
@@ -308,8 +308,8 @@ LinesComponent = React.createClass
iterator = null
charIndex = 0
for {value, scopes}, tokenIndex in tokenizedLine.tokens
charWidths = editor.getScopedCharWidths(scopes)
for {value, scopeDescriptor}, tokenIndex in tokenizedLine.tokens
charWidths = editor.getScopedCharWidths(scopeDescriptor)
for char in value
continue if char is '\0'
@@ -331,7 +331,7 @@ LinesComponent = React.createClass
rangeForMeasurement.setStart(textNode, i)
rangeForMeasurement.setEnd(textNode, i + 1)
charWidth = rangeForMeasurement.getBoundingClientRect().width
editor.setScopedCharWidth(scopes, char, charWidth)
editor.setScopedCharWidth(scopeDescriptor, char, charWidth)
charIndex++
+3 -3
Ver Arquivo
@@ -160,7 +160,7 @@ class Marker
getProperties: ->
@bufferMarker.getProperties()
getAttributes: ->
deprecate 'Use Marker::getProperties instead'
Grim.deprecate 'Use Marker::getProperties instead'
@getProperties()
# Essential: Merges an {Object} containing new properties into the marker's
@@ -170,14 +170,14 @@ class Marker
setProperties: (properties) ->
@bufferMarker.setProperties(properties)
setAttributes: (properties) ->
deprecate 'Use Marker::getProperties instead'
Grim.deprecate 'Use Marker::getProperties instead'
@setProperties(properties)
matchesProperties: (attributes) ->
attributes = @displayBuffer.translateToBufferMarkerParams(attributes)
@bufferMarker.matchesParams(attributes)
matchesAttributes: (attributes) ->
deprecate 'Use Marker::matchesProperties instead'
Grim.deprecate 'Use Marker::matchesProperties instead'
@matchesProperties(attributes)
###
+52
Ver Arquivo
@@ -0,0 +1,52 @@
_ = require 'underscore-plus'
ItemSpecificities = new WeakMap
merge = (menu, item, itemSpecificity=Infinity) ->
item = cloneMenuItem(item)
ItemSpecificities.set(item, itemSpecificity) if itemSpecificity
matchingItemIndex = findMatchingItemIndex(menu, item)
matchingItem = menu[matchingItemIndex] unless matchingItemIndex is - 1
if matchingItem?
if item.submenu?
merge(matchingItem.submenu, submenuItem, itemSpecificity) for submenuItem in item.submenu
else if itemSpecificity
unless itemSpecificity < ItemSpecificities.get(matchingItem)
menu[matchingItemIndex] = item
else unless item.type is 'separator' and _.last(menu)?.type is 'separator'
menu.push(item)
unmerge = (menu, item) ->
matchingItemIndex = findMatchingItemIndex(menu, item)
matchingItem = menu[matchingItemIndex] unless matchingItemIndex is - 1
if matchingItem?
if item.submenu?
unmerge(matchingItem.submenu, submenuItem) for submenuItem in item.submenu
unless matchingItem.submenu?.length > 0
menu.splice(matchingItemIndex, 1)
findMatchingItemIndex = (menu, {type, label, submenu}) ->
return -1 if type is 'separator'
for item, index in menu
if normalizeLabel(item.label) is normalizeLabel(label) and item.submenu? is submenu?
return index
-1
normalizeLabel = (label) ->
return undefined unless label?
if process.platform is 'darwin'
label
else
label.replace(/\&/g, '')
cloneMenuItem = (item) ->
item = _.pick(item, 'type', 'label', 'command', 'submenu', 'commandDetail')
if item.submenu?
item.submenu = item.submenu.map (submenuItem) -> cloneMenuItem(submenuItem)
item
module.exports = {merge, unmerge, normalizeLabel, cloneMenuItem}
+21 -20
Ver Arquivo
@@ -4,6 +4,9 @@ _ = require 'underscore-plus'
ipc = require 'ipc'
CSON = require 'season'
fs = require 'fs-plus'
{Disposable} = require 'event-kit'
MenuHelpers = require './menu-helpers'
# Extended: Provides a registry for menu items that you'd like to appear in the
# application menu.
@@ -34,10 +37,18 @@ 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) ->
items = _.deepClone(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.
@@ -52,14 +63,14 @@ class MenuManager
# Selector isn't valid
return false
# Simulate an .editor element attached to a .workspace element attached to
# a body element that has the same classes as the current body element.
# Simulate an atom-text-editor element attached to a atom-workspace element attached
# to a body element that has the same classes as the current body element.
unless @testEditor?
testBody = document.createElement('body')
testBody.classList.add(@classesForElement(document.body)...)
testWorkspace = document.createElement('div')
workspaceClasses = @classesForElement(document.body.querySelector('.workspace'))
workspaceClasses = @classesForElement(document.body.querySelector('atom-workspace'))
workspaceClasses = ['workspace'] if workspaceClasses.length is 0
testWorkspace.classList.add(workspaceClasses...)
@@ -95,12 +106,10 @@ class MenuManager
# Merges an item in a submenu aware way such that new items are always
# appended to the bottom of existing menus where possible.
merge: (menu, item) ->
item = _.deepClone(item)
MenuHelpers.merge(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
else
menu.push(item) unless _.find(menu, ({label}) => label and @normalizeLabel(label) is @normalizeLabel(item.label))
unmerge: (menu, item) ->
MenuHelpers.unmerge(menu, item)
# OSX can't handle displaying accelerators for multiple keystrokes.
# If they are sent across, it will stop processing accelerators for the rest
@@ -119,25 +128,17 @@ class MenuManager
keystrokesByCommand = @filterMultipleKeystroke(keystrokesByCommand)
ipc.send 'update-application-menu', template, keystrokesByCommand
normalizeLabel: (label) ->
return undefined unless label?
if process.platform is 'darwin'
label
else
label.replace(/\&/g, '')
# Get an {Array} of {String} classes for the given element.
classesForElement: (element) ->
element?.classList.toString().split(' ') ? []
sortPackagesMenu: ->
packagesMenu = @template.find ({label}) => @normalizeLabel(label) is 'Packages'
packagesMenu = @template.find ({label}) -> MenuHelpers.normalizeLabel(label) is 'Packages'
return unless packagesMenu?.submenu?
packagesMenu.submenu.sort (item1, item2) =>
packagesMenu.submenu.sort (item1, item2) ->
if item1.label and item2.label
@normalizeLabel(item1.label).localeCompare(@normalizeLabel(item2.label))
MenuHelpers.normalizeLabel(item1.label).localeCompare(MenuHelpers.normalizeLabel(item2.label))
else
0
@update()
+4 -4
Ver Arquivo
@@ -256,13 +256,13 @@ class PackageManager
metadata?.engines?.atom?
unobserveDisabledPackages: ->
@disabledPackagesSubscription?.off()
@disabledPackagesSubscription?.dispose()
@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
+29 -21
Ver Arquivo
@@ -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
@@ -156,9 +162,10 @@ class Package
@stylesheetsActivated = true
activateResources: ->
atom.keymaps.add(keymapPath, map) for [keymapPath, map] in @keymaps
atom.contextMenu.add(menuPath, map['context-menu']) for [menuPath, map] in @menus
atom.menu.add(map.menu) for [menuPath, map] in @menus when map.menu
@activationDisposables = new CompositeDisposable
@activationDisposables.add(atom.keymaps.add(keymapPath, map)) for [keymapPath, map] in @keymaps
@activationDisposables.add(atom.contextMenu.add(map['context-menu'])) for [menuPath, map] in @menus
@activationDisposables.add(atom.menu.add(map.menu)) for [menuPath, map] in @menus when map.menu
unless @grammarsActivated
grammar.activate() for grammar in @grammars
@@ -288,8 +295,8 @@ class Package
deactivateResources: ->
grammar.deactivate() for grammar in @grammars
scopedProperties.deactivate() for scopedProperties in @scopedProperties
atom.keymaps.remove(keymapPath) for [keymapPath] in @keymaps
atom.themes.removeStylesheet(stylesheetPath) for [stylesheetPath] in @stylesheets
@activationDisposables?.dispose()
@stylesheetsActivated = false
@grammarsActivated = false
@scopedPropertiesActivated = false
@@ -328,9 +335,18 @@ class Package
@activationCommandSubscriptions = new CompositeDisposable
for selector, commands of @getActivationCommands()
for command in commands
@activationCommandSubscriptions.add(
atom.commands.add(selector, command, @handleActivationCommand)
)
do (selector, command) =>
atom.commands.commandRegistered(command)
@activationCommandSubscriptions.add(atom.commands.onWillDispatch (event) =>
return unless event.type is command
currentTarget = event.target
while currentTarget
if currentTarget.webkitMatchesSelector(selector)
@activationCommandSubscriptions.dispose()
@activateNow()
break
currentTarget = currentTarget.parentElement
)
getActivationCommands: ->
return @activationCommands if @activationCommands?
@@ -348,28 +364,20 @@ class Package
if @metadata.activationEvents?
if _.isArray(@metadata.activationEvents)
for eventName in @metadata.activationEvents
@activationCommands['.workspace'] ?= []
@activationCommands['.workspace'].push(eventName)
@activationCommands['atom-workspace'] ?= []
@activationCommands['atom-workspace'].push(eventName)
else if _.isString(@metadata.activationEvents)
eventName = @metadata.activationEvents
@activationCommands['.workspace'] ?= []
@activationCommands['.workspace'].push(eventName)
@activationCommands['atom-workspace'] ?= []
@activationCommands['atom-workspace'].push(eventName)
else
for eventName, selector of @metadata.activationEvents
selector ?= '.workspace'
selector ?= 'atom-workspace'
@activationCommands[selector] ?= []
@activationCommands[selector].push(eventName)
@activationCommands
handleActivationCommand: (event) =>
event.stopImmediatePropagation()
@activationCommandSubscriptions.dispose()
reenableInvokedListeners = event.disableInvokedListeners()
@activateNow()
event.target.dispatchEvent(new CustomEvent(event.type, bubbles: true))
reenableInvokedListeners()
# Does the given module path contain native code?
isNativeModule: (modulePath) ->
try
+42
Ver Arquivo
@@ -0,0 +1,42 @@
{CompositeDisposable} = require 'event-kit'
{callAttachHooks} = require './space-pen-extensions'
class PaneAxisElement extends HTMLElement
createdCallback: ->
@subscriptions = new CompositeDisposable
detachedCallback: ->
@subscriptions.dispose()
setModel: (@model) ->
@subscriptions.add @model.onDidAddChild(@childAdded.bind(this))
@subscriptions.add @model.onDidRemoveChild(@childRemoved.bind(this))
@subscriptions.add @model.onDidReplaceChild(@childReplaced.bind(this))
@childAdded({child, index}) for child, index in @model.getChildren()
switch @model.getOrientation()
when 'horizontal'
@classList.add('horizontal', 'pane-row')
when 'vertical'
@classList.add('vertical', 'pane-column')
childAdded: ({child, index}) ->
view = @model.getView(child)
@insertBefore(view, @children[index])
callAttachHooks(view) # for backward compatibility with SpacePen views
childRemoved: ({child}) ->
view = @model.getView(child)
view.remove()
childReplaced: ({index, oldChild, newChild}) ->
focusedElement = document.activeElement if @hasFocus()
@childRemoved({child: oldChild, index})
@childAdded({child: newChild, index})
focusedElement?.focus() if document.activeElement is document.body
hasFocus: ->
this is document.activeElement or @contains(document.activeElement)
module.exports = PaneAxisElement = document.registerElement 'atom-pane-axis', prototype: PaneAxisElement.prototype
-37
Ver Arquivo
@@ -1,37 +0,0 @@
{CompositeDisposable} = require 'event-kit'
{View} = require './space-pen-extensions'
PaneView = null
module.exports =
class PaneAxisView extends View
initialize: (@model) ->
@subscriptions = new CompositeDisposable
@onChildAdded({child, index}) for child, index in @model.getChildren()
@subscriptions.add @model.onDidAddChild(@onChildAdded)
@subscriptions.add @model.onDidRemoveChild(@onChildRemoved)
@subscriptions.add @model.onDidReplaceChild(@onChildReplaced)
afterAttach: ->
@container = @closest('.panes').view()
onChildReplaced: ({index, oldChild, newChild}) =>
focusedElement = document.activeElement if @hasFocus()
@onChildRemoved({child: oldChild, index})
@onChildAdded({child: newChild, index})
focusedElement?.focus() if document.activeElement is document.body
onChildAdded: ({child, index}) =>
view = @model.getView(child).__spacePenView
@insertAt(index, view)
onChildRemoved: ({child}) =>
view = @model.getView(child).__spacePenView
view.detach()
PaneView ?= require './pane-view'
if view instanceof PaneView and view.model.isDestroyed()
@container?.trigger 'pane:removed', [view]
beforeRemove: ->
@subscriptions.dispose()
+1 -8
Ver Arquivo
@@ -3,9 +3,6 @@
{flatten} = require 'underscore-plus'
Serializable = require 'serializable'
PaneRowView = null
PaneColumnView = null
module.exports =
class PaneAxis extends Model
atom.deserializers.add(this)
@@ -40,11 +37,7 @@ class PaneAxis extends Model
setContainer: (@container) -> @container
getViewClass: ->
if @orientation is 'vertical'
PaneColumnView ?= require './pane-column-view'
else
PaneRowView ?= require './pane-row-view'
getOrientation: -> @orientation
getView: (object) ->
@container.getView(object)
-12
Ver Arquivo
@@ -1,12 +0,0 @@
{$} = require './space-pen-extensions'
_ = require 'underscore-plus'
PaneAxisView = require './pane-axis-view'
module.exports =
class PaneColumnView extends PaneAxisView
@content: ->
@div class: 'pane-column'
className: ->
"PaneColumn"

Alguns arquivos não foram exibidos porque demasiados arquivos foram alterados neste diff Mostrar Mais