Comparar commits

...

293 Commits

Autor SHA1 Mensagem Data
Kevin Sawicki f6bb7fc089 Merge pull request #3458 from atom/ks-store-injection-grammars
Include injection grammars in active list
2014-09-05 09:14:41 -07:00
Ben Ogle 805c621ac6 Merge pull request #3459 from atom/bo-remove-editor-view-split-methods
Deprecate EditorView::split* methods
2014-09-04 17:44:22 -07:00
Ben Ogle 7fe567521e Use the model methods in the commands 2014-09-04 17:09:52 -07:00
Ben Ogle e48748122f Suggest better alternative in deprecation warnings 2014-09-04 16:49:33 -07:00
Ben Ogle 1291cf19fb Rename EditorView::getPane -> ::getPaneView() 2014-09-04 16:49:02 -07:00
Ben Ogle 336afc32c2 Add PaneView::getModel() 2014-09-04 16:48:04 -07:00
Ben Ogle a81393320c Support a copyActiveItem param in Pane::split* methods 2014-09-04 16:41:20 -07:00
Kevin Sawicki 3e407296ad 🐎 Upgrade to less-cache@0.14 2014-09-04 16:31:21 -07:00
Kevin Sawicki 7c8451e178 Use getter on GrammarRegistry 2014-09-04 16:09:46 -07:00
Kevin Sawicki 90592a70be Include injection grammars in active list
Prevents an immediate flicker when restarting Atom with editors
open that have injection matches.
2014-09-04 16:04:32 -07:00
Ben Ogle 914e4e6342 Deprecate EditorView::split* methods 2014-09-04 16:00:34 -07:00
Ben Ogle 86e623e9db Merge pull request #3457 from atom/bo-deprecate-editor-view-methods
Deprecate obvious EditorView methods
2014-09-04 15:42:28 -07:00
Ben Ogle 70df5a5c0a Remove unnecessary fixme 2014-09-04 15:30:06 -07:00
Ben Ogle dba1e22ded Deprecate EditorView::setSoftWrap 2014-09-04 15:29:54 -07:00
Ben Ogle dc21e8707f Deprecate EditorView::getFirstVisibleScreenRow 2014-09-04 15:25:55 -07:00
Ben Ogle 52c19a5dcd Deprecate pixelPositionFor*Position 2014-09-04 15:20:20 -07:00
Ben Ogle 5ae040f688 Add Editor::scrollToTop to compliment scrollToBottom() 2014-09-04 15:17:17 -07:00
Ben Ogle c511a71488 Deprecate EditorView::scrollToBottom 2014-09-04 15:17:01 -07:00
Ben Ogle 04b0ed9704 Deprecate EditorView::scrollTo*Position() functions 2014-09-04 15:14:38 -07:00
Ben Ogle 2c9241506b Fix doc strings 2014-09-04 14:53:33 -07:00
Kevin Sawicki 326f5fc646 Upgrade to settings-view@0.142 2014-09-04 14:29:15 -07:00
Nathan Sobo 705c57158d Merge pull request #3454 from atom/ns-text-buffer-event-methods
Add event subscription methods to TextBuffer and Marker
2014-09-04 15:17:55 -06:00
Nathan Sobo a50f62dc93 Merge remote-tracking branch 'origin/master' into ns-text-buffer-event-methods
Conflicts:
	package.json
2014-09-04 14:40:52 -06:00
Kevin Sawicki eb9d4ba816 📝 Use ### for example sections 2014-09-04 13:40:04 -07:00
Nathan Sobo 6cb085b341 Upgrade text-buffer again to fix specs 2014-09-04 14:15:42 -06:00
Ivan Žužak 1ffe459b1e Merge pull request #3455 from atom/iz-remove-deprecated-calls-check
Remove check for deprecated function calls
2014-09-04 22:02:51 +02:00
Nathan Sobo effe7e8070 Upgrade find-and-replace for spec fixes 2014-09-04 14:00:14 -06:00
Ivan Žužak b5676adf8a Remove check for deprecated function calls 2014-09-04 21:52:00 +02:00
Ivan Žužak 1909f24d5c Merge pull request #3433 from atom/iz-gutter-click-select-line
Support selecting rows by clicking and meta-clicking the gutter
2014-09-04 21:35:31 +02:00
Nathan Sobo a947a357f4 Upgrade text-buffer for event subscription methods 2014-09-04 12:44:53 -06:00
Kevin Sawicki d8be03850b Merge pull request #3443 from atom/ks-upgrade-fuzzaldrin
Upgrade fuzzaldrin
2014-09-04 09:20:39 -07:00
Kevin Sawicki 641698330f Upgrade to fuzzy-finder@0.58 2014-09-04 09:02:38 -07:00
Kevin Sawicki 55913626cc Upgrade to fuzzaldrin 2.1 2014-09-04 09:02:38 -07:00
Ivan Zuzak af2f155082 Merge branch 'master' into iz-gutter-click-select-line 2014-09-04 16:22:51 +02:00
Nathan Sobo b9e90f2fdd Fix editor observation docs 2014-09-04 08:06:19 -06:00
Nathan Sobo 621c247a75 Merge pull request #3418 from atom/ns-simplify-events
Clean Up Workspace Event Subscription API
2014-09-04 07:47:55 -06:00
Nathan Sobo 2f6f374cc7 Upgrade event-kit to stop throwing when emitting on disposed emitters 2014-09-04 07:02:35 -06:00
Nathan Sobo aac64e3a9b Document Workspace::onDidOpen 2014-09-04 07:01:32 -06:00
Nathan Sobo 9de0ba17b2 Add Workspace::onDidOpen event subscription method 2014-09-04 06:57:59 -06:00
Nathan Sobo 57699e6245 Use Workspace::getActivePane instead of property in spec 2014-09-04 06:57:46 -06:00
Ivan Zuzak 8a6e72f21f Respect preserveFolds attribute when creating selections from markers 2014-09-04 13:57:41 +02:00
Nathan Sobo 0f912c97b9 Upgrade emissary to call prefer calling ::dispose in Subscriber mixin 2014-09-03 19:37:42 -06:00
Nathan Sobo 4946eec367 Merge remote-tracking branch 'origin/master' into ns-simplify-events
Conflicts:
	docs/your-first-package.md
2014-09-03 19:31:37 -06:00
Nathan Sobo db571a2fbf Avoid deprecation by calling ::getActivePaneItem 2014-09-03 19:26:19 -06:00
Nathan Sobo 22c62b3107 Replace ‘editor-created’ event with ::onDidAddTextEditor 2014-09-03 19:26:07 -06:00
Nathan Sobo 83327eeabb Don’t test for editor-created events when editor is copied
We can handle this through ::onDidAddTextEditor when the copy is added
back to the pane.
2014-09-03 19:25:40 -06:00
Ben Ogle 8e286194f1 Merge pull request #3446 from atom/bo-move-var
Add columnCount variables to cursor::moveLeft and moveRight and related methods
2014-09-03 17:36:31 -07:00
Ben Ogle 691c7ee585 Considerably more elegant (and correct) moveLeft and moveRight 2014-09-03 17:19:06 -07:00
Ben Ogle 48b693c1c1 Add columnCounts to selection methods 2014-09-03 16:20:25 -07:00
Ben Ogle 7a3893c7bb Update doc strings 2014-09-03 16:10:33 -07:00
Ben Ogle 06165b2167 Remove the max call 2014-09-03 16:10:33 -07:00
Ben Ogle f82c59d865 Add columnCount to moveRight 2014-09-03 16:10:33 -07:00
Ben Ogle 29f15d0f20 Make moveLeft() with huge values span multiple rows 2014-09-03 16:10:33 -07:00
Ben Ogle 99c07decf2 Add columnCount var to Editor::moveLeft and Cursor::moveLeft 2014-09-03 16:10:33 -07:00
Ben Ogle 851034c8d3 Failing test 2014-09-03 16:10:33 -07:00
Ben Ogle 3a85148f69 Fix doc strings 2014-09-03 16:10:33 -07:00
Nathan Sobo f87f7c358a Kill a couple deprecation errors 2014-09-03 17:08:13 -06:00
Ben Ogle df579a9295 Merge pull request #3445 from atom/bo-line-for-row
lineForRow changes
2014-09-03 16:07:42 -07:00
Ben Ogle b90670ff2d Gracefully handle the case when there is no screenline 2014-09-03 16:00:57 -07:00
Nathan Sobo 67dc703c18 💄 docs 2014-09-03 16:46:53 -06:00
Nathan Sobo c508f76af0 Upgrade event-kit for deprecated .off on subscriptions 2014-09-03 16:40:18 -06:00
Nathan Sobo a8c1f2d0a5 Deprecate Workspace methods 2014-09-03 16:37:36 -06:00
Nathan Sobo 7ad992e52f 💄 2014-09-03 16:35:46 -06:00
Nathan Sobo 87fb0b46f7 Deprecate theorist-provided behaviors in Pane 2014-09-03 16:31:14 -06:00
Nathan Sobo 873818ee52 Deprecate string-based event subscriptions 2014-09-03 16:21:42 -06:00
Ben Ogle 523a255e48 Add Editor::lineTextForScreenRow()
Closes #3055
2014-09-03 14:42:46 -07:00
Ben Ogle 5e21d1ca5b Deprecate Editor::lineLengthForBufferRow 2014-09-03 14:42:46 -07:00
Ben Ogle 0703788209 Editor::linesForScreenRows -> ::tokenizedLinesForScreenRows 2014-09-03 14:42:46 -07:00
Ben Ogle c0c941b8db lineForBufferRow -> lineTextForBufferRow 2014-09-03 14:42:46 -07:00
Ben Ogle e3a0339fe3 Editor::lineForScreenRow -> ::tokenizedLineForScreenRow 2014-09-03 14:42:46 -07:00
Ben Ogle c4265776b3 Rename unused method 2014-09-03 14:42:46 -07:00
Ben Ogle ae49fd50b7 DisplayBuffer::linesForRows -> ::tokenizedLinesForScreenRows
Clarity!
2014-09-03 14:42:46 -07:00
Ben Ogle cdbbec91f0 row -> bufferRow for clarity 2014-09-03 14:42:45 -07:00
Ben Ogle dbb0ff9830 Remove unused method 2014-09-03 14:42:45 -07:00
Ben Ogle 99f899dc4a lineForScreenRow -> tokenizedLineForRow
The method was severely mislabeled
2014-09-03 14:42:45 -07:00
Ben Ogle 2b9b4a48ef tokenizedLineForRow -> tokenizedLineForScreenRow 2014-09-03 14:42:45 -07:00
Ben Ogle b516f5a74d lineForBufferRow -> lineTextForBufferRow 2014-09-03 14:42:45 -07:00
Ben Ogle 05bbc480b0 displayBuffer::lineForRow -> tokenizedLineForRow 2014-09-03 14:42:45 -07:00
Ben Ogle c0e2ed4282 Fix comments 2014-09-03 12:04:21 -07:00
Ben Ogle d3c2cd756a Fix comment 2014-09-03 12:01:36 -07:00
Kevin Sawicki 1ff9da5f7a Upgrade to markdown-preview@0.101 2014-09-03 11:31:41 -07:00
Nathan Sobo d3422786c3 Unmount component when EditorView is detached
Fixes #3431

When a pane item is moved to another pane, we *detach* the associated
view but we don’t fully remove it. This was to prevent removing a view
when it was used as the pane item directly. However, this was causing
the editor component not to be unmounted, which caused leaks and
incorrect measurements.

We need to unmount the component, but we don’t want to destroy the
editor. So I’ve moved editor destruction to the wrapper view for now,
and I only do it when the view is actually removed.

Ultimately, we need to have a 1:1 relationship with pane items and their
views and only allow a pane item to appear once in the pane tree. Then
we can recycle the same view and avoid this confusing situation where
the old view is detached and a new view is created.
2014-09-03 11:42:56 -06:00
Ivan Zuzak ebbfaa23ce Preserve folds when selecting rows by clicking the gutter 2014-09-03 18:54:46 +02:00
Ivan Zuzak 29ad748aa4 Dont propagate fold icon clicks to editor component 2014-09-03 18:52:50 +02:00
Nathan Sobo d753a7f38d Merge pull request #3440 from atom/ns-exclusive-selection-intersection
Don’t merge adjacent non-empty selections
2014-09-03 09:24:05 -06:00
Ben Ogle 1e4fb5b4bc nof 2014-09-02 17:44:01 -07:00
Nathan Sobo cfd2722348 Don’t merge adjacent non-empty selections
This improves the behavior of #3433
2014-09-02 18:10:05 -06:00
Ben Ogle ae0bffc4ea Fix some doc strings 2014-09-02 17:01:20 -07:00
Ben Ogle 3d8f3883d1 Upgrade deprecation cop to remove the status bar icon. 2014-09-02 16:52:22 -07:00
Ben Ogle 81532d52f7 Move select all fn so docs read better 2014-09-02 16:45:49 -07:00
Ben Ogle 0b34e46a1a Merge pull request #3420 from atom/bo-update-cursor-selection-apis
Update cursor and selection APIs
2014-09-02 16:41:42 -07:00
Ben Ogle 539e4e0745 Upgrade fnr to fix specs 2014-09-02 15:10:38 -07:00
Ben Ogle 1f925078e9 Remove deprecation 2014-09-02 14:59:06 -07:00
Ben Ogle a564da1eb0 Remove unnecessary deprecated methods 2014-09-02 14:58:20 -07:00
Ben Ogle dca36d1307 Reorder return values of getSelectedBufferRanges
The implementation does not depend on a specific order, just the test
2014-09-02 14:55:02 -07:00
Ben Ogle 3f67252757 Add row count docs 2014-09-02 14:50:15 -07:00
Ben Ogle a7db555030 Order the getting ranges / positions by their insertion order 2014-09-02 14:38:11 -07:00
Kevin Sawicki 3bd7edb94e Upgrade to language-sass@0.21 2014-09-02 14:25:40 -07:00
Kevin Sawicki a9227b5f43 Upgrade to language-less@0.15 2014-09-02 14:22:51 -07:00
Ben Ogle 659c05c825 Add selectToBufferPosition 2014-09-02 14:09:56 -07:00
Ben Ogle 5ea64f8b11 selectWord() -> selectWordsContainingCursors() 2014-09-02 14:03:57 -07:00
Ben Ogle 70af6198bd selectLine -> selectLinesContainingCursors 2014-09-02 14:02:26 -07:00
Kevin Sawicki 1aa391a207 Don't load ~/.atom/init.coffee in safe mode
This ensures the code from the init script isn't causing issues
when trying to reproduce something in safe mode.

Refs #2772
2014-09-02 13:51:26 -07:00
Kevin Sawicki 03a6d10703 Upgrade to tree-view@0.114 2014-09-02 13:44:13 -07:00
Kevin Sawicki 24add494ae Normalize project path in Project::setPath
This will remove consecutive slashes as well as . and ..
characters and make path comparisons accurate.

Closes atom/tree-view#191
2014-09-02 10:49:02 -07:00
Nathan Sobo c5aa446bc2 Prevent focusout events on hidden input when clicking focused editors
Fixes #3384

This is achieved by calling .preventDefault() on mousedown events when
the editor is already focused, which prevents the moving of focus to
the editor itself.
2014-09-02 11:37:46 -06:00
Kevin Sawicki fbcef99aac Upgrade to language-todo@0.11 2014-09-02 09:04:49 -07:00
Kevin Sawicki 8fa8519924 Upgrade to language-python@0.19 2014-09-02 08:56:04 -07:00
Kevin Sawicki 5a36988930 Upgrade to language-xml@0.19 2014-09-02 08:49:06 -07:00
Ivan Zuzak 65cae0f68d Fix indentation to make coffeelint happy 2014-09-01 18:24:04 +02:00
Ivan Zuzak 7f14965ca8 Support selecting multiple rows with meta-click 2014-09-01 17:42:55 +02:00
Ivan Zuzak 8c36d2673b Select row when clicking the gutter 2014-08-30 20:20:09 +02:00
Kevin Sawicki 7f2d9984b8 Upgrade to language-go@0.17 2014-08-29 11:30:06 -07:00
Kevin Sawicki d43702f017 🐎 Use direct comparison instead of regex 2014-08-29 09:55:50 -07:00
Kevin Sawicki 690d32cca9 Document undefined case 2014-08-29 09:42:51 -07:00
Kevin Sawicki d870cb8f36 Return undefined to ? fallback works 2014-08-29 09:42:01 -07:00
Kevin Sawicki 7cd080786c Return a boolean like the comment says 2014-08-29 09:40:55 -07:00
Kevin Sawicki a8a251c457 💄 2014-08-29 09:36:55 -07:00
Kevin Sawicki 9574458feb 📝 💄 2014-08-29 09:34:59 -07:00
Kevin Sawicki 692bf534b6 Merge pull request #3369 from khakionion/master
Better autodetection of Soft Tabs.
2014-08-29 09:34:01 -07:00
Kevin Sawicki f35346c507 Upgrade to tree-view@0.113 2014-08-29 09:15:34 -07:00
Kevin Sawicki 78f7ff6ee7 Focus existing window after opening path 2014-08-29 09:10:12 -07:00
Kevin Sawicki 71470f88ad Merge pull request #3409 from syndbg/master
Added linux open-folder keybind.
2014-08-29 08:32:07 -07:00
Ben Ogle 4b4af946cf Fix specs 2014-08-28 18:30:08 -07:00
Ben Ogle 5163d0f810 Fix dupe functions 2014-08-28 18:19:12 -07:00
Ben Ogle 08388d87c0 Remove getSelectionAtIndex
We’re going to eventually get rid of the clone in 
getSelections / getCursors freeze those properties 
and return them directly. Then they can operate 
on the list garbage free.
2014-08-28 18:16:33 -07:00
Ben Ogle 9c53d6f014 Deprecate getCursor() 2014-08-28 18:10:18 -07:00
Nathan Sobo c9e5ff6606 Organize workspace API into sections. Add ::getActiveTextEditor 2014-08-28 19:06:57 -06:00
Ben Ogle 2fced0c1bc Deprecate getSelection 2014-08-28 17:51:16 -07:00
Ben Ogle 271af5dd99 Add Editor::setSelectedScreenRanges() 2014-08-28 17:28:24 -07:00
Nathan Sobo 6c2bb26e77 Add Workspace::observeTextEditors and ::onDidAddTextEditor 2014-08-28 18:28:10 -06:00
Nathan Sobo 70a23b0107 Add Workspace::getPanes and ::getPaneItems 2014-08-28 18:27:13 -06:00
Ben Ogle c6a76e6c62 De public a non-used method 2014-08-28 16:59:10 -07:00
Ben Ogle 535724fa84 Nothing uses this function, not internal nor packages. 2014-08-28 16:58:59 -07:00
Ben Ogle 14dcf50683 De-public a couple unused methods 2014-08-28 16:53:44 -07:00
Ben Ogle 882261e782 Break into Essential and extended 2014-08-28 16:53:21 -07:00
Nathan Sobo acb9bdaf33 Add pane and pane item observer methods to workspace. Also document. 2014-08-28 17:52:30 -06:00
Ben Ogle 713d82a895 Reorder selections section 2014-08-28 16:51:31 -07:00
Nathan Sobo a33706ddbc Add PaneContainer::onDidAddPaneItem and ::observePaneItems 2014-08-28 17:42:12 -06:00
Ben Ogle 2551313b58 Deprecate methods on cursor 2014-08-28 16:31:10 -07:00
Nathan Sobo 877fa40a49 Activate next pane on before invoking onDidDestroy observers 2014-08-28 17:23:49 -06:00
Nathan Sobo cee7539e35 Add PaneContainer::observePanes and ::onDidAddPane 2014-08-28 17:22:28 -06:00
Ben Ogle 7ca5ece68a Add methods to be symmetrical with selections
* getCursorsOrderedByBufferPosition
* getCursorBufferPositions
* getCursorScreenPositions
2014-08-28 16:06:44 -07:00
Nathan Sobo 5471e9bccc Add PaneContainer::onDidDestroyPaneItem 2014-08-28 16:58:38 -06:00
Nathan Sobo b60b9f3e3a Add Pane::observeItems 2014-08-28 16:40:54 -06:00
Nathan Sobo 12f78dd957 💄 2014-08-28 16:27:20 -06:00
Ben Ogle e74244fc25 Move less used function down in the order 2014-08-28 15:25:35 -07:00
Ben Ogle 65ba95a449 Add missing docs 2014-08-28 15:25:23 -07:00
Ben Ogle 370ad23f7c Remove Cursor from ::moveCursor* methods 2014-08-28 15:25:12 -07:00
Nathan Sobo cea4db5381 Break pane API into sections 2014-08-28 16:24:53 -06:00
Nathan Sobo 345617e0f3 Clean up existing pane API docs 2014-08-28 15:57:30 -06:00
Nathan Sobo 78c24fb737 Remove legacy event documentation 2014-08-28 15:54:16 -06:00
Ben Ogle 01b48d2a0a Move adding cursor functions under more heavily used functions 2014-08-28 14:44:23 -07:00
Ben Ogle 45a9bd21fc Deprecate getCursorScreenRow
It’s out of place, and unnecessary.
2014-08-28 14:43:36 -07:00
Ben Ogle db83375293 Buffer before screen, get before set 2014-08-28 14:38:58 -07:00
Ben Ogle a4a25576a2 Split cursor methods into essential and extended 2014-08-28 14:35:39 -07:00
Nathan Sobo e88eb3012e Document Pane event subscription methods 2014-08-28 15:32:02 -06:00
Nathan Sobo d7063c0932 Add Pane::onDidDestroy 2014-08-28 15:21:35 -06:00
Nathan Sobo 34cb5d6012 Don’t implement ::isActive in terms of the theorist model behavior 2014-08-28 15:21:10 -06:00
Nathan Sobo 95e9686b37 Emit legacy item-added DOM event correctly 2014-08-28 14:42:13 -06:00
Nathan Sobo b1916069de Delegate ::getActivePane[Item] directly to PaneContainer 2014-08-28 14:42:13 -06:00
Nathan Sobo 9223361c22 Add PaneContainer::onDidChange/observeRoot
Also, don’t use a behavior to monitor root changes
2014-08-28 14:42:13 -06:00
Nathan Sobo 7556b85806 Remove/add the *subscription*, not the child 2014-08-28 14:42:12 -06:00
Nathan Sobo b74554ad4c Actually subscribe 2014-08-28 14:42:12 -06:00
Nathan Sobo b34367ad44 💄 pane-container-spec 2014-08-28 14:42:12 -06:00
Nathan Sobo cf3e1177ab Upgrade event-kit to fix stupid bug 2014-08-28 14:42:12 -06:00
Nathan Sobo 74b2f26540 Add PaneContainer::onDidChangeActivePaneItem 2014-08-28 14:41:56 -06:00
Nathan Sobo b89202f82c Dispose of PaneAxis subscriptions when destroyed 2014-08-28 14:41:56 -06:00
Nathan Sobo 9487609f0c 💄 pane-container-spec 2014-08-28 14:41:56 -06:00
Nathan Sobo da63c6bab2 Add ::onDidDestroy to Pane and PaneAxis 2014-08-28 14:41:56 -06:00
Ivan Žužak a00b3b2cc9 Merge pull request #3394 from atom/iz-builtin-context-menu-commands
Add cut/copy/paste built-in context menu items
2014-08-28 20:41:21 +02:00
Ben Ogle 0888d8ac60 Upgrade atom-dark-ui 2014-08-28 11:27:45 -07:00
Ben Ogle b895f7074d Upgrade find and replace to remove deprecation 2014-08-28 11:19:40 -07:00
Ivan Zuzak 7b73d6749d Add undo, redo, delete and select all commands to context menu 2014-08-28 20:13:16 +02:00
Nathan Sobo 67c3a41a60 Upgrade event-kit to fix bug and get CompositeDisposable::remove 2014-08-28 11:43:33 -06:00
Nathan Sobo c25ab0db43 Rename ::disposables to ::subscriptions in PaneView
Now that emissary’s Subscriber no longer conflicts with the name
2014-08-28 11:43:09 -06:00
Nathan Sobo 9979ae4b09 Add child event methods to PaneAxis
This eliminates our reliance on the Sequence object for informing us
of changes
2014-08-28 11:43:09 -06:00
Nathan Sobo a9294aebc3 Don’t use Sequence in PaneAxis 2014-08-28 11:43:09 -06:00
Nathan Sobo f161f5352e Don’t rely on Sequences to reparent the last child 2014-08-28 11:43:09 -06:00
Nathan Sobo 4f826a70f8 Use Array instead of Sequence for Pane::items 2014-08-28 11:43:08 -06:00
Nathan Sobo 1d365db9df Use getActiveItem getter in pane-view-spec 2014-08-28 11:43:08 -06:00
Nathan Sobo b9feed8eb4 Handle objects in subscriptions instead of multiple args 2014-08-28 11:43:08 -06:00
Nathan Sobo 475dc6074c 💄 2014-08-28 11:43:08 -06:00
Nathan Sobo 40d93cd0cf Use Pane::setActiveItem internally so observers are invoked 2014-08-28 11:43:08 -06:00
Nathan Sobo 99d70b4a4e Don’t emit ::onDidChangeActiveItem events unless it really changes 2014-08-28 11:43:08 -06:00
Nathan Sobo 87cdc1a45d Don’t invoke ::onDidChangeActivePane events unless it really changes 2014-08-28 11:43:08 -06:00
Nathan Sobo e7a7e86dea Add Pane::observeActive and ::observeActiveItem
These have behavior semantics, invoking the observer immediately with
the current value of the observed property.
2014-08-28 11:43:07 -06:00
Nathan Sobo b6c669a292 Subscribe with new event methods in PaneView 2014-08-28 11:43:07 -06:00
Nathan Sobo 44d70aaa5b Add Pane::onDidChangeActive() 2014-08-28 11:43:07 -06:00
Nathan Sobo 2b63f8a4ee Add PaneContainer::onDidChangeActivePane 2014-08-28 11:43:07 -06:00
Nathan Sobo 8225f759bf Add Pane::onWillDestroyItem() 2014-08-28 11:43:07 -06:00
Nathan Sobo 2d58d9c8b5 Add Pane::onDidActivate 2014-08-28 11:43:07 -06:00
Nathan Sobo 548018e9b2 Add spec for onDidRemoveItem observers when moving items to other panes 2014-08-28 11:43:07 -06:00
Nathan Sobo 9bd2eec4bc Add Pane::onDidMoveItem() 2014-08-28 11:43:07 -06:00
Nathan Sobo b8fcbe9451 Start adding event subscription methods to pane
This branch uses EventKit, an ultra-simple library for implementing
events. The object implementing the methods maintains its own emitter
object rather than doing a mixin like Emissary encourages. This will
make it easier for us to deprecate ::on on the object itself. Unlike
emissary, the EventKit Emitter implements a super minimalistic API that
only allows one value to be emitted and always returns a Disposable
from subscriptions.
2014-08-28 11:43:06 -06:00
Ivan Zuzak 861dff107a 💄 simplify assignment using coffeescript magic 2014-08-28 19:42:59 +02:00
Nathan Sobo ebb02bcd37 Use public getters instead of properties in pane-spec 2014-08-28 11:42:42 -06:00
syndg fcb72049e1 Added linux open-folder keybind.
Moved application:open-dev to `ctrl-alt-o`
2014-08-28 14:05:42 +03:00
Michael Herring 039e61e960 updated regex in usesSoftTabs to only look for Tab and Space 2014-08-28 17:44:49 +09:00
Michael Herring 002f9ca2b1 merge latest upstream master 2014-08-28 17:35:09 +09:00
Ben Ogle 726b04ef80 Update find-and-replace 2014-08-27 19:21:49 -07:00
Kevin Sawicki 20b64dd744 Upgrade to tabs@0.50 2014-08-27 15:26:31 -07:00
Kevin Sawicki a3d2924484 Split on whitespace 2014-08-27 14:43:23 -07:00
Kevin Sawicki d225966374 installSize -> installedSize 2014-08-27 14:35:16 -07:00
Kevin Sawicki 6d23fa1620 🐧 Set installedSize value in control file
Closes #2183
2014-08-27 14:23:09 -07:00
Kevin Sawicki 682d84dea0 Log location of created .deb file 2014-08-27 14:09:57 -07:00
Kevin Sawicki 969e5b65df Upgrade to welcome@0.18 2014-08-27 12:36:36 -07:00
Kevin Sawicki 8e5f4ced21 🐧 Move settings items to Edit menu
Closes #2467
2014-08-27 12:34:48 -07:00
Ben Ogle bbdd304834 Merge pull request #3229 from atom/docs-metadata
New API docs
2014-08-27 11:33:04 -07:00
Kevin Sawicki 5360b719f2 Upgrade to oniguruma 3.0.4 2014-08-27 11:29:14 -07:00
Kevin Sawicki 17a9e397f3 🐧 Add ~/.atom open commands to File menu 2014-08-27 11:10:30 -07:00
Kevin Sawicki f01f0eb90b Upgrade to language-sass@0.20 2014-08-27 10:57:33 -07:00
Kevin Sawicki 53d16098ca Merge pull request #3396 from syndbg/master
Added missing keybind in linux.cson.
2014-08-27 10:17:25 -07:00
Ben Ogle cb34539508 Fix syntax highlighting 2014-08-27 09:36:08 -07:00
syndg 1221a140aa Added missing keybind in linux.cson.
`'ctrl-,': 'application:show-settings'` exists in `win32.cson` and `darwin32.cson`
2014-08-27 17:10:08 +03:00
Ivan Zuzak 776a8e935a Add cut/copy/paste built-in context menu items 2014-08-27 13:55:44 +02:00
Ivan Zuzak 096255f283 Support built-in context menu items 2014-08-27 13:54:55 +02:00
Ben Ogle 327749b6c5 Upgrade packages in the public docs.
They now are on the latest grunt-atomdoc and have docstrings that export
well
2014-08-26 19:23:51 -07:00
Kevin Sawicki cd3bd048fd Merge pull request #3389 from atom/ks-spec-task-on-linux
Add spec task on Linux
2014-08-26 18:38:34 -07:00
Ben Ogle d79807fbe5 Document atom.* globals as properties 2014-08-26 16:00:35 -07:00
Ben Ogle 7a67619216 Use donna 1.0 2014-08-26 15:59:53 -07:00
Kevin Sawicki 496e49a5b9 Use correct process name on Linux 2014-08-26 15:10:43 -07:00
Kevin Sawicki 08decbe533 Explicitly set app path perms to 755 on Linux 2014-08-26 14:59:42 -07:00
Kevin Sawicki 37fc8b5945 Add initial spec task support on linux 2014-08-26 14:59:42 -07:00
Kevin Sawicki f88c805466 Upgrade to markdown-preview@0.100 2014-08-26 14:59:28 -07:00
Kevin Sawicki e8cd59eaef Waits for reloaded event from ThemeManager
Previously disabling a theme wouldn't wait for the full reload
to finish since and the spec would intermittently fail because
the promise was fulfilled after the spec completed and the
subscription was leaked.
2014-08-26 14:23:20 -07:00
Kevin Sawicki 600005de15 Upgrade to go-to-line@0.25 2014-08-26 14:21:14 -07:00
Kevin Sawicki aaa788b8da Upgrade to settings-view@0.141 2014-08-26 12:53:44 -07:00
Kevin Sawicki 9a70fdc3d9 Prepare 0.125 2014-08-26 12:04:27 -07:00
Ben Ogle a296364e53 Fixup doc strings that don’t parse correctly
We can’t have a huge indent on the second line of a list item. Markdown
parses it as a code block. :(
2014-08-26 10:47:36 -07:00
Ben Ogle d8a4280df1 Upgrade text-buffer for updated doc strings 2014-08-25 19:05:50 -07:00
Kevin Sawicki 157a753bfb Upgrade to space-pen 3.4.3 2014-08-25 16:36:53 -07:00
Kevin Sawicki 08f39c6a5a Upgrade to atom-keymap@2.0.4 2014-08-25 15:35:47 -07:00
Ben Ogle d6d7d3942c 📝 Convert EditorView docs 2014-08-25 15:26:38 -07:00
Ben Ogle c3acd8cf0c 📝 Convert workspaceView docs 2014-08-25 15:13:46 -07:00
Ben Ogle 12f58f0478 📝 Convert workspace docs 2014-08-25 15:13:45 -07:00
Ben Ogle 66e6a481a4 📝 Convert ThemeManager docs 2014-08-25 15:13:45 -07:00
Ben Ogle de27dce6bf Convert SelectListView docs 2014-08-25 15:13:45 -07:00
Ben Ogle 6c19a58c7c 📝 Convert Project docs 2014-08-25 15:13:45 -07:00
Ben Ogle c294208f87 📝 Convert PaneView docs 2014-08-25 15:13:45 -07:00
Ben Ogle d7f3add250 📝 Convert Pane docs 2014-08-25 15:13:45 -07:00
Ben Ogle a93ef05e13 📝 Convert Selection docs 2014-08-25 15:13:45 -07:00
Kevin Sawicki 8241918b6e Include classes from node_modules in proper object and order 2014-08-25 15:13:45 -07:00
Ben Ogle 8aae7b983e 📝 Convert Cursor Docs 2014-08-25 15:13:45 -07:00
Ben Ogle ad4f464d7c Fix Decoration events 2014-08-25 15:13:45 -07:00
Ben Ogle 352f1e34ab No mo : 2014-08-25 15:08:46 -07:00
Kevin Sawicki 2cdae3c6c1 Upgrade to pathwatcher 2.0.9 2014-08-25 15:08:46 -07:00
Kevin Sawicki 5df944e804 📝 Update Task docs 2014-08-25 15:08:46 -07:00
Kevin Sawicki 762f8c2e5a 📝 Update Syntax docs 2014-08-25 15:08:46 -07:00
Kevin Sawicki 41c96a82a9 Upgrade to first-mate 2.0.4 2014-08-25 15:08:46 -07:00
Ben Ogle 5a51d3a0c9 Fix indentation 2014-08-25 15:08:46 -07:00
Ben Ogle d79eb8eed3 Update decoration docs 2014-08-25 15:08:46 -07:00
Ben Ogle 9bb6bdf666 Update decorateMarker docs 2014-08-25 15:08:46 -07:00
Ben Ogle 0ab282340f Upgrade to tello@0.2 2014-08-25 15:08:45 -07:00
Ben Ogle 393f6bdd35 Add optional to all optional args 2014-08-25 15:08:45 -07:00
Ben Ogle a4b2f3aa4b Editor event documentation 2014-08-25 15:08:45 -07:00
Kevin Sawicki ee4c7e996f 📝 Convert ScrollView docs 2014-08-25 15:08:45 -07:00
Kevin Sawicki 59bf16fed3 📝 Convert PackageManager docs 2014-08-25 15:08:45 -07:00
Ben Ogle 99917a536e Add a couple events for test purposes 2014-08-25 15:08:45 -07:00
Ben Ogle 61a82fa0e4 Upgrade tello to use new events format 2014-08-25 15:08:45 -07:00
Kevin Sawicki 0bca0810b9 📝 Convert MenuManager docs 2014-08-25 15:08:45 -07:00
Kevin Sawicki 7d910000a2 📝 Convert DeserializerManager docs 2014-08-25 15:08:45 -07:00
Kevin Sawicki af67671f60 📝 Convert ContextMenuManager docs 2014-08-25 15:08:45 -07:00
Kevin Sawicki 0079007bb6 📝 Convert Config docs 2014-08-25 15:08:45 -07:00
Kevin Sawicki c2fa20c543 📝 Convert Clipboard docs 2014-08-25 15:08:45 -07:00
Kevin Sawicki aa5870570f 📝 Convert BufferedProcess docs 2014-08-25 15:08:45 -07:00
Kevin Sawicki 0e0d62b54c 📝 Convert BufferedNodeProcess docs 2014-08-25 15:08:45 -07:00
Kevin Sawicki 37542e3117 📝 Convert Atom docs 2014-08-25 15:08:44 -07:00
Kevin Sawicki 90e89ebaf9 📝 Convert Git docs 2014-08-25 15:07:15 -07:00
Ben Ogle e4939a8d6d Add sections to editor docs 2014-08-25 15:07:15 -07:00
Kevin Sawicki 50ddb8e3cc Upload atom-api.json asset during publish 2014-08-25 15:04:22 -07:00
Kevin Sawicki c61e36c7d3 Remove donnatello output 2014-08-25 15:04:22 -07:00
Kevin Sawicki 3035242daf Task is no longer async 2014-08-25 15:04:22 -07:00
Kevin Sawicki cfc965c135 Write to docs/output/api.json 2014-08-25 15:04:22 -07:00
Kevin Sawicki 1bc879a9b0 Remove copy-docs unused task 2014-08-25 15:04:22 -07:00
Kevin Sawicki 6225acbe8b Genrate docs from local api.json files 2014-08-25 15:04:22 -07:00
Kevin Sawicki bdf68ba15f Upgrade to theorist 1.0.2 2014-08-25 15:04:22 -07:00
Kevin Sawicki bbef8083d5 Upgrade to text-buffer 3.0.2 2014-08-25 15:04:21 -07:00
Kevin Sawicki f2f88cb343 Upgrade to space-pen 3.4.2 2014-08-25 15:04:21 -07:00
Kevin Sawicki a42de1e9be Upgrade to pathwatcher@2.0.8 2014-08-25 15:04:21 -07:00
Kevin Sawicki 1c97eb977e 💄 2014-08-25 15:04:21 -07:00
Kevin Sawicki d13fd495e4 Upgrade to first-mate 2.0.3 2014-08-25 15:04:21 -07:00
Kevin Sawicki c49ef1fd9d Parse all api.json files in node_modules 2014-08-25 15:04:21 -07:00
Ben Ogle e011be3428 Update argument lists in editor.coffee 2014-08-25 15:04:21 -07:00
Kevin Sawicki f993b78479 Remove unused deploy-docs task 2014-08-25 15:04:21 -07:00
Ben Ogle 86ef06ebb1 Update to contain superclasses 2014-08-25 15:04:21 -07:00
Ben Ogle 9f27e53bf1 Remove unnecessary metadata.json 2014-08-25 15:04:21 -07:00
Ben Ogle 720770e2ba Dont dupe classes 2014-08-25 15:04:21 -07:00
Ben Ogle e86b8c1a66 Remove unnecessary things 2014-08-25 15:04:20 -07:00
Ben Ogle 3b9d25ae92 Use donna and tello. Together. 2014-08-25 15:04:20 -07:00
Ben Ogle 9ee6a3d430 Docs task uses metadoc 2014-08-25 15:04:19 -07:00
Ben Ogle 162713e5b5 Sync package.json files for doc imports 2014-08-25 15:04:19 -07:00
Michael Herring aa9728c004 Better autodetection of Soft Tabs.
Check for the presence of a space, instead of the absence of a tab.
This ensures that Soft Tabs will not be activated on a file that (for
example) starts with a BOM or something, but is otherwise full of hard
tabs.
2014-08-24 19:04:46 +09:00
69 arquivos alterados com 5032 adições e 3451 exclusões
+9 -9
Ver Arquivo
@@ -53,7 +53,7 @@ describe "editorView.", ->
describe "at-end.", ->
beforeEach ->
editorView.moveCursorToBottom()
editorView.moveToBottom()
benchmark "insert-delete", ->
editorView.insertText('"')
@@ -62,8 +62,8 @@ describe "editorView.", ->
describe "empty-vs-set-innerHTML.", ->
[firstRow, lastRow] = []
beforeEach ->
firstRow = editorView.getFirstVisibleScreenRow()
lastRow = editorView.getLastVisibleScreenRow()
firstRow = editorView.getModel().getFirstVisibleScreenRow()
lastRow = editorView.getModel().getLastVisibleScreenRow()
benchmark "build-gutter-html.", 1000, ->
editorView.gutter.renderLineNumbers(null, firstRow, lastRow)
@@ -97,13 +97,13 @@ describe "editorView.", ->
describe "multiple-lines.", ->
[firstRow, lastRow] = []
beforeEach ->
firstRow = editorView.getFirstVisibleScreenRow()
lastRow = editorView.getLastVisibleScreenRow()
firstRow = editorView.getModel().getFirstVisibleScreenRow()
lastRow = editorView.getModel().getLastVisibleScreenRow()
benchmark "cache-entire-visible-area", 100, ->
for i in [firstRow..lastRow]
line = editorView.lineElementForScreenRow(i)[0]
editorView.positionLeftForLineAndColumn(line, i, Math.max(0, editorView.lineLengthForBufferRow(i)))
editorView.positionLeftForLineAndColumn(line, i, Math.max(0, editorView.getModel().lineTextForBufferRow(i).length))
describe "text-rendering.", ->
beforeEach ->
@@ -178,7 +178,7 @@ describe "editorView.", ->
atom.workspaceView.openSync('huge.js')
benchmark "moving-to-eof.", 1, ->
editorView.moveCursorToBottom()
editorView.moveToBottom()
describe "on-first-line.", ->
benchmark "inserting-newline", 5, ->
@@ -195,11 +195,11 @@ describe "editorView.", ->
endPosition = null
beforeEach ->
editorView.moveCursorToBottom()
editorView.moveToBottom()
endPosition = editorView.getCursorScreenPosition()
benchmark "move-to-beginning-of-word", ->
editorView.moveCursorToBeginningOfWord()
editorView.moveToBeginningOfWord()
editorView.setCursorScreenPosition(endPosition)
benchmark "insert", ->
+2 -2
Ver Arquivo
@@ -60,7 +60,7 @@ module.exports = (grunt) ->
contentsDir = shellAppDir
appDir = path.join(shellAppDir, 'resources', 'app')
installDir ?= process.env.INSTALL_PREFIX ? '/usr/local'
killCommand ='pkill -9 Atom'
killCommand ='pkill -9 atom'
coffeeConfig =
glob_to_multiple:
@@ -130,7 +130,7 @@ module.exports = (grunt) ->
atom: {appDir, appName, symbolsDir, buildDir, contentsDir, installDir, shellAppDir}
docsOutputDir: 'docs/output/api'
docsOutputDir: 'docs/output'
coffee: coffeeConfig
+2 -1
Ver Arquivo
@@ -7,7 +7,8 @@
},
"dependencies": {
"async": "~0.2.9",
"biscotto": ">=2.1.1 <3.0",
"donna": "~1.0",
"tello": "~0.2",
"formidable": "~1.0.14",
"fs-plus": "2.x",
"github-releases": "~0.2.0",
+28 -151
Ver Arquivo
@@ -1,162 +1,39 @@
path = require 'path'
async = require 'async'
fs = require 'fs-plus'
request = require 'request'
_ = require 'underscore-plus'
donna = require 'donna'
tello = require 'tello'
module.exports = (grunt) ->
{rm} = require('./task-helpers')(grunt)
getClassesToInclude = ->
modulesPath = path.resolve(__dirname, '..', '..', 'node_modules')
classes = {}
fs.traverseTreeSync modulesPath, (modulePath) ->
return true unless path.basename(modulePath) is 'package.json'
return true unless fs.isFileSync(modulePath)
cmd = path.join('node_modules', '.bin', 'coffee')
commonArgs = [path.join('build', 'node_modules', '.bin', 'biscotto'), '--']
opts =
stdio: 'inherit'
apiPath = path.join(path.dirname(modulePath), 'api.json')
if fs.isFileSync(apiPath)
_.extend(classes, grunt.file.readJSON(apiPath).classes)
true
classes
sortClasses = (classes) ->
sortedClasses = {}
for className in Object.keys(classes).sort()
sortedClasses[className] = classes[className]
sortedClasses
grunt.registerTask 'build-docs', 'Builds the API docs in src', ->
done = @async()
docsOutputDir = grunt.config.get('docsOutputDir')
downloadIncludes (error, includePaths) ->
if error?
done(error)
else
rm(docsOutputDir)
args = [
commonArgs...
'--title', 'Atom API Documentation'
'-o', docsOutputDir
'-r', 'docs/README.md'
'--stability', '1'
'src/'
includePaths...
]
grunt.util.spawn({cmd, args, opts}, done)
metadata = donna.generateMetadata(['.'])
api = tello.digest(metadata)
_.extend(api.classes, getClassesToInclude())
api.classes = sortClasses(api.classes)
grunt.registerTask 'lint-docs', 'Generate stats about the doc coverage', ->
done = @async()
downloadIncludes (error, includePaths) ->
if error?
done(error)
else
args = [
commonArgs...
'--noOutput'
'src/'
includePaths...
]
grunt.util.spawn({cmd, args, opts}, done)
grunt.registerTask 'missing-docs', 'Generate stats about the doc coverage', ->
done = @async()
downloadIncludes (error, includePaths) ->
if error?
done(error)
else
args = [
commonArgs...
'--noOutput'
'--missing'
'src/'
includePaths...
]
grunt.util.spawn({cmd, args, opts}, done)
grunt.registerTask 'copy-docs', 'Copies over latest API docs to atom-docs', ->
done = @async()
fetchTag = (args..., callback) ->
cmd = 'git'
args = ['describe', '--abbrev=0', '--tags']
grunt.util.spawn {cmd, args}, (error, result) ->
if error?
callback(error)
else
callback(null, String(result).trim())
copyDocs = (tag, callback) ->
cmd = 'cp'
args = ['-r', 'docs/output/', "../atom.io/public/docs/api/#{tag}/"]
fs.exists "../atom.io/public/docs/api/", (exists) ->
if exists
grunt.util.spawn {cmd, args}, (error, result) ->
if error?
callback(error)
else
callback(null, tag)
else
grunt.log.error "../atom.io/public/docs/api/ doesn't exist"
return false
grunt.util.async.waterfall [fetchTag, copyDocs], done
grunt.registerTask 'deploy-docs', 'Publishes latest API docs to atom-docs.githubapp.com', ->
done = @async()
docsRepoArgs = ['--work-tree=../atom-docs/', '--git-dir=../atom-docs/.git/']
fetchTag = (args..., callback) ->
cmd = 'git'
args = ['describe', '--abbrev=0', '--tags']
grunt.util.spawn {cmd, args}, (error, result) ->
if error?
callback(error)
else
callback(null, String(result).trim().split('.')[0..1].join('.'))
stageDocs = (tag, callback) ->
cmd = 'git'
args = [docsRepoArgs..., 'add', "public/#{tag}"]
grunt.util.spawn({cmd, args, opts}, callback)
fetchSha = (args..., callback) ->
cmd = 'git'
args = ['rev-parse', 'HEAD']
grunt.util.spawn {cmd, args}, (error, result) ->
if error?
callback(error)
else
callback(null, String(result).trim())
commitChanges = (sha, callback) ->
cmd = 'git'
args = [docsRepoArgs..., 'commit', "-m Update API docs to #{sha}"]
grunt.util.spawn({cmd, args, opts}, callback)
pushOrigin = (args..., callback) ->
cmd = 'git'
args = [docsRepoArgs..., 'push', 'origin', 'master']
grunt.util.spawn({cmd, args, opts}, callback)
pushHeroku = (args..., callback) ->
cmd = 'git'
args = [docsRepoArgs..., 'push', 'heroku', 'master']
grunt.util.spawn({cmd, args, opts}, callback)
grunt.util.async.waterfall [fetchTag, stageDocs, fetchSha, commitChanges, pushOrigin, pushHeroku], done
downloadFileFromRepo = ({repo, file}, callback) ->
uri = "https://raw.github.com/atom/#{repo}/master/#{file}"
request uri, (error, response, contents) ->
return callback(error) if error?
downloadPath = path.join('docs', 'includes', repo, file)
fs.writeFile downloadPath, contents, (error) ->
callback(error, downloadPath)
downloadIncludes = (callback) ->
includes = [
{repo: 'atom-keymap', file: 'src/keymap-manager.coffee'}
{repo: 'atom-keymap', file: 'src/key-binding.coffee'}
{repo: 'first-mate', file: 'src/grammar.coffee'}
{repo: 'first-mate', file: 'src/grammar-registry.coffee'}
{repo: 'node-pathwatcher', file: 'src/directory.coffee'}
{repo: 'node-pathwatcher', file: 'src/file.coffee'}
{repo: 'space-pen', file: 'src/space-pen.coffee'}
{repo: 'text-buffer', file: 'src/marker.coffee'}
{repo: 'text-buffer', file: 'src/point.coffee'}
{repo: 'text-buffer', file: 'src/range.coffee'}
{repo: 'text-buffer', file: 'src/text-buffer.coffee'}
{repo: 'theorist', file: 'src/model.coffee'}
]
async.map(includes, downloadFileFromRepo, callback)
apiJson = JSON.stringify(api, null, 2)
apiJsonPath = path.join(docsOutputDir, 'api.json')
grunt.file.write(apiJsonPath, apiJson)
+21 -9
Ver Arquivo
@@ -13,8 +13,16 @@ module.exports = (grunt) ->
grunt.file.write(outputPath, filled)
outputPath
getInstalledSize = (buildDir, callback) ->
cmd = 'du'
args = ['-sk', path.join(buildDir, 'Atom')]
spawn {cmd, args}, (error, {stdout}) ->
installedSize = stdout.split(/\s+/)?[0] or '200000' # default to 200MB
callback(null, installedSize)
grunt.registerTask 'mkdeb', 'Create debian package', ->
done = @async()
buildDir = grunt.config.get('atom.buildDir')
if process.arch is 'ia32'
arch = 'i386'
@@ -28,13 +36,17 @@ module.exports = (grunt) ->
maintainer = 'GitHub <atom@github.com>'
installDir = '/usr'
iconName = 'atom'
data = {name, version, description, section, arch, maintainer, installDir, iconName}
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)
icon = path.join('resources', 'atom.png')
controlFilePath = fillTemplate(path.join('resources', 'linux', 'debian', 'control'), data)
desktopFilePath = fillTemplate(path.join('resources', 'linux', 'Atom.desktop'), data)
icon = path.join('resources', 'atom.png')
buildDir = grunt.config.get('atom.buildDir')
cmd = path.join('script', 'mkdeb')
args = [version, arch, controlFilePath, desktopFilePath, icon, buildDir]
spawn({cmd, args}, done)
cmd = path.join('script', 'mkdeb')
args = [version, arch, controlFilePath, desktopFilePath, icon, buildDir]
spawn {cmd, args}, (error) ->
if error?
done(error)
else
grunt.log.ok "Created #{buildDir}/atom-#{version}-#{arch}.deb"
done()
+7 -4
Ver Arquivo
@@ -17,6 +17,7 @@ defaultHeaders =
module.exports = (gruntObject) ->
grunt = gruntObject
{cp} = require('./task-helpers')(grunt)
grunt.registerTask 'publish-build', 'Publish the built app', ->
return if process.env.JANKY_SHA1 and process.env.JANKY_BRANCH isnt 'master'
@@ -24,8 +25,10 @@ module.exports = (gruntObject) ->
tasks.unshift('build-docs', 'prepare-docs') if process.platform is 'darwin'
grunt.task.run(tasks)
grunt.registerTask 'prepare-docs', 'Move the build docs to the build dir', ->
fs.copySync(grunt.config.get('docsOutputDir'), path.join(grunt.config.get('atom.buildDir'), 'atom-docs'))
grunt.registerTask 'prepare-docs', 'Move api.json to atom-api.json', ->
docsOutputDir = grunt.config.get('docsOutputDir')
buildDir = grunt.config.get('atom.buildDir')
cp path.join(docsOutputDir, 'api.json'), path.join(buildDir, 'atom-api.json')
grunt.registerTask 'upload-assets', 'Upload the assets to a GitHub release', ->
done = @async()
@@ -46,7 +49,7 @@ getAssets = ->
[
{assetName: 'atom-mac.zip', sourcePath: 'Atom.app'}
{assetName: 'atom-mac-symbols.zip', sourcePath: 'Atom.breakpad.syms'}
{assetName: 'atom-docs.zip', sourcePath: 'atom-docs'}
{assetName: 'atom-api.json', sourcePath: 'atom-api.json'}
]
else
[
@@ -70,7 +73,7 @@ zipAssets = (buildDir, assets, callback) ->
callback(error)
tasks = []
for {assetName, sourcePath} in assets
for {assetName, sourcePath} in assets when path.extname(assetName) is '.zip'
fs.removeSync(path.join(buildDir, assetName))
tasks.push(zip.bind(this, buildDir, sourcePath, assetName))
async.parallel(tasks, callback)
+18 -14
Ver Arquivo
@@ -2,7 +2,6 @@ fs = require 'fs'
path = require 'path'
_ = require 'underscore-plus'
async = require 'async'
module.exports = (grunt) ->
@@ -10,18 +9,27 @@ module.exports = (grunt) ->
packageSpecQueue = null
getAppPath = ->
contentsDir = grunt.config.get('atom.contentsDir')
switch process.platform
when 'darwin'
path.join(contentsDir, 'MacOS', 'Atom')
when 'linux'
path.join(contentsDir, 'atom')
when 'win32'
path.join(contentsDir, 'atom.exe')
runPackageSpecs = (callback) ->
failedPackages = []
rootDir = grunt.config.get('atom.shellAppDir')
contentsDir = grunt.config.get('atom.contentsDir')
resourcePath = process.cwd()
if process.platform is 'darwin'
appPath = path.join(contentsDir, 'MacOS', 'Atom')
else if process.platform is 'win32'
appPath = path.join(contentsDir, 'atom.exe')
appPath = getAppPath()
# Ensure application is executable on Linux
fs.chmodSync(appPath, '755') if process.platform is 'linux'
packageSpecQueue = async.queue (packagePath, callback) ->
if process.platform is 'darwin'
if process.platform in ['darwin', 'linux']
options =
cmd: appPath
args: ['--test', "--resource-path=#{resourcePath}", "--spec-directory=#{path.join(packagePath, 'spec')}"]
@@ -57,15 +65,11 @@ module.exports = (grunt) ->
packageSpecQueue.drain = -> callback(null, failedPackages)
runCoreSpecs = (callback) ->
contentsDir = grunt.config.get('atom.contentsDir')
if process.platform is 'darwin'
appPath = path.join(contentsDir, 'MacOS', 'Atom')
else if process.platform is 'win32'
appPath = path.join(contentsDir, 'atom.exe')
appPath = getAppPath()
resourcePath = process.cwd()
coreSpecsPath = path.resolve('spec')
if process.platform is 'darwin'
if process.platform in ['darwin', 'linux']
options =
cmd: appPath
args: ['--test', "--resource-path=#{resourcePath}", "--spec-directory=#{coreSpecsPath}"]
@@ -90,7 +94,7 @@ module.exports = (grunt) ->
# TODO: This should really be parallel on both platforms, however our
# fixtures step on each others toes currently.
if process.platform is 'darwin'
if process.platform in ['darwin', 'linux']
method = async.parallel
else if process.platform is 'win32'
method = async.series
+1 -1
Ver Arquivo
@@ -56,7 +56,7 @@ character of the current line:
class EditorView
listenForEvents: ->
@command 'editor:move-to-first-character-of-line', =>
@editor.moveCursorToFirstCharacterOfLine()
@editor.moveToFirstCharacterOfLine()
```
The `::command` method is basically an enhanced version of jQuery's `::on`
+3 -3
Ver Arquivo
@@ -53,7 +53,7 @@ module.exports =
convert: ->
# This assumes the active pane item is an editor
editor = atom.workspace.activePaneItem
editor = atom.workspace.getActivePaneItem()
editor.insertText('Hello, World!')
```
@@ -131,8 +131,8 @@ inserting 'Hello, World!' convert the selected text to ASCII art.
```coffeescript
convert: ->
# This assumes the active pane item is an editor
editor = atom.workspace.activePaneItem
selection = editor.getSelection()
editor = atom.workspace.getActivePaneItem()
selection = editor.getLastSelection()
figlet = require 'figlet'
figlet selection.getText(), {font: "Larry 3D 2"}, (error, asciiArt) ->
+3 -1
Ver Arquivo
@@ -10,10 +10,12 @@
'ctrl-shift-i': 'window:toggle-dev-tools'
'ctrl-alt-p': 'window:run-package-specs'
'ctrl-alt-s': 'application:run-all-specs'
'ctrl-shift-o': 'application:open-dev'
'ctrl-alt-o': 'application:open-dev'
'ctrl-shift-o': 'application:open-folder'
'F11': 'window:toggle-full-screen'
# Sublime Parity
'ctrl-,': 'application:show-settings'
'ctrl-N': 'application:new-window'
'ctrl-W': 'window:close'
'ctrl-o': 'application:open-file'
+10
Ver Arquivo
@@ -192,3 +192,13 @@
]
}
]
'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'
+17 -2
Ver Arquivo
@@ -8,8 +8,6 @@
{ label: 'Open Folder...', command: 'application:open-folder' }
{ label: 'Reopen Last &Item', command: 'pane:reopen-closed-item' }
{ type: 'separator' }
{ label: '&Preferences...', command: 'application:show-settings' }
{ type: 'separator' }
{ label: '&Save', command: 'core:save' }
{ label: 'Save &As...', command: 'core:save-as' }
{ label: 'Save A&ll', command: 'window:save-all' }
@@ -80,6 +78,13 @@
{ label: 'Fold Level 9', command: 'editor:fold-at-indent-level-9' }
]
}
{ type: 'separator' }
{ label: '&Preferences', command: 'application:show-settings' }
{ label: 'Open Your Config', command: 'application:open-your-config' }
{ label: 'Open Your Init Script', command: 'application:open-your-init-script' }
{ label: 'Open Your Keymap', command: 'application:open-your-keymap' }
{ label: 'Open Your Snippets', command: 'application:open-your-snippets' }
{ label: 'Open Your Stylesheet', command: 'application:open-your-stylesheet' }
]
}
@@ -145,3 +150,13 @@
]
}
]
'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'
+10
Ver Arquivo
@@ -169,3 +169,13 @@
]
}
]
'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'
+28 -28
Ver Arquivo
@@ -1,7 +1,7 @@
{
"name": "atom",
"productName": "Atom",
"version": "0.124.0",
"version": "0.125.0",
"description": "A hackable text editor for the 21st Century.",
"main": "./src/browser/main.js",
"repository": {
@@ -20,28 +20,29 @@
"atomShellVersion": "0.15.9",
"dependencies": {
"async": "0.2.6",
"atom-keymap": "^2.0.2",
"atom-keymap": "^2.0.5",
"bootstrap": "git+https://github.com/atom/bootstrap.git#6af81906189f1747fd6c93479e3d998ebe041372",
"clear-cut": "0.4.0",
"coffee-script": "1.7.0",
"coffeestack": "0.7.0",
"delegato": "^1",
"emissary": "^1.2.2",
"first-mate": "^2.0.1",
"emissary": "^1.3.1",
"event-kit": "0.5.0",
"first-mate": "^2.0.5",
"fs-plus": "^2.2.6",
"fstream": "0.1.24",
"fuzzaldrin": "^1.1",
"fuzzaldrin": "^2.1",
"git-utils": "^2.1.4",
"grim": "0.12.0",
"guid": "0.0.10",
"jasmine-tagged": "^1.1.2",
"less-cache": "0.13.0",
"less-cache": "0.14.0",
"mixto": "^1",
"mkdirp": "0.3.5",
"nslog": "^1.0.1",
"oniguruma": "^3.0.3",
"oniguruma": "^3.0.4",
"optimist": "0.4.0",
"pathwatcher": "^2.0.7",
"pathwatcher": "^2.0.10",
"property-accessors": "^1",
"q": "^1.0.1",
"random-words": "0.0.1",
@@ -54,16 +55,16 @@
"season": "^1.0.2",
"semver": "1.1.4",
"serializable": "^1",
"space-pen": "3.4.1",
"space-pen": "3.4.6",
"temp": "0.7.0",
"text-buffer": "^3.0.1",
"theorist": "^1",
"text-buffer": "^3.2.0",
"theorist": "^1.0.2",
"underscore-plus": "^1.5.1",
"vm-compatibility-layer": "0.1.0"
},
"packageDependencies": {
"atom-dark-syntax": "0.19.0",
"atom-dark-ui": "0.33.0",
"atom-dark-ui": "0.34.0",
"atom-light-syntax": "0.20.0",
"atom-light-ui": "0.29.0",
"base16-tomorrow-dark-theme": "0.21.0",
@@ -78,67 +79,66 @@
"bookmarks": "0.28.0",
"bracket-matcher": "0.54.0",
"command-palette": "0.24.0",
"deprecation-cop": "0.9.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.130.0",
"fuzzy-finder": "0.57.0",
"find-and-replace": "0.134.0",
"fuzzy-finder": "0.58.0",
"git-diff": "0.39.0",
"go-to-line": "0.24.0",
"go-to-line": "0.25.0",
"grammar-selector": "0.29.0",
"image-view": "0.36.0",
"incompatible-packages": "0.9.0",
"keybinding-resolver": "0.19.0",
"link": "0.25.0",
"markdown-preview": "0.99.0",
"markdown-preview": "0.101.0",
"metrics": "0.33.0",
"open-on-github": "0.30.0",
"package-generator": "0.31.0",
"release-notes": "0.36.0",
"settings-view": "0.140.0",
"settings-view": "0.142.0",
"snippets": "0.51.0",
"spell-check": "0.42.0",
"status-bar": "0.44.0",
"styleguide": "0.30.0",
"symbols-view": "0.63.0",
"tabs": "0.49.0",
"tabs": "0.50.0",
"timecop": "0.22.0",
"tree-view": "0.112.0",
"tree-view": "0.114.0",
"update-package-dependencies": "0.6.0",
"welcome": "0.17.0",
"welcome": "0.18.0",
"whitespace": "0.25.0",
"wrap-guide": "0.21.0",
"language-c": "0.28.0",
"language-coffee-script": "0.30.0",
"language-css": "0.17.0",
"language-gfm": "0.48.0",
"language-git": "0.9.0",
"language-go": "0.16.0",
"language-go": "0.17.0",
"language-html": "0.25.0",
"language-hyperlink": "0.12.0",
"language-java": "0.11.0",
"language-javascript": "0.39.0",
"language-json": "0.8.0",
"language-less": "0.14.0",
"language-less": "0.15.0",
"language-make": "0.12.0",
"language-mustache": "0.10.0",
"language-objective-c": "0.11.0",
"language-perl": "0.9.0",
"language-php": "0.15.0",
"language-property-list": "0.7.0",
"language-python": "0.18.0",
"language-python": "0.19.0",
"language-ruby": "0.35.0",
"language-ruby-on-rails": "0.18.0",
"language-sass": "0.19.0",
"language-sass": "0.21.0",
"language-shellscript": "0.8.0",
"language-source": "0.8.0",
"language-sql": "0.10.0",
"language-text": "0.6.0",
"language-todo": "0.10.0",
"language-todo": "0.11.0",
"language-toml": "0.12.0",
"language-xml": "0.18.0",
"language-xml": "0.19.0",
"language-yaml": "0.17.0"
},
"private": true,
+1 -1
Ver Arquivo
@@ -3,6 +3,6 @@ Version: <%= version %>
Section: <%= section %>
Priority: optional
Architecture: <%= arch %>
Installed-Size: `du -ks usr|cut -f 1`
Installed-Size: <%= installedSize %>
Maintainer: <%= maintainer %>
Description: <%= description %>
+8 -3
Ver Arquivo
@@ -493,13 +493,14 @@ describe "the `atom` global", ->
expect(atom.config.get('core.disabledPackages')).toContain packageName
describe "with themes", ->
reloadedHandler = null
beforeEach ->
waitsForPromise ->
atom.themes.activateThemes()
afterEach ->
atom.themes.deactivateThemes()
atom.config.unobserve('core.themes')
it ".enablePackage() and .disablePackage() enables and disables a theme", ->
packageName = 'theme-with-package-file'
@@ -517,13 +518,17 @@ describe "the `atom` global", ->
expect(atom.config.get('core.themes')).toContain packageName
expect(atom.config.get('core.disabledPackages')).not.toContain packageName
# disabling of theme
reloadedHandler = jasmine.createSpy('reloadedHandler')
reloadedHandler.reset()
atom.themes.on('reloaded', reloadedHandler)
pack = atom.packages.disablePackage(packageName)
waitsFor ->
not (pack in atom.packages.getActivePackages())
reloadedHandler.callCount is 1
runs ->
expect(atom.packages.getActivePackages()).not.toContain pack
expect(atom.config.get('core.themes')).not.toContain packageName
expect(atom.config.get('core.themes')).not.toContain packageName
expect(atom.config.get('core.disabledPackages')).not.toContain packageName
+2 -1
Ver Arquivo
@@ -6,7 +6,8 @@ describe "ContextMenuManager", ->
[contextMenu] = []
beforeEach ->
contextMenu = new ContextMenuManager
{resourcePath} = atom.getLoadSettings()
contextMenu = new ContextMenuManager({resourcePath})
describe "adding definitions", ->
it 'loads', ->
+104 -104
Ver Arquivo
@@ -67,48 +67,48 @@ describe "DisplayBuffer", ->
it "uses the preferred line length as the soft wrap column when it is less than the configured soft wrap column", ->
atom.config.set('editor.preferredLineLength', 100)
atom.config.set('editor.softWrapAtPreferredLineLength', true)
expect(displayBuffer.lineForRow(10).text).toBe ' return '
expect(displayBuffer.tokenizedLineForScreenRow(10).text).toBe ' return '
atom.config.set('editor.preferredLineLength', 5)
expect(displayBuffer.lineForRow(10).text).toBe 'funct'
expect(displayBuffer.tokenizedLineForScreenRow(10).text).toBe 'funct'
atom.config.set('editor.softWrapAtPreferredLineLength', false)
expect(displayBuffer.lineForRow(10).text).toBe ' return '
expect(displayBuffer.tokenizedLineForScreenRow(10).text).toBe ' return '
describe "when the line is shorter than the max line length", ->
it "renders the line unchanged", ->
expect(displayBuffer.lineForRow(0).text).toBe buffer.lineForRow(0)
expect(displayBuffer.tokenizedLineForScreenRow(0).text).toBe buffer.lineForRow(0)
describe "when the line is empty", ->
it "renders the empty line", ->
expect(displayBuffer.lineForRow(13).text).toBe ''
expect(displayBuffer.tokenizedLineForScreenRow(13).text).toBe ''
describe "when there is a non-whitespace character at the max length boundary", ->
describe "when there is whitespace before the boundary", ->
it "wraps the line at the end of the first whitespace preceding the boundary", ->
expect(displayBuffer.lineForRow(10).text).toBe ' return '
expect(displayBuffer.lineForRow(11).text).toBe 'sort(left).concat(pivot).concat(sort(right));'
expect(displayBuffer.tokenizedLineForScreenRow(10).text).toBe ' return '
expect(displayBuffer.tokenizedLineForScreenRow(11).text).toBe 'sort(left).concat(pivot).concat(sort(right));'
describe "when there is no whitespace before the boundary", ->
it "wraps the line exactly at the boundary since there's no more graceful place to wrap it", ->
buffer.setTextInRange([[0, 0], [1, 0]], 'abcdefghijklmnopqrstuvwxyz\n')
displayBuffer.setEditorWidthInChars(10)
expect(displayBuffer.lineForRow(0).text).toBe 'abcdefghij'
expect(displayBuffer.lineForRow(1).text).toBe 'klmnopqrst'
expect(displayBuffer.lineForRow(2).text).toBe 'uvwxyz'
expect(displayBuffer.tokenizedLineForScreenRow(0).text).toBe 'abcdefghij'
expect(displayBuffer.tokenizedLineForScreenRow(1).text).toBe 'klmnopqrst'
expect(displayBuffer.tokenizedLineForScreenRow(2).text).toBe 'uvwxyz'
describe "when there is a whitespace character at the max length boundary", ->
it "wraps the line at the first non-whitespace character following the boundary", ->
expect(displayBuffer.lineForRow(3).text).toBe ' var pivot = items.shift(), current, left = [], '
expect(displayBuffer.lineForRow(4).text).toBe 'right = [];'
expect(displayBuffer.tokenizedLineForScreenRow(3).text).toBe ' var pivot = items.shift(), current, left = [], '
expect(displayBuffer.tokenizedLineForScreenRow(4).text).toBe 'right = [];'
describe "when there are hard tabs", ->
beforeEach ->
buffer.setText(buffer.getText().replace(new RegExp(' ', 'g'), '\t'))
it "correctly tokenizes the hard tabs", ->
expect(displayBuffer.lineForRow(3).tokens[0].isHardTab).toBeTruthy()
expect(displayBuffer.lineForRow(3).tokens[1].isHardTab).toBeTruthy()
expect(displayBuffer.tokenizedLineForScreenRow(3).tokens[0].isHardTab).toBeTruthy()
expect(displayBuffer.tokenizedLineForScreenRow(3).tokens[1].isHardTab).toBeTruthy()
describe "when the buffer changes", ->
describe "when buffer lines are updated", ->
@@ -121,8 +121,8 @@ describe "DisplayBuffer", ->
describe "when the update makes a soft-wrapped line shorter than the max line length", ->
it "rewraps the line and emits a change event", ->
buffer.delete([[6, 24], [6, 42]])
expect(displayBuffer.lineForRow(7).text).toBe ' current < pivot ? : right.push(current);'
expect(displayBuffer.lineForRow(8).text).toBe ' }'
expect(displayBuffer.tokenizedLineForScreenRow(7).text).toBe ' current < pivot ? : right.push(current);'
expect(displayBuffer.tokenizedLineForScreenRow(8).text).toBe ' }'
expect(changeHandler).toHaveBeenCalled()
[[event]]= changeHandler.argsForCall
@@ -132,30 +132,30 @@ describe "DisplayBuffer", ->
describe "when the update causes a line to softwrap an additional time", ->
it "rewraps the line and emits a change event", ->
buffer.insert([6, 28], '1234567890')
expect(displayBuffer.lineForRow(7).text).toBe ' current < pivot ? '
expect(displayBuffer.lineForRow(8).text).toBe 'left1234567890.push(current) : '
expect(displayBuffer.lineForRow(9).text).toBe 'right.push(current);'
expect(displayBuffer.lineForRow(10).text).toBe ' }'
expect(displayBuffer.tokenizedLineForScreenRow(7).text).toBe ' current < pivot ? '
expect(displayBuffer.tokenizedLineForScreenRow(8).text).toBe 'left1234567890.push(current) : '
expect(displayBuffer.tokenizedLineForScreenRow(9).text).toBe 'right.push(current);'
expect(displayBuffer.tokenizedLineForScreenRow(10).text).toBe ' }'
expect(changeHandler).toHaveBeenCalledWith(start: 7, end: 8, screenDelta: 1, bufferDelta: 0)
describe "when buffer lines are inserted", ->
it "inserts / updates wrapped lines and emits a change event", ->
buffer.insert([6, 21], '1234567890 abcdefghij 1234567890\nabcdefghij')
expect(displayBuffer.lineForRow(7).text).toBe ' current < pivot1234567890 abcdefghij '
expect(displayBuffer.lineForRow(8).text).toBe '1234567890'
expect(displayBuffer.lineForRow(9).text).toBe 'abcdefghij ? left.push(current) : '
expect(displayBuffer.lineForRow(10).text).toBe 'right.push(current);'
expect(displayBuffer.tokenizedLineForScreenRow(7).text).toBe ' current < pivot1234567890 abcdefghij '
expect(displayBuffer.tokenizedLineForScreenRow(8).text).toBe '1234567890'
expect(displayBuffer.tokenizedLineForScreenRow(9).text).toBe 'abcdefghij ? left.push(current) : '
expect(displayBuffer.tokenizedLineForScreenRow(10).text).toBe 'right.push(current);'
expect(changeHandler).toHaveBeenCalledWith(start: 7, end: 8, screenDelta: 2, bufferDelta: 1)
describe "when buffer lines are removed", ->
it "removes lines and emits a change event", ->
buffer.setTextInRange([[3, 21], [7, 5]], ';')
expect(displayBuffer.lineForRow(3).text).toBe ' var pivot = items;'
expect(displayBuffer.lineForRow(4).text).toBe ' return '
expect(displayBuffer.lineForRow(5).text).toBe 'sort(left).concat(pivot).concat(sort(right));'
expect(displayBuffer.lineForRow(6).text).toBe ' };'
expect(displayBuffer.tokenizedLineForScreenRow(3).text).toBe ' var pivot = items;'
expect(displayBuffer.tokenizedLineForScreenRow(4).text).toBe ' return '
expect(displayBuffer.tokenizedLineForScreenRow(5).text).toBe 'sort(left).concat(pivot).concat(sort(right));'
expect(displayBuffer.tokenizedLineForScreenRow(6).text).toBe ' };'
expect(changeHandler).toHaveBeenCalledWith(start: 3, end: 9, screenDelta: -6, bufferDelta: -4)
@@ -169,9 +169,9 @@ describe "DisplayBuffer", ->
buffer.delete([[0, Infinity], [1, 0]])
buffer.insert([0, Infinity], '\n')
expect(displayBuffer.lineForRow(0).text).toBe "the quick brown fox jumps over "
expect(displayBuffer.lineForRow(1).text).toBe "the lazy dog."
expect(displayBuffer.lineForRow(2).text).toBe ""
expect(displayBuffer.tokenizedLineForScreenRow(0).text).toBe "the quick brown fox jumps over "
expect(displayBuffer.tokenizedLineForScreenRow(1).text).toBe "the lazy dog."
expect(displayBuffer.tokenizedLineForScreenRow(2).text).toBe ""
describe "position translation", ->
it "translates positions accounting for wrapped lines", ->
@@ -204,9 +204,9 @@ describe "DisplayBuffer", ->
describe ".setEditorWidthInChars(length)", ->
it "changes the length at which lines are wrapped and emits a change event for all screen lines", ->
displayBuffer.setEditorWidthInChars(40)
expect(tokensText displayBuffer.lineForRow(4).tokens).toBe 'left = [], right = [];'
expect(tokensText displayBuffer.lineForRow(5).tokens).toBe ' while(items.length > 0) {'
expect(tokensText displayBuffer.lineForRow(12).tokens).toBe 'sort(left).concat(pivot).concat(sort(rig'
expect(tokensText displayBuffer.tokenizedLineForScreenRow(4).tokens).toBe 'left = [], right = [];'
expect(tokensText displayBuffer.tokenizedLineForScreenRow(5).tokens).toBe ' while(items.length > 0) {'
expect(tokensText displayBuffer.tokenizedLineForScreenRow(12).tokens).toBe 'sort(left).concat(pivot).concat(sort(rig'
expect(changeHandler).toHaveBeenCalledWith(start: 0, end: 15, screenDelta: 3, bufferDelta: 0)
it "only allows positive widths to be assigned", ->
@@ -242,7 +242,7 @@ describe "DisplayBuffer", ->
fold = displayBuffer.createFold(4, 7)
expect(fold).toBeDefined()
[line4, line5] = displayBuffer.linesForRows(4, 5)
[line4, line5] = displayBuffer.tokenizedLinesForScreenRows(4, 5)
expect(line4.fold).toBe fold
expect(line4.text).toMatch /^4-+/
expect(line5.text).toBe '8'
@@ -251,7 +251,7 @@ describe "DisplayBuffer", ->
changeHandler.reset()
fold.destroy()
[line4, line5] = displayBuffer.linesForRows(4, 5)
[line4, line5] = displayBuffer.tokenizedLinesForScreenRows(4, 5)
expect(line4.fold).toBeUndefined()
expect(line4.text).toMatch /^4-+/
expect(line5.text).toBe '5'
@@ -262,7 +262,7 @@ describe "DisplayBuffer", ->
it "renders a fold placeholder for the folded line but does not skip any lines", ->
fold = displayBuffer.createFold(4, 4)
[line4, line5] = displayBuffer.linesForRows(4, 5)
[line4, line5] = displayBuffer.tokenizedLinesForScreenRows(4, 5)
expect(line4.fold).toBe fold
expect(line4.text).toMatch /^4-+/
expect(line5.text).toBe '5'
@@ -275,7 +275,7 @@ describe "DisplayBuffer", ->
fold.destroy()
[line4, line5] = displayBuffer.linesForRows(4, 5)
[line4, line5] = displayBuffer.tokenizedLinesForScreenRows(4, 5)
expect(line4.fold).toBeUndefined()
expect(line4.text).toMatch /^4-+/
expect(line5.text).toBe '5'
@@ -287,13 +287,13 @@ describe "DisplayBuffer", ->
innerFold = displayBuffer.createFold(6, 7)
outerFold = displayBuffer.createFold(4, 8)
[line4, line5] = displayBuffer.linesForRows(4, 5)
[line4, line5] = displayBuffer.tokenizedLinesForScreenRows(4, 5)
expect(line4.fold).toBe outerFold
expect(line4.text).toMatch /4-+/
expect(line5.text).toMatch /9-+/
outerFold.destroy()
[line4, line5, line6, line7] = displayBuffer.linesForRows(4, 7)
[line4, line5, line6, line7] = displayBuffer.tokenizedLinesForScreenRows(4, 7)
expect(line4.fold).toBeUndefined()
expect(line4.text).toMatch /^4-+/
expect(line5.text).toBe '5'
@@ -305,7 +305,7 @@ describe "DisplayBuffer", ->
innerFold = displayBuffer.createFold(4, 6)
outerFold = displayBuffer.createFold(4, 8)
[line4, line5] = displayBuffer.linesForRows(4, 5)
[line4, line5] = displayBuffer.tokenizedLinesForScreenRows(4, 5)
expect(line4.fold).toBe outerFold
expect(line4.text).toMatch /4-+/
expect(line5.text).toMatch /9-+/
@@ -326,14 +326,14 @@ describe "DisplayBuffer", ->
innerFold = displayBuffer.createFold(2, 5)
expect(changeHandler).not.toHaveBeenCalled()
[line0, line1] = displayBuffer.linesForRows(0, 1)
[line0, line1] = displayBuffer.tokenizedLinesForScreenRows(0, 1)
expect(line0.fold).toBe outerFold
expect(line1.fold).toBeUndefined()
changeHandler.reset()
innerFold.destroy()
expect(changeHandler).not.toHaveBeenCalled()
[line0, line1] = displayBuffer.linesForRows(0, 1)
[line0, line1] = displayBuffer.tokenizedLinesForScreenRows(0, 1)
expect(line0.fold).toBe outerFold
expect(line1.fold).toBeUndefined()
@@ -342,8 +342,8 @@ describe "DisplayBuffer", ->
fold2 = displayBuffer.createFold(4, 9)
fold1 = displayBuffer.createFold(0, 4)
expect(displayBuffer.lineForRow(0).text).toMatch /^0/
expect(displayBuffer.lineForRow(1).text).toMatch /^10/
expect(displayBuffer.tokenizedLineForScreenRow(0).text).toMatch /^0/
expect(displayBuffer.tokenizedLineForScreenRow(1).text).toMatch /^10/
describe "when there is another display buffer pointing to the same buffer", ->
it "does not create folds in the other display buffer", ->
@@ -363,19 +363,19 @@ describe "DisplayBuffer", ->
buffer.setTextInRange([[1, 0], [5, 1]], 'party!')
it "removes the fold and replaces the selection with the new text", ->
expect(displayBuffer.lineForRow(0).text).toBe "0"
expect(displayBuffer.lineForRow(1).text).toBe "party!"
expect(displayBuffer.lineForRow(2).fold).toBe fold2
expect(displayBuffer.lineForRow(3).text).toMatch /^9-+/
expect(displayBuffer.tokenizedLineForScreenRow(0).text).toBe "0"
expect(displayBuffer.tokenizedLineForScreenRow(1).text).toBe "party!"
expect(displayBuffer.tokenizedLineForScreenRow(2).fold).toBe fold2
expect(displayBuffer.tokenizedLineForScreenRow(3).text).toMatch /^9-+/
expect(changeHandler).toHaveBeenCalledWith(start: 1, end: 3, screenDelta: -2, bufferDelta: -4)
describe "when the changes is subsequently undone", ->
xit "restores destroyed folds", ->
buffer.undo()
expect(displayBuffer.lineForRow(2).text).toBe '2'
expect(displayBuffer.lineForRow(2).fold).toBe fold1
expect(displayBuffer.lineForRow(3).text).toBe '5'
expect(displayBuffer.tokenizedLineForScreenRow(2).text).toBe '2'
expect(displayBuffer.tokenizedLineForScreenRow(2).fold).toBe fold1
expect(displayBuffer.tokenizedLineForScreenRow(3).text).toBe '5'
describe "when the old range surrounds two nested folds", ->
it "removes both folds and replaces the selection with the new text", ->
@@ -384,9 +384,9 @@ describe "DisplayBuffer", ->
buffer.setTextInRange([[1, 0], [10, 0]], 'goodbye')
expect(displayBuffer.lineForRow(0).text).toBe "0"
expect(displayBuffer.lineForRow(1).text).toBe "goodbye10"
expect(displayBuffer.lineForRow(2).text).toBe "11"
expect(displayBuffer.tokenizedLineForScreenRow(0).text).toBe "0"
expect(displayBuffer.tokenizedLineForScreenRow(1).text).toBe "goodbye10"
expect(displayBuffer.tokenizedLineForScreenRow(2).text).toBe "11"
expect(changeHandler).toHaveBeenCalledWith(start: 1, end: 3, screenDelta: -2, bufferDelta: -9)
@@ -403,42 +403,42 @@ describe "DisplayBuffer", ->
it "updates the buffer and re-positions subsequent folds", ->
buffer.setTextInRange([[0, 0], [1, 1]], 'abc')
expect(displayBuffer.lineForRow(0).text).toBe "abc"
expect(displayBuffer.lineForRow(1).fold).toBe fold1
expect(displayBuffer.lineForRow(2).text).toBe "5"
expect(displayBuffer.lineForRow(3).fold).toBe fold2
expect(displayBuffer.lineForRow(4).text).toMatch /^9-+/
expect(displayBuffer.tokenizedLineForScreenRow(0).text).toBe "abc"
expect(displayBuffer.tokenizedLineForScreenRow(1).fold).toBe fold1
expect(displayBuffer.tokenizedLineForScreenRow(2).text).toBe "5"
expect(displayBuffer.tokenizedLineForScreenRow(3).fold).toBe fold2
expect(displayBuffer.tokenizedLineForScreenRow(4).text).toMatch /^9-+/
expect(changeHandler).toHaveBeenCalledWith(start: 0, end: 1, screenDelta: -1, bufferDelta: -1)
changeHandler.reset()
fold1.destroy()
expect(displayBuffer.lineForRow(0).text).toBe "abc"
expect(displayBuffer.lineForRow(1).text).toBe "2"
expect(displayBuffer.lineForRow(3).text).toMatch /^4-+/
expect(displayBuffer.lineForRow(4).text).toBe "5"
expect(displayBuffer.lineForRow(5).fold).toBe fold2
expect(displayBuffer.lineForRow(6).text).toMatch /^9-+/
expect(displayBuffer.tokenizedLineForScreenRow(0).text).toBe "abc"
expect(displayBuffer.tokenizedLineForScreenRow(1).text).toBe "2"
expect(displayBuffer.tokenizedLineForScreenRow(3).text).toMatch /^4-+/
expect(displayBuffer.tokenizedLineForScreenRow(4).text).toBe "5"
expect(displayBuffer.tokenizedLineForScreenRow(5).fold).toBe fold2
expect(displayBuffer.tokenizedLineForScreenRow(6).text).toMatch /^9-+/
expect(changeHandler).toHaveBeenCalledWith(start: 1, end: 1, screenDelta: 2, bufferDelta: 0)
describe "when the old range straddles the beginning of a fold", ->
it "destroys the fold", ->
buffer.setTextInRange([[1, 1], [3, 0]], "a\nb\nc\nd\n")
expect(displayBuffer.lineForRow(1).text).toBe '1a'
expect(displayBuffer.lineForRow(2).text).toBe 'b'
expect(displayBuffer.lineForRow(2).fold).toBeUndefined()
expect(displayBuffer.lineForRow(3).text).toBe 'c'
expect(displayBuffer.tokenizedLineForScreenRow(1).text).toBe '1a'
expect(displayBuffer.tokenizedLineForScreenRow(2).text).toBe 'b'
expect(displayBuffer.tokenizedLineForScreenRow(2).fold).toBeUndefined()
expect(displayBuffer.tokenizedLineForScreenRow(3).text).toBe 'c'
describe "when the old range follows a fold", ->
it "re-positions the screen ranges for the change event based on the preceding fold", ->
buffer.setTextInRange([[10, 0], [11, 0]], 'abc')
expect(displayBuffer.lineForRow(1).text).toBe "1"
expect(displayBuffer.lineForRow(2).fold).toBe fold1
expect(displayBuffer.lineForRow(3).text).toBe "5"
expect(displayBuffer.lineForRow(4).fold).toBe fold2
expect(displayBuffer.lineForRow(5).text).toMatch /^9-+/
expect(displayBuffer.tokenizedLineForScreenRow(1).text).toBe "1"
expect(displayBuffer.tokenizedLineForScreenRow(2).fold).toBe fold1
expect(displayBuffer.tokenizedLineForScreenRow(3).text).toBe "5"
expect(displayBuffer.tokenizedLineForScreenRow(4).fold).toBe fold2
expect(displayBuffer.tokenizedLineForScreenRow(5).text).toMatch /^9-+/
expect(changeHandler).toHaveBeenCalledWith(start: 6, end: 7, screenDelta: -1, bufferDelta: -1)
@@ -449,12 +449,12 @@ describe "DisplayBuffer", ->
expect(fold1.getStartRow()).toBe 2
expect(fold1.getEndRow()).toBe 5
expect(displayBuffer.lineForRow(1).text).toBe "1"
expect(displayBuffer.lineForRow(2).text).toBe "2"
expect(displayBuffer.lineForRow(2).fold).toBe fold1
expect(displayBuffer.lineForRow(3).text).toMatch "5"
expect(displayBuffer.lineForRow(4).fold).toBe fold2
expect(displayBuffer.lineForRow(5).text).toMatch /^9-+/
expect(displayBuffer.tokenizedLineForScreenRow(1).text).toBe "1"
expect(displayBuffer.tokenizedLineForScreenRow(2).text).toBe "2"
expect(displayBuffer.tokenizedLineForScreenRow(2).fold).toBe fold1
expect(displayBuffer.tokenizedLineForScreenRow(3).text).toMatch "5"
expect(displayBuffer.tokenizedLineForScreenRow(4).fold).toBe fold2
expect(displayBuffer.tokenizedLineForScreenRow(5).text).toMatch /^9-+/
expect(changeHandler).toHaveBeenCalledWith(start: 2, end: 2, screenDelta: 0, bufferDelta: 1)
@@ -464,12 +464,12 @@ describe "DisplayBuffer", ->
expect(fold1.getStartRow()).toBe 2
expect(fold1.getEndRow()).toBe 7
expect(displayBuffer.lineForRow(1).text).toBe "1"
expect(displayBuffer.lineForRow(2).text).toBe "2"
expect(displayBuffer.lineForRow(2).fold).toBe fold1
expect(displayBuffer.lineForRow(3).text).toMatch "5"
expect(displayBuffer.lineForRow(4).fold).toBe fold2
expect(displayBuffer.lineForRow(5).text).toMatch /^9-+/
expect(displayBuffer.tokenizedLineForScreenRow(1).text).toBe "1"
expect(displayBuffer.tokenizedLineForScreenRow(2).text).toBe "2"
expect(displayBuffer.tokenizedLineForScreenRow(2).fold).toBe fold1
expect(displayBuffer.tokenizedLineForScreenRow(3).text).toMatch "5"
expect(displayBuffer.tokenizedLineForScreenRow(4).fold).toBe fold2
expect(displayBuffer.tokenizedLineForScreenRow(5).text).toMatch /^9-+/
expect(changeHandler).toHaveBeenCalledWith(start: 2, end: 2, screenDelta: 0, bufferDelta: 3)
@@ -478,21 +478,21 @@ describe "DisplayBuffer", ->
it "destroys the fold", ->
fold2.destroy()
buffer.setTextInRange([[3, 0], [6, 0]], 'a\n')
expect(displayBuffer.lineForRow(2).text).toBe '2'
expect(displayBuffer.lineForRow(2).fold).toBeUndefined()
expect(displayBuffer.lineForRow(3).text).toBe 'a'
expect(displayBuffer.lineForRow(4).text).toBe '6'
expect(displayBuffer.tokenizedLineForScreenRow(2).text).toBe '2'
expect(displayBuffer.tokenizedLineForScreenRow(2).fold).toBeUndefined()
expect(displayBuffer.tokenizedLineForScreenRow(3).text).toBe 'a'
expect(displayBuffer.tokenizedLineForScreenRow(4).text).toBe '6'
describe "when the old range is contained to a single line in-between two folds", ->
it "re-renders the line with the placeholder and re-positions the second fold", ->
buffer.insert([5, 0], 'abc\n')
expect(displayBuffer.lineForRow(1).text).toBe "1"
expect(displayBuffer.lineForRow(2).fold).toBe fold1
expect(displayBuffer.lineForRow(3).text).toMatch "abc"
expect(displayBuffer.lineForRow(4).text).toBe "5"
expect(displayBuffer.lineForRow(5).fold).toBe fold2
expect(displayBuffer.lineForRow(6).text).toMatch /^9-+/
expect(displayBuffer.tokenizedLineForScreenRow(1).text).toBe "1"
expect(displayBuffer.tokenizedLineForScreenRow(2).fold).toBe fold1
expect(displayBuffer.tokenizedLineForScreenRow(3).text).toMatch "abc"
expect(displayBuffer.tokenizedLineForScreenRow(4).text).toBe "5"
expect(displayBuffer.tokenizedLineForScreenRow(5).fold).toBe fold2
expect(displayBuffer.tokenizedLineForScreenRow(6).text).toMatch /^9-+/
expect(changeHandler).toHaveBeenCalledWith(start: 3, end: 3, screenDelta: 1, bufferDelta: 1)
@@ -545,15 +545,15 @@ describe "DisplayBuffer", ->
displayBuffer.createFold(1, 9)
displayBuffer.createFold(11, 12)
expect(displayBuffer.lineForRow(1).text).toBe '1'
expect(displayBuffer.lineForRow(2).text).toBe '10'
expect(displayBuffer.tokenizedLineForScreenRow(1).text).toBe '1'
expect(displayBuffer.tokenizedLineForScreenRow(2).text).toBe '10'
displayBuffer.unfoldBufferRow(2)
expect(displayBuffer.lineForRow(1).text).toBe '1'
expect(displayBuffer.lineForRow(2).text).toBe '2'
expect(displayBuffer.lineForRow(7).fold).toBeDefined()
expect(displayBuffer.lineForRow(8).text).toMatch /^9-+/
expect(displayBuffer.lineForRow(10).fold).toBeDefined()
expect(displayBuffer.tokenizedLineForScreenRow(1).text).toBe '1'
expect(displayBuffer.tokenizedLineForScreenRow(2).text).toBe '2'
expect(displayBuffer.tokenizedLineForScreenRow(7).fold).toBeDefined()
expect(displayBuffer.tokenizedLineForScreenRow(8).text).toMatch /^9-+/
expect(displayBuffer.tokenizedLineForScreenRow(10).fold).toBeDefined()
describe ".outermostFoldsInBufferRowRange(startRow, endRow)", ->
it "returns the outermost folds entirely contained in the given row range, exclusive of end row", ->
+78 -34
Ver Arquivo
@@ -65,9 +65,9 @@ describe "EditorComponent", ->
linesNode = componentNode.querySelector('.lines')
expect(linesNode.style['-webkit-transform']).toBe "translate3d(0px, 0px, 0px)"
expect(componentNode.querySelectorAll('.line').length).toBe 6 + 2 # no margin above
expect(component.lineNodeForScreenRow(0).textContent).toBe editor.lineForScreenRow(0).text
expect(component.lineNodeForScreenRow(0).textContent).toBe editor.tokenizedLineForScreenRow(0).text
expect(component.lineNodeForScreenRow(0).offsetTop).toBe 0
expect(component.lineNodeForScreenRow(5).textContent).toBe editor.lineForScreenRow(5).text
expect(component.lineNodeForScreenRow(5).textContent).toBe editor.tokenizedLineForScreenRow(5).text
expect(component.lineNodeForScreenRow(5).offsetTop).toBe 5 * lineHeightInPixels
verticalScrollbarNode.scrollTop = 4.5 * lineHeightInPixels
@@ -77,9 +77,9 @@ describe "EditorComponent", ->
expect(linesNode.style['-webkit-transform']).toBe "translate3d(0px, #{-4.5 * lineHeightInPixels}px, 0px)"
expect(componentNode.querySelectorAll('.line').length).toBe 6 + 4 # margin above and below
expect(component.lineNodeForScreenRow(2).offsetTop).toBe 2 * lineHeightInPixels
expect(component.lineNodeForScreenRow(2).textContent).toBe editor.lineForScreenRow(2).text
expect(component.lineNodeForScreenRow(2).textContent).toBe editor.tokenizedLineForScreenRow(2).text
expect(component.lineNodeForScreenRow(9).offsetTop).toBe 9 * lineHeightInPixels
expect(component.lineNodeForScreenRow(9).textContent).toBe editor.lineForScreenRow(9).text
expect(component.lineNodeForScreenRow(9).textContent).toBe editor.tokenizedLineForScreenRow(9).text
it "updates the top position of subsequent lines when lines are inserted or removed", ->
editor.getBuffer().deleteRows(0, 1)
@@ -111,11 +111,11 @@ describe "EditorComponent", ->
buffer.insert([0, 0], '\n\n')
nextAnimationFrame()
expect(component.lineNodeForScreenRow(3).textContent).toBe editor.lineForScreenRow(3).text
expect(component.lineNodeForScreenRow(3).textContent).toBe editor.tokenizedLineForScreenRow(3).text
buffer.delete([[0, 0], [3, 0]])
nextAnimationFrame()
expect(component.lineNodeForScreenRow(3).textContent).toBe editor.lineForScreenRow(3).text
expect(component.lineNodeForScreenRow(3).textContent).toBe editor.tokenizedLineForScreenRow(3).text
it "updates the top position of lines when the line height changes", ->
initialLineHeightInPixels = editor.getLineHeightInPixels()
@@ -601,7 +601,7 @@ describe "EditorComponent", ->
describe "cursor rendering", ->
it "renders the currently visible cursors, translated relative to the scroll position", ->
cursor1 = editor.getCursor()
cursor1 = editor.getLastCursor()
cursor1.setScreenPosition([0, 5])
wrapperNode.style.height = 4.5 * lineHeightInPixels + 'px'
@@ -710,7 +710,7 @@ describe "EditorComponent", ->
expect(cursorsNode.classList.contains('blink-off')).toBe false
# Stop blinking after moving the cursor
editor.moveCursorRight()
editor.moveRight()
expect(cursorsNode.classList.contains('blink-off')).toBe false
advanceClock(component.props.cursorBlinkResumeDelay)
@@ -814,8 +814,8 @@ describe "EditorComponent", ->
it "does not render empty selections", ->
editor.addSelectionForBufferRange([[2, 2], [2, 2]])
nextAnimationFrame()
expect(editor.getSelection(0).isEmpty()).toBe true
expect(editor.getSelection(1).isEmpty()).toBe true
expect(editor.getSelections()[0].isEmpty()).toBe true
expect(editor.getSelections()[1].isEmpty()).toBe true
expect(componentNode.querySelectorAll('.selection').length).toBe 0
@@ -1331,9 +1331,19 @@ describe "EditorComponent", ->
gutterNode = componentNode.querySelector('.gutter')
describe "when the gutter is clicked", ->
it "moves the cursor to the beginning of the clicked row", ->
it "selects the clicked row", ->
gutterNode.dispatchEvent(buildMouseEvent('mousedown', clientCoordinatesForScreenRowInGutter(4)))
expect(editor.getCursorScreenPosition()).toEqual [4, 0]
expect(editor.getSelectedScreenRange()).toEqual [[4, 0], [5, 0]]
describe "when the gutter is meta-clicked", ->
it "creates a new selection for the clicked row", ->
editor.setSelectedScreenRange([[3, 0], [3, 2]])
gutterNode.dispatchEvent(buildMouseEvent('mousedown', clientCoordinatesForScreenRowInGutter(4), metaKey: true))
expect(editor.getSelectedScreenRanges()).toEqual [[[3, 0], [3, 2]], [[4, 0], [5, 0]]]
gutterNode.dispatchEvent(buildMouseEvent('mousedown', clientCoordinatesForScreenRowInGutter(6), metaKey: true))
expect(editor.getSelectedScreenRanges()).toEqual [[[3, 0], [3, 2]], [[4, 0], [5, 0]], [[6, 0], [7, 0]]]
describe "when the gutter is shift-clicked", ->
beforeEach ->
@@ -1366,6 +1376,40 @@ describe "EditorComponent", ->
gutterNode.dispatchEvent(buildMouseEvent('mouseup', clientCoordinatesForScreenRowInGutter(2)))
expect(editor.getSelectedScreenRange()).toEqual [[2, 0], [7, 0]]
describe "when the gutter is meta-clicked and dragged", ->
beforeEach ->
editor.setSelectedScreenRange([[3, 0], [3, 2]])
describe "when dragging downward", ->
it "selects the rows between the start and end of the drag", ->
gutterNode.dispatchEvent(buildMouseEvent('mousedown', clientCoordinatesForScreenRowInGutter(4), metaKey: true))
gutterNode.dispatchEvent(buildMouseEvent('mousemove', clientCoordinatesForScreenRowInGutter(6), metaKey: true))
nextAnimationFrame()
gutterNode.dispatchEvent(buildMouseEvent('mouseup', clientCoordinatesForScreenRowInGutter(6), metaKey: true))
expect(editor.getSelectedScreenRanges()).toEqual [[[3, 0], [3, 2]], [[4, 0], [7, 0]]]
it "merges overlapping selections", ->
gutterNode.dispatchEvent(buildMouseEvent('mousedown', clientCoordinatesForScreenRowInGutter(2), metaKey: true))
gutterNode.dispatchEvent(buildMouseEvent('mousemove', clientCoordinatesForScreenRowInGutter(6), metaKey: true))
nextAnimationFrame()
gutterNode.dispatchEvent(buildMouseEvent('mouseup', clientCoordinatesForScreenRowInGutter(6), metaKey: true))
expect(editor.getSelectedScreenRanges()).toEqual [[[2, 0], [7, 0]]]
describe "when dragging upward", ->
it "selects the rows between the start and end of the drag", ->
gutterNode.dispatchEvent(buildMouseEvent('mousedown', clientCoordinatesForScreenRowInGutter(6), metaKey: true))
gutterNode.dispatchEvent(buildMouseEvent('mousemove', clientCoordinatesForScreenRowInGutter(4), metaKey: true))
nextAnimationFrame()
gutterNode.dispatchEvent(buildMouseEvent('mouseup', clientCoordinatesForScreenRowInGutter(4), metaKey: true))
expect(editor.getSelectedScreenRanges()).toEqual [[[3, 0], [3, 2]], [[4, 0], [7, 0]]]
it "merges overlapping selections", ->
gutterNode.dispatchEvent(buildMouseEvent('mousedown', clientCoordinatesForScreenRowInGutter(6), metaKey: true))
gutterNode.dispatchEvent(buildMouseEvent('mousemove', clientCoordinatesForScreenRowInGutter(2), metaKey: true))
nextAnimationFrame()
gutterNode.dispatchEvent(buildMouseEvent('mouseup', clientCoordinatesForScreenRowInGutter(2), metaKey: true))
expect(editor.getSelectedScreenRanges()).toEqual [[[2, 0], [7, 0]]]
describe "when the gutter is shift-clicked and dragged", ->
describe "when the shift-click is below the existing selection's tail", ->
describe "when dragging downward", ->
@@ -1437,7 +1481,7 @@ describe "EditorComponent", ->
cursor = null
beforeEach ->
cursor = editor.getCursor()
cursor = editor.getLastCursor()
cursor.setScreenPosition([0, 0])
it "adds the 'has-selection' class to the editor when there is a selection", ->
@@ -1783,28 +1827,28 @@ describe "EditorComponent", ->
it "inserts the newest character in the input's value into the buffer", ->
componentNode.dispatchEvent(buildTextInputEvent(data: 'x', target: inputNode))
nextAnimationFrame()
expect(editor.lineForBufferRow(0)).toBe 'xvar quicksort = function () {'
expect(editor.lineTextForBufferRow(0)).toBe 'xvar quicksort = function () {'
componentNode.dispatchEvent(buildTextInputEvent(data: 'y', target: inputNode))
nextAnimationFrame()
expect(editor.lineForBufferRow(0)).toBe 'xyvar quicksort = function () {'
expect(editor.lineTextForBufferRow(0)).toBe 'xyvar quicksort = function () {'
it "replaces the last character if the length of the input's value doesn't increase, as occurs with the accented character menu", ->
componentNode.dispatchEvent(buildTextInputEvent(data: 'u', target: inputNode))
nextAnimationFrame()
expect(editor.lineForBufferRow(0)).toBe 'uvar quicksort = function () {'
expect(editor.lineTextForBufferRow(0)).toBe 'uvar quicksort = function () {'
# simulate the accented character suggestion's selection of the previous character
inputNode.setSelectionRange(0, 1)
componentNode.dispatchEvent(buildTextInputEvent(data: 'ü', target: inputNode))
nextAnimationFrame()
expect(editor.lineForBufferRow(0)).toBe 'üvar quicksort = function () {'
expect(editor.lineTextForBufferRow(0)).toBe 'üvar quicksort = function () {'
it "does not handle input events when input is disabled", ->
component.setInputEnabled(false)
componentNode.dispatchEvent(buildTextInputEvent(data: 'x', target: inputNode))
expect(nextAnimationFrame).toBe noAnimationFrame
expect(editor.lineForBufferRow(0)).toBe 'var quicksort = function () {'
expect(editor.lineTextForBufferRow(0)).toBe 'var quicksort = function () {'
describe "when IME composition is used to insert international characters", ->
inputNode = null
@@ -1822,46 +1866,46 @@ describe "EditorComponent", ->
it "inserts the chosen completion", ->
componentNode.dispatchEvent(buildIMECompositionEvent('compositionstart', target: inputNode))
componentNode.dispatchEvent(buildIMECompositionEvent('compositionupdate', data: 's', target: inputNode))
expect(editor.lineForBufferRow(0)).toBe 'svar quicksort = function () {'
expect(editor.lineTextForBufferRow(0)).toBe 'svar quicksort = function () {'
componentNode.dispatchEvent(buildIMECompositionEvent('compositionupdate', data: 'sd', target: inputNode))
expect(editor.lineForBufferRow(0)).toBe 'sdvar quicksort = function () {'
expect(editor.lineTextForBufferRow(0)).toBe 'sdvar quicksort = function () {'
componentNode.dispatchEvent(buildIMECompositionEvent('compositionend', target: inputNode))
componentNode.dispatchEvent(buildTextInputEvent(data: '速度', target: inputNode))
expect(editor.lineForBufferRow(0)).toBe '速度var quicksort = function () {'
expect(editor.lineTextForBufferRow(0)).toBe '速度var quicksort = function () {'
it "reverts back to the original text when the completion helper is dismissed", ->
componentNode.dispatchEvent(buildIMECompositionEvent('compositionstart', target: inputNode))
componentNode.dispatchEvent(buildIMECompositionEvent('compositionupdate', data: 's', target: inputNode))
expect(editor.lineForBufferRow(0)).toBe 'svar quicksort = function () {'
expect(editor.lineTextForBufferRow(0)).toBe 'svar quicksort = function () {'
componentNode.dispatchEvent(buildIMECompositionEvent('compositionupdate', data: 'sd', target: inputNode))
expect(editor.lineForBufferRow(0)).toBe 'sdvar quicksort = function () {'
expect(editor.lineTextForBufferRow(0)).toBe 'sdvar quicksort = function () {'
componentNode.dispatchEvent(buildIMECompositionEvent('compositionend', target: inputNode))
expect(editor.lineForBufferRow(0)).toBe 'var quicksort = function () {'
expect(editor.lineTextForBufferRow(0)).toBe 'var quicksort = function () {'
it "allows multiple accented character to be inserted with the ' on a US international layout", ->
inputNode.value = "'"
inputNode.setSelectionRange(0, 1)
componentNode.dispatchEvent(buildIMECompositionEvent('compositionstart', target: inputNode))
componentNode.dispatchEvent(buildIMECompositionEvent('compositionupdate', data: "'", target: inputNode))
expect(editor.lineForBufferRow(0)).toBe "'var quicksort = function () {"
expect(editor.lineTextForBufferRow(0)).toBe "'var quicksort = function () {"
componentNode.dispatchEvent(buildIMECompositionEvent('compositionend', target: inputNode))
componentNode.dispatchEvent(buildTextInputEvent(data: 'á', target: inputNode))
expect(editor.lineForBufferRow(0)).toBe "ávar quicksort = function () {"
expect(editor.lineTextForBufferRow(0)).toBe "ávar quicksort = function () {"
inputNode.value = "'"
inputNode.setSelectionRange(0, 1)
componentNode.dispatchEvent(buildIMECompositionEvent('compositionstart', target: inputNode))
componentNode.dispatchEvent(buildIMECompositionEvent('compositionupdate', data: "'", target: inputNode))
expect(editor.lineForBufferRow(0)).toBe "á'var quicksort = function () {"
expect(editor.lineTextForBufferRow(0)).toBe "á'var quicksort = function () {"
componentNode.dispatchEvent(buildIMECompositionEvent('compositionend', target: inputNode))
componentNode.dispatchEvent(buildTextInputEvent(data: 'á', target: inputNode))
expect(editor.lineForBufferRow(0)).toBe "áávar quicksort = function () {"
expect(editor.lineTextForBufferRow(0)).toBe "áávar quicksort = function () {"
describe "when a string is selected", ->
beforeEach ->
@@ -1870,25 +1914,25 @@ describe "EditorComponent", ->
it "inserts the chosen completion", ->
componentNode.dispatchEvent(buildIMECompositionEvent('compositionstart', target: inputNode))
componentNode.dispatchEvent(buildIMECompositionEvent('compositionupdate', data: 's', target: inputNode))
expect(editor.lineForBufferRow(0)).toBe 'var ssort = function () {'
expect(editor.lineTextForBufferRow(0)).toBe 'var ssort = function () {'
componentNode.dispatchEvent(buildIMECompositionEvent('compositionupdate', data: 'sd', target: inputNode))
expect(editor.lineForBufferRow(0)).toBe 'var sdsort = function () {'
expect(editor.lineTextForBufferRow(0)).toBe 'var sdsort = function () {'
componentNode.dispatchEvent(buildIMECompositionEvent('compositionend', target: inputNode))
componentNode.dispatchEvent(buildTextInputEvent(data: '速度', target: inputNode))
expect(editor.lineForBufferRow(0)).toBe 'var 速度sort = function () {'
expect(editor.lineTextForBufferRow(0)).toBe 'var 速度sort = function () {'
it "reverts back to the original text when the completion helper is dismissed", ->
componentNode.dispatchEvent(buildIMECompositionEvent('compositionstart', target: inputNode))
componentNode.dispatchEvent(buildIMECompositionEvent('compositionupdate', data: 's', target: inputNode))
expect(editor.lineForBufferRow(0)).toBe 'var ssort = function () {'
expect(editor.lineTextForBufferRow(0)).toBe 'var ssort = function () {'
componentNode.dispatchEvent(buildIMECompositionEvent('compositionupdate', data: 'sd', target: inputNode))
expect(editor.lineForBufferRow(0)).toBe 'var sdsort = function () {'
expect(editor.lineTextForBufferRow(0)).toBe 'var sdsort = function () {'
componentNode.dispatchEvent(buildIMECompositionEvent('compositionend', target: inputNode))
expect(editor.lineForBufferRow(0)).toBe 'var quicksort = function () {'
expect(editor.lineTextForBufferRow(0)).toBe 'var quicksort = function () {'
describe "commands", ->
describe "editor:consolidate-selections", ->
+438 -296
Ver Arquivo
Diferenças do arquivo suprimidas por serem muito extensas Carregar Diff
+2 -2
Ver Arquivo
@@ -253,10 +253,10 @@ describe "Git", ->
statusHandler = jasmine.createSpy('statusHandler')
atom.project.getRepo().on 'status-changed', statusHandler
editor.getBuffer().emit 'path-changed'
editor.getBuffer().emitter.emit 'did-change-path'
expect(statusHandler.callCount).toBe 1
expect(statusHandler).toHaveBeenCalledWith editor.getPath(), 256
editor.getBuffer().emit 'path-changed'
editor.getBuffer().emitter.emit 'did-change-path'
expect(statusHandler.callCount).toBe 1
describe "when a project is deserialized", ->
+18 -18
Ver Arquivo
@@ -275,46 +275,46 @@ describe "LanguageMode", ->
it "folds every foldable line", ->
languageMode.foldAll()
fold1 = editor.lineForScreenRow(0).fold
fold1 = editor.tokenizedLineForScreenRow(0).fold
expect([fold1.getStartRow(), fold1.getEndRow()]).toEqual [0, 12]
fold1.destroy()
fold2 = editor.lineForScreenRow(1).fold
fold2 = editor.tokenizedLineForScreenRow(1).fold
expect([fold2.getStartRow(), fold2.getEndRow()]).toEqual [1, 9]
fold2.destroy()
fold3 = editor.lineForScreenRow(4).fold
fold3 = editor.tokenizedLineForScreenRow(4).fold
expect([fold3.getStartRow(), fold3.getEndRow()]).toEqual [4, 7]
describe ".foldBufferRow(bufferRow)", ->
describe "when bufferRow can be folded", ->
it "creates a fold based on the syntactic region starting at the given row", ->
languageMode.foldBufferRow(1)
fold = editor.lineForScreenRow(1).fold
fold = editor.tokenizedLineForScreenRow(1).fold
expect(fold.getStartRow()).toBe 1
expect(fold.getEndRow()).toBe 9
describe "when bufferRow can't be folded", ->
it "searches upward for the first row that begins a syntatic region containing the given buffer row (and folds it)", ->
languageMode.foldBufferRow(8)
fold = editor.lineForScreenRow(1).fold
fold = editor.tokenizedLineForScreenRow(1).fold
expect(fold.getStartRow()).toBe 1
expect(fold.getEndRow()).toBe 9
describe "when the bufferRow is already folded", ->
it "searches upward for the first row that begins a syntatic region containing the folded row (and folds it)", ->
languageMode.foldBufferRow(2)
expect(editor.lineForScreenRow(1).fold).toBeDefined()
expect(editor.lineForScreenRow(0).fold).not.toBeDefined()
expect(editor.tokenizedLineForScreenRow(1).fold).toBeDefined()
expect(editor.tokenizedLineForScreenRow(0).fold).not.toBeDefined()
languageMode.foldBufferRow(1)
expect(editor.lineForScreenRow(0).fold).toBeDefined()
expect(editor.tokenizedLineForScreenRow(0).fold).toBeDefined()
describe "when the bufferRow is in a multi-line comment", ->
it "searches upward and downward for surrounding comment lines and folds them as a single fold", ->
buffer.insert([1,0], " //this is a comment\n // and\n //more docs\n\n//second comment")
languageMode.foldBufferRow(1)
fold = editor.lineForScreenRow(1).fold
fold = editor.tokenizedLineForScreenRow(1).fold
expect(fold.getStartRow()).toBe 1
expect(fold.getEndRow()).toBe 3
@@ -322,7 +322,7 @@ describe "LanguageMode", ->
it "searches upward for the first row that begins a syntatic region containing the folded row (and folds it)", ->
buffer.insert([1,0], " //this is a single line comment\n")
languageMode.foldBufferRow(1)
fold = editor.lineForScreenRow(0).fold
fold = editor.tokenizedLineForScreenRow(0).fold
expect(fold.getStartRow()).toBe 0
expect(fold.getEndRow()).toBe 13
@@ -357,38 +357,38 @@ describe "LanguageMode", ->
it "folds every foldable line", ->
languageMode.foldAll()
fold1 = editor.lineForScreenRow(0).fold
fold1 = editor.tokenizedLineForScreenRow(0).fold
expect([fold1.getStartRow(), fold1.getEndRow()]).toEqual [0, 19]
fold1.destroy()
fold2 = editor.lineForScreenRow(1).fold
fold2 = editor.tokenizedLineForScreenRow(1).fold
expect([fold2.getStartRow(), fold2.getEndRow()]).toEqual [1, 4]
fold3 = editor.lineForScreenRow(2).fold.destroy()
fold3 = editor.tokenizedLineForScreenRow(2).fold.destroy()
fold4 = editor.lineForScreenRow(3).fold
fold4 = editor.tokenizedLineForScreenRow(3).fold
expect([fold4.getStartRow(), fold4.getEndRow()]).toEqual [6, 8]
describe ".foldAllAtIndentLevel()", ->
it "folds every foldable range at a given indentLevel", ->
languageMode.foldAllAtIndentLevel(2)
fold1 = editor.lineForScreenRow(6).fold
fold1 = editor.tokenizedLineForScreenRow(6).fold
expect([fold1.getStartRow(), fold1.getEndRow()]).toEqual [6, 8]
fold1.destroy()
fold2 = editor.lineForScreenRow(11).fold
fold2 = editor.tokenizedLineForScreenRow(11).fold
expect([fold2.getStartRow(), fold2.getEndRow()]).toEqual [11, 14]
fold2.destroy()
it "does not fold anything but the indentLevel", ->
languageMode.foldAllAtIndentLevel(0)
fold1 = editor.lineForScreenRow(0).fold
fold1 = editor.tokenizedLineForScreenRow(0).fold
expect([fold1.getStartRow(), fold1.getEndRow()]).toEqual [0, 19]
fold1.destroy()
fold2 = editor.lineForScreenRow(5).fold
fold2 = editor.tokenizedLineForScreenRow(5).fold
expect(fold2).toBeFalsy()
describe ".isFoldableAtBufferRow(bufferRow)", ->
+70 -21
Ver Arquivo
@@ -27,42 +27,91 @@ describe "PaneContainer", ->
it "preserves the active pane across serialization, independent of focus", ->
pane3A.activate()
expect(containerA.activePane).toBe pane3A
expect(containerA.getActivePane()).toBe pane3A
containerB = containerA.testSerialization()
[pane1B, pane2B, pane3B] = containerB.getPanes()
expect(containerB.activePane).toBe pane3B
expect(containerB.getActivePane()).toBe pane3B
describe "::activePane", ->
it "does not allow the root pane to be destroyed", ->
container = new PaneContainer
container.getRoot().destroy()
expect(container.getRoot()).toBeDefined()
expect(container.getRoot().isDestroyed()).toBe false
describe "::getActivePane()", ->
[container, pane1, pane2] = []
beforeEach ->
container = new PaneContainer
pane1 = container.root
pane1 = container.getRoot()
it "references the first pane if no pane has been made active", ->
expect(container.activePane).toBe pane1
expect(pane1.active).toBe true
it "returns the first pane if no pane has been made active", ->
expect(container.getActivePane()).toBe pane1
expect(pane1.isActive()).toBe true
it "references the most pane on which ::activate was most recently called", ->
it "returns the most pane on which ::activate() was most recently called", ->
pane2 = pane1.splitRight()
pane2.activate()
expect(container.activePane).toBe pane2
expect(pane1.active).toBe false
expect(pane2.active).toBe true
expect(container.getActivePane()).toBe pane2
expect(pane1.isActive()).toBe false
expect(pane2.isActive()).toBe true
pane1.activate()
expect(container.activePane).toBe pane1
expect(pane1.active).toBe true
expect(pane2.active).toBe false
expect(container.getActivePane()).toBe pane1
expect(pane1.isActive()).toBe true
expect(pane2.isActive()).toBe false
it "is reassigned to the next pane if the current active pane is destroyed", ->
it "returns the next pane if the current active pane is destroyed", ->
pane2 = pane1.splitRight()
pane2.activate()
pane2.destroy()
expect(container.activePane).toBe pane1
expect(pane1.active).toBe true
expect(container.getActivePane()).toBe pane1
expect(pane1.isActive()).toBe true
it "does not allow the root pane to be destroyed", ->
pane1.destroy()
expect(container.root).toBe pane1
expect(pane1.isDestroyed()).toBe false
describe "::onDidChangeActivePaneItem()", ->
[container, pane1, pane2, observed] = []
beforeEach ->
container = new PaneContainer(root: new Pane(items: [new Object, new Object]))
container.getRoot().splitRight(items: [new Object, new Object])
[pane1, pane2] = container.getPanes()
observed = []
container.onDidChangeActivePaneItem (item) -> observed.push(item)
it "invokes observers when the active item of the active pane changes", ->
pane2.activateNextItem()
pane2.activateNextItem()
expect(observed).toEqual [pane2.itemAtIndex(1), pane2.itemAtIndex(0)]
it "invokes observers when the active pane changes", ->
pane1.activate()
pane2.activate()
expect(observed).toEqual [pane1.itemAtIndex(0), pane2.itemAtIndex(0)]
describe "::observePanes()", ->
it "invokes observers with all current and future panes", ->
container = new PaneContainer
container.getRoot().splitRight()
[pane1, pane2] = container.getPanes()
observed = []
container.observePanes (pane) -> observed.push(pane)
pane3 = pane2.splitDown()
pane4 = pane2.splitRight()
expect(observed).toEqual [pane1, pane2, pane3, pane4]
describe "::observePaneItems()", ->
it "invokes observers with all current and future pane items", ->
container = new PaneContainer(root: new Pane(items: [new Object, new Object]))
container.getRoot().splitRight(items: [new Object])
[pane1, pane2] = container.getPanes()
observed = []
container.observePaneItems (pane) -> observed.push(pane)
pane3 = pane2.splitDown(items: [new Object])
pane3.addItems([new Object, new Object])
expect(observed).toEqual container.getPaneItems()
+218 -107
Ver Arquivo
@@ -21,39 +21,83 @@ describe "Pane", ->
describe "construction", ->
it "sets the active item to the first item", ->
pane = new Pane(items: [new Item("A"), new Item("B")])
expect(pane.activeItem).toBe pane.items[0]
expect(pane.getActiveItem()).toBe pane.itemAtIndex(0)
it "compacts the items array", ->
pane = new Pane(items: [undefined, new Item("A"), null, new Item("B")])
expect(pane.items.length).toBe 2
expect(pane.activeItem).toBe pane.items[0]
expect(pane.getItems().length).toBe 2
expect(pane.getActiveItem()).toBe pane.itemAtIndex(0)
describe "::activate()", ->
[container, pane1, pane2] = []
beforeEach ->
container = new PaneContainer(root: new Pane)
container.getRoot().splitRight()
[pane1, pane2] = container.getPanes()
it "changes the active pane on the container", ->
expect(container.getActivePane()).toBe pane2
pane1.activate()
expect(container.getActivePane()).toBe pane1
pane2.activate()
expect(container.getActivePane()).toBe pane2
it "invokes ::onDidChangeActivePane observers on the container", ->
observed = []
container.onDidChangeActivePane (activePane) -> observed.push(activePane)
pane1.activate()
pane1.activate()
pane2.activate()
pane1.activate()
expect(observed).toEqual [pane1, pane2, pane1]
it "invokes ::onDidChangeActive observers on the relevant panes", ->
observed = []
pane1.onDidChangeActive (active) -> observed.push(active)
pane1.activate()
pane2.activate()
expect(observed).toEqual [true, false]
it "invokes ::onDidActivate() observers", ->
eventCount = 0
pane1.onDidActivate -> eventCount++
pane1.activate()
pane1.activate()
pane2.activate()
expect(eventCount).toBe 2
describe "::addItem(item, index)", ->
it "adds the item at the given index", ->
pane = new Pane(items: [new Item("A"), new Item("B")])
[item1, item2] = pane.items
[item1, item2] = pane.getItems()
item3 = new Item("C")
pane.addItem(item3, 1)
expect(pane.items).toEqual [item1, item3, item2]
expect(pane.getItems()).toEqual [item1, item3, item2]
it "adds the item after the active item ", ->
it "adds the item after the active item if no index is provided", ->
pane = new Pane(items: [new Item("A"), new Item("B"), new Item("C")])
[item1, item2, item3] = pane.items
[item1, item2, item3] = pane.getItems()
pane.activateItem(item2)
item4 = new Item("D")
pane.addItem(item4)
expect(pane.items).toEqual [item1, item2, item4, item3]
expect(pane.getItems()).toEqual [item1, item2, item4, item3]
it "sets the active item after adding the first item", ->
pane = new Pane
item = new Item("A")
events = []
pane.on 'item-added', -> events.push('item-added')
pane.$activeItem.changes.onValue -> events.push('active-item-changed')
pane.addItem(item)
expect(pane.activeItem).toBe item
expect(events).toEqual ['item-added', 'active-item-changed']
expect(pane.getActiveItem()).toBe item
it "invokes ::onDidAddItem() observers", ->
pane = new Pane(items: [new Item("A"), new Item("B")])
events = []
pane.onDidAddItem (event) -> events.push(event)
item = new Item("C")
pane.addItem(item, 1)
expect(events).toEqual [{item, index: 1}]
describe "::activateItem(item)", ->
pane = null
@@ -62,83 +106,102 @@ describe "Pane", ->
pane = new Pane(items: [new Item("A"), new Item("B")])
it "changes the active item to the current item", ->
expect(pane.activeItem).toBe pane.items[0]
pane.activateItem(pane.items[1])
expect(pane.activeItem).toBe pane.items[1]
expect(pane.getActiveItem()).toBe pane.itemAtIndex(0)
pane.activateItem(pane.itemAtIndex(1))
expect(pane.getActiveItem()).toBe pane.itemAtIndex(1)
it "adds the given item if it isn't present in ::items", ->
item = new Item("C")
pane.activateItem(item)
expect(item in pane.items).toBe true
expect(pane.activeItem).toBe item
expect(item in pane.getItems()).toBe true
expect(pane.getActiveItem()).toBe item
it "invokes ::onDidChangeActiveItem() observers", ->
observed = []
pane.onDidChangeActiveItem (item) -> observed.push(item)
pane.activateItem(pane.itemAtIndex(1))
expect(observed).toEqual [pane.itemAtIndex(1)]
describe "::activateNextItem() and ::activatePreviousItem()", ->
it "sets the active item to the next/previous item, looping around at either end", ->
pane = new Pane(items: [new Item("A"), new Item("B"), new Item("C")])
[item1, item2, item3] = pane.items
[item1, item2, item3] = pane.getItems()
expect(pane.activeItem).toBe item1
expect(pane.getActiveItem()).toBe item1
pane.activatePreviousItem()
expect(pane.activeItem).toBe item3
expect(pane.getActiveItem()).toBe item3
pane.activatePreviousItem()
expect(pane.activeItem).toBe item2
expect(pane.getActiveItem()).toBe item2
pane.activateNextItem()
expect(pane.activeItem).toBe item3
expect(pane.getActiveItem()).toBe item3
pane.activateNextItem()
expect(pane.activeItem).toBe item1
expect(pane.getActiveItem()).toBe item1
describe "::activateItemAtIndex(index)", ->
it "activates the item at the given index", ->
pane = new Pane(items: [new Item("A"), new Item("B"), new Item("C")])
[item1, item2, item3] = pane.items
[item1, item2, item3] = pane.getItems()
pane.activateItemAtIndex(2)
expect(pane.activeItem).toBe item3
expect(pane.getActiveItem()).toBe item3
pane.activateItemAtIndex(1)
expect(pane.activeItem).toBe item2
expect(pane.getActiveItem()).toBe item2
pane.activateItemAtIndex(0)
expect(pane.activeItem).toBe item1
expect(pane.getActiveItem()).toBe item1
# Doesn't fail with out-of-bounds indices
pane.activateItemAtIndex(100)
expect(pane.activeItem).toBe item1
expect(pane.getActiveItem()).toBe item1
pane.activateItemAtIndex(-1)
expect(pane.activeItem).toBe item1
expect(pane.getActiveItem()).toBe item1
describe "::destroyItem(item)", ->
[pane, item1, item2, item3] = []
beforeEach ->
pane = new Pane(items: [new Item("A"), new Item("B"), new Item("C")])
[item1, item2, item3] = pane.items
[item1, item2, item3] = pane.getItems()
it "removes the item from the items list", ->
expect(pane.activeItem).toBe item1
it "removes the item from the items list and destroyes it", ->
expect(pane.getActiveItem()).toBe item1
pane.destroyItem(item2)
expect(item2 in pane.items).toBe false
expect(pane.activeItem).toBe item1
expect(item2 in pane.getItems()).toBe false
expect(item2.isDestroyed()).toBe true
expect(pane.getActiveItem()).toBe item1
pane.destroyItem(item1)
expect(item1 in pane.items).toBe false
expect(item1 in pane.getItems()).toBe false
expect(item1.isDestroyed()).toBe true
it "invokes ::onWillDestroyItem() observers before destroying the item", ->
events = []
pane.onWillDestroyItem (event) ->
expect(item2.isDestroyed()).toBe false
events.push(event)
pane.destroyItem(item2)
expect(item2.isDestroyed()).toBe true
expect(events).toEqual [{item: item2, index: 1}]
it "invokes ::onDidRemoveItem() observers", ->
events = []
pane.onDidRemoveItem (event) -> events.push(event)
pane.destroyItem(item2)
expect(events).toEqual [{item: item2, index: 1, destroyed: true}]
describe "when the destroyed item is the active item and is the first item", ->
it "activates the next item", ->
expect(pane.activeItem).toBe item1
expect(pane.getActiveItem()).toBe item1
pane.destroyItem(item1)
expect(pane.activeItem).toBe item2
expect(pane.getActiveItem()).toBe item2
describe "when the destroyed item is the active item and is not the first item", ->
beforeEach ->
pane.activateItem(item2)
it "activates the previous item", ->
expect(pane.activeItem).toBe item2
expect(pane.getActiveItem()).toBe item2
pane.destroyItem(item2)
expect(pane.activeItem).toBe item1
it "emits 'item-removed' with the item, its index, and true indicating the item is being destroyed", ->
pane.on 'item-removed', itemRemovedHandler = jasmine.createSpy("itemRemovedHandler")
pane.destroyItem(item2)
expect(itemRemovedHandler).toHaveBeenCalledWith(item2, 1, true)
expect(pane.getActiveItem()).toBe item1
describe "if the item is modified", ->
itemUri = null
@@ -157,7 +220,7 @@ describe "Pane", ->
pane.destroyItem(item1)
expect(item1.save).toHaveBeenCalled()
expect(item1 in pane.items).toBe false
expect(item1 in pane.getItems()).toBe false
expect(item1.isDestroyed()).toBe true
describe "when the item has no uri", ->
@@ -170,7 +233,7 @@ describe "Pane", ->
expect(atom.showSaveDialogSync).toHaveBeenCalled()
expect(item1.saveAs).toHaveBeenCalledWith("/selected/path")
expect(item1 in pane.items).toBe false
expect(item1 in pane.getItems()).toBe false
expect(item1.isDestroyed()).toBe true
describe "if the [Don't Save] option is selected", ->
@@ -179,7 +242,7 @@ describe "Pane", ->
pane.destroyItem(item1)
expect(item1.save).not.toHaveBeenCalled()
expect(item1 in pane.items).toBe false
expect(item1 in pane.getItems()).toBe false
expect(item1.isDestroyed()).toBe true
describe "if the [Cancel] option is selected", ->
@@ -188,7 +251,7 @@ describe "Pane", ->
pane.destroyItem(item1)
expect(item1.save).not.toHaveBeenCalled()
expect(item1 in pane.items).toBe true
expect(item1 in pane.getItems()).toBe true
expect(item1.isDestroyed()).toBe false
describe "when the last item is destroyed", ->
@@ -197,7 +260,7 @@ describe "Pane", ->
expect(atom.config.get('core.destroyEmptyPanes')).toBe false
pane.destroyItem(item) for item in pane.getItems()
expect(pane.isDestroyed()).toBe false
expect(pane.activeItem).toBeUndefined()
expect(pane.getActiveItem()).toBeUndefined()
expect(-> pane.saveActiveItem()).not.toThrow()
expect(-> pane.saveActiveItemAs()).not.toThrow()
@@ -210,10 +273,10 @@ describe "Pane", ->
describe "::destroyActiveItem()", ->
it "destroys the active item", ->
pane = new Pane(items: [new Item("A"), new Item("B")])
activeItem = pane.activeItem
activeItem = pane.getActiveItem()
pane.destroyActiveItem()
expect(activeItem.isDestroyed()).toBe true
expect(activeItem in pane.items).toBe false
expect(activeItem in pane.getItems()).toBe false
it "does not throw an exception if there are no more items", ->
pane = new Pane
@@ -222,27 +285,40 @@ describe "Pane", ->
describe "::destroyItems()", ->
it "destroys all items", ->
pane = new Pane(items: [new Item("A"), new Item("B"), new Item("C")])
[item1, item2, item3] = pane.items
[item1, item2, item3] = pane.getItems()
pane.destroyItems()
expect(item1.isDestroyed()).toBe true
expect(item2.isDestroyed()).toBe true
expect(item3.isDestroyed()).toBe true
expect(pane.items).toEqual []
expect(pane.getItems()).toEqual []
describe "::observeItems()", ->
it "invokes the observer with all current and future items", ->
pane = new Pane(items: [new Item, new Item])
[item1, item2] = pane.getItems()
observed = []
pane.observeItems (item) -> observed.push(item)
item3 = new Item
pane.addItem(item3)
expect(observed).toEqual [item1, item2, item3]
describe "when an item emits a destroyed event", ->
it "removes it from the list of items", ->
pane = new Pane(items: [new Item("A"), new Item("B"), new Item("C")])
[item1, item2, item3] = pane.items
pane.items[1].destroy()
expect(pane.items).toEqual [item1, item3]
[item1, item2, item3] = pane.getItems()
pane.itemAtIndex(1).destroy()
expect(pane.getItems()).toEqual [item1, item3]
describe "::destroyInactiveItems()", ->
it "destroys all items but the active item", ->
pane = new Pane(items: [new Item("A"), new Item("B"), new Item("C")])
[item1, item2, item3] = pane.items
[item1, item2, item3] = pane.getItems()
pane.activateItem(item2)
pane.destroyInactiveItems()
expect(pane.items).toEqual [item2]
expect(pane.getItems()).toEqual [item2]
describe "::saveActiveItem()", ->
pane = null
@@ -253,30 +329,30 @@ describe "Pane", ->
describe "when the active item has a uri", ->
beforeEach ->
pane.activeItem.uri = "test"
pane.getActiveItem().uri = "test"
describe "when the active item has a save method", ->
it "saves the current item", ->
pane.activeItem.save = jasmine.createSpy("save")
pane.getActiveItem().save = jasmine.createSpy("save")
pane.saveActiveItem()
expect(pane.activeItem.save).toHaveBeenCalled()
expect(pane.getActiveItem().save).toHaveBeenCalled()
describe "when the current item has no save method", ->
it "does nothing", ->
expect(pane.activeItem.save).toBeUndefined()
expect(pane.getActiveItem().save).toBeUndefined()
pane.saveActiveItem()
describe "when the current item has no uri", ->
describe "when the current item has a saveAs method", ->
it "opens a save dialog and saves the current item as the selected path", ->
pane.activeItem.saveAs = jasmine.createSpy("saveAs")
pane.getActiveItem().saveAs = jasmine.createSpy("saveAs")
pane.saveActiveItem()
expect(atom.showSaveDialogSync).toHaveBeenCalled()
expect(pane.activeItem.saveAs).toHaveBeenCalledWith('/selected/path')
expect(pane.getActiveItem().saveAs).toHaveBeenCalledWith('/selected/path')
describe "when the current item has no saveAs method", ->
it "does nothing", ->
expect(pane.activeItem.saveAs).toBeUndefined()
expect(pane.getActiveItem().saveAs).toBeUndefined()
pane.saveActiveItem()
expect(atom.showSaveDialogSync).not.toHaveBeenCalled()
@@ -289,22 +365,22 @@ describe "Pane", ->
describe "when the current item has a saveAs method", ->
it "opens the save dialog and calls saveAs on the item with the selected path", ->
pane.activeItem.path = __filename
pane.activeItem.saveAs = jasmine.createSpy("saveAs")
pane.getActiveItem().path = __filename
pane.getActiveItem().saveAs = jasmine.createSpy("saveAs")
pane.saveActiveItemAs()
expect(atom.showSaveDialogSync).toHaveBeenCalledWith(__filename)
expect(pane.activeItem.saveAs).toHaveBeenCalledWith('/selected/path')
expect(pane.getActiveItem().saveAs).toHaveBeenCalledWith('/selected/path')
describe "when the current item does not have a saveAs method", ->
it "does nothing", ->
expect(pane.activeItem.saveAs).toBeUndefined()
expect(pane.getActiveItem().saveAs).toBeUndefined()
pane.saveActiveItemAs()
expect(atom.showSaveDialogSync).not.toHaveBeenCalled()
describe "::itemForUri(uri)", ->
it "returns the item for which a call to .getUri() returns the given uri", ->
pane = new Pane(items: [new Item("A"), new Item("B"), new Item("C"), new Item("D")])
[item1, item2, item3] = pane.items
[item1, item2, item3] = pane.getItems()
item1.uri = "a"
item2.uri = "b"
expect(pane.itemForUri("a")).toBe item1
@@ -312,24 +388,32 @@ describe "Pane", ->
expect(pane.itemForUri("bogus")).toBeUndefined()
describe "::moveItem(item, index)", ->
it "moves the item to the given index and emits an 'item-moved' event with the item and its new index", ->
pane = new Pane(items: [new Item("A"), new Item("B"), new Item("C"), new Item("D")])
[item1, item2, item3, item4] = pane.items
pane.on 'item-moved', itemMovedHandler = jasmine.createSpy("itemMovedHandler")
[pane, item1, item2, item3, item4] = []
beforeEach ->
pane = new Pane(items: [new Item("A"), new Item("B"), new Item("C"), new Item("D")])
[item1, item2, item3, item4] = pane.getItems()
it "moves the item to the given index and invokes ::onDidMoveItem observers", ->
pane.moveItem(item1, 2)
expect(pane.getItems()).toEqual [item2, item3, item1, item4]
expect(itemMovedHandler).toHaveBeenCalledWith(item1, 2)
itemMovedHandler.reset()
pane.moveItem(item2, 3)
expect(pane.getItems()).toEqual [item3, item1, item4, item2]
expect(itemMovedHandler).toHaveBeenCalledWith(item2, 3)
itemMovedHandler.reset()
pane.moveItem(item2, 1)
expect(pane.getItems()).toEqual [item3, item2, item1, item4]
expect(itemMovedHandler).toHaveBeenCalledWith(item2, 1)
it "invokes ::onDidMoveItem() observers", ->
events = []
pane.onDidMoveItem (event) -> events.push(event)
pane.moveItem(item1, 2)
pane.moveItem(item2, 3)
expect(events).toEqual [
{item: item1, oldIndex: 0, newIndex: 2}
{item: item2, oldIndex: 0, newIndex: 3}
]
describe "::moveItemToPane(item, pane, index)", ->
[container, pane1, pane2] = []
@@ -339,13 +423,20 @@ describe "Pane", ->
pane1 = new Pane(items: [new Item("A"), new Item("B"), new Item("C")])
container = new PaneContainer(root: pane1)
pane2 = pane1.splitRight(items: [new Item("D"), new Item("E")])
[item1, item2, item3] = pane1.items
[item4, item5] = pane2.items
[item1, item2, item3] = pane1.getItems()
[item4, item5] = pane2.getItems()
it "moves the item to the given pane at the given index", ->
pane1.moveItemToPane(item2, pane2, 1)
expect(pane1.items).toEqual [item1, item3]
expect(pane2.items).toEqual [item4, item2, item5]
expect(pane1.getItems()).toEqual [item1, item3]
expect(pane2.getItems()).toEqual [item4, item2, item5]
it "invokes ::onDidRemoveItem() observers", ->
events = []
pane1.onDidRemoveItem (event) -> events.push(event)
pane1.moveItemToPane(item2, pane2, 1)
expect(events).toEqual [{item: item2, index: 1, destroyed: false}]
describe "when the moved item the last item in the source pane", ->
beforeEach ->
@@ -368,22 +459,27 @@ describe "Pane", ->
[pane1, container] = []
beforeEach ->
pane1 = new Pane(items: ["A"])
pane1 = new Pane(items: [new Item("A")])
container = new PaneContainer(root: pane1)
describe "::splitLeft(params)", ->
describe "when the parent is the container root", ->
it "replaces itself with a row and inserts a new pane to the left of itself", ->
pane2 = pane1.splitLeft(items: ["B"])
pane3 = pane1.splitLeft(items: ["C"])
pane2 = pane1.splitLeft(items: [new Item("B")])
pane3 = pane1.splitLeft(items: [new Item("C")])
expect(container.root.orientation).toBe 'horizontal'
expect(container.root.children).toEqual [pane2, pane3, pane1]
describe "when `copyActiveItem: true` is passed in the params", ->
it "duplicates the active item", ->
pane2 = pane1.splitLeft(copyActiveItem: true)
expect(pane2.getActiveItem()).toEqual pane1.getActiveItem()
describe "when the parent is a column", ->
it "replaces itself with a row and inserts a new pane to the left of itself", ->
pane1.splitDown()
pane2 = pane1.splitLeft(items: ["B"])
pane3 = pane1.splitLeft(items: ["C"])
pane2 = pane1.splitLeft(items: [new Item("B")])
pane3 = pane1.splitLeft(items: [new Item("C")])
row = container.root.children[0]
expect(row.orientation).toBe 'horizontal'
expect(row.children).toEqual [pane2, pane3, pane1]
@@ -391,16 +487,21 @@ describe "Pane", ->
describe "::splitRight(params)", ->
describe "when the parent is the container root", ->
it "replaces itself with a row and inserts a new pane to the right of itself", ->
pane2 = pane1.splitRight(items: ["B"])
pane3 = pane1.splitRight(items: ["C"])
pane2 = pane1.splitRight(items: [new Item("B")])
pane3 = pane1.splitRight(items: [new Item("C")])
expect(container.root.orientation).toBe 'horizontal'
expect(container.root.children).toEqual [pane1, pane3, pane2]
describe "when `copyActiveItem: true` is passed in the params", ->
it "duplicates the active item", ->
pane2 = pane1.splitRight(copyActiveItem: true)
expect(pane2.getActiveItem()).toEqual pane1.getActiveItem()
describe "when the parent is a column", ->
it "replaces itself with a row and inserts a new pane to the right of itself", ->
pane1.splitDown()
pane2 = pane1.splitRight(items: ["B"])
pane3 = pane1.splitRight(items: ["C"])
pane2 = pane1.splitRight(items: [new Item("B")])
pane3 = pane1.splitRight(items: [new Item("C")])
row = container.root.children[0]
expect(row.orientation).toBe 'horizontal'
expect(row.children).toEqual [pane1, pane3, pane2]
@@ -408,16 +509,21 @@ describe "Pane", ->
describe "::splitUp(params)", ->
describe "when the parent is the container root", ->
it "replaces itself with a column and inserts a new pane above itself", ->
pane2 = pane1.splitUp(items: ["B"])
pane3 = pane1.splitUp(items: ["C"])
pane2 = pane1.splitUp(items: [new Item("B")])
pane3 = pane1.splitUp(items: [new Item("C")])
expect(container.root.orientation).toBe 'vertical'
expect(container.root.children).toEqual [pane2, pane3, pane1]
describe "when `copyActiveItem: true` is passed in the params", ->
it "duplicates the active item", ->
pane2 = pane1.splitUp(copyActiveItem: true)
expect(pane2.getActiveItem()).toEqual pane1.getActiveItem()
describe "when the parent is a row", ->
it "replaces itself with a column and inserts a new pane above itself", ->
pane1.splitRight()
pane2 = pane1.splitUp(items: ["B"])
pane3 = pane1.splitUp(items: ["C"])
pane2 = pane1.splitUp(items: [new Item("B")])
pane3 = pane1.splitUp(items: [new Item("C")])
column = container.root.children[0]
expect(column.orientation).toBe 'vertical'
expect(column.children).toEqual [pane2, pane3, pane1]
@@ -425,16 +531,21 @@ describe "Pane", ->
describe "::splitDown(params)", ->
describe "when the parent is the container root", ->
it "replaces itself with a column and inserts a new pane below itself", ->
pane2 = pane1.splitDown(items: ["B"])
pane3 = pane1.splitDown(items: ["C"])
pane2 = pane1.splitDown(items: [new Item("B")])
pane3 = pane1.splitDown(items: [new Item("C")])
expect(container.root.orientation).toBe 'vertical'
expect(container.root.children).toEqual [pane1, pane3, pane2]
describe "when `copyActiveItem: true` is passed in the params", ->
it "duplicates the active item", ->
pane2 = pane1.splitDown(copyActiveItem: true)
expect(pane2.getActiveItem()).toEqual pane1.getActiveItem()
describe "when the parent is a row", ->
it "replaces itself with a column and inserts a new pane below itself", ->
pane1.splitRight()
pane2 = pane1.splitDown(items: ["B"])
pane3 = pane1.splitDown(items: ["C"])
pane2 = pane1.splitDown(items: [new Item("B")])
pane3 = pane1.splitDown(items: [new Item("C")])
column = container.root.children[0]
expect(column.orientation).toBe 'vertical'
expect(column.children).toEqual [pane1, pane3, pane2]
@@ -455,7 +566,7 @@ describe "Pane", ->
pane2 = pane1.splitRight()
it "destroys the pane's destroyable items", ->
[item1, item2] = pane1.items
[item1, item2] = pane1.getItems()
pane1.destroy()
expect(item1.isDestroyed()).toBe true
expect(item2.isDestroyed()).toBe true
@@ -493,12 +604,12 @@ describe "Pane", ->
it "can serialize and deserialize the pane and all its items", ->
newPane = pane.testSerialization()
expect(newPane.items).toEqual pane.items
expect(newPane.getItems()).toEqual pane.getItems()
it "restores the active item on deserialization", ->
pane.activateItemAtIndex(1)
newPane = pane.testSerialization()
expect(newPane.activeItem).toEqual newPane.items[1]
expect(newPane.getActiveItem()).toEqual newPane.itemAtIndex(1)
it "does not include items that cannot be deserialized", ->
spyOn(console, 'warn')
@@ -506,8 +617,8 @@ describe "Pane", ->
pane.activateItem(unserializable)
newPane = pane.testSerialization()
expect(newPane.activeItem).toEqual pane.items[0]
expect(newPane.items.length).toBe pane.items.length - 1
expect(newPane.getActiveItem()).toEqual pane.itemAtIndex(0)
expect(newPane.getItems().length).toBe pane.getItems().length - 1
it "includes the pane's focus state in the serialized state", ->
pane.focus()
+6 -6
Ver Arquivo
@@ -29,7 +29,7 @@ describe "PaneView", ->
runs ->
pane = container.getRoot()
paneModel = pane.model
paneModel = pane.getModel()
paneModel.addItems([view1, editor1, view2, editor2])
afterEach ->
@@ -37,7 +37,7 @@ describe "PaneView", ->
describe "when the active pane item changes", ->
it "hides all item views except the active one", ->
expect(pane.activeItem).toBe view1
expect(pane.getActiveItem()).toBe view1
expect(view1.css('display')).not.toBe 'none'
pane.activateItem(view2)
@@ -48,7 +48,7 @@ describe "PaneView", ->
itemChangedHandler = jasmine.createSpy("itemChangedHandler")
container.on 'pane:active-item-changed', itemChangedHandler
expect(pane.activeItem).toBe view1
expect(pane.getActiveItem()).toBe view1
paneModel.activateItem(view2)
paneModel.activateItem(view2)
@@ -149,7 +149,7 @@ describe "PaneView", ->
activeItemTitleChangedHandler = jasmine.createSpy("activeItemTitleChangedHandler")
pane.on 'pane:active-item-title-changed', activeItemTitleChangedHandler
expect(pane.activeItem).toBe view1
expect(pane.getActiveItem()).toBe view1
view2.trigger 'title-changed'
expect(activeItemTitleChangedHandler).not.toHaveBeenCalled()
@@ -246,7 +246,7 @@ describe "PaneView", ->
it "transfers focus to the active view", ->
focusHandler = jasmine.createSpy("focusHandler")
pane.activeItem.on 'focus', focusHandler
pane.getActiveItem().on 'focus', focusHandler
pane.focus()
expect(focusHandler).toHaveBeenCalled()
@@ -259,7 +259,7 @@ describe "PaneView", ->
describe "when a pane is split", ->
it "builds the appropriate pane-row and pane-column views", ->
pane1 = pane
pane1Model = pane.model
pane1Model = pane.getModel()
pane.activateItem(editor1)
pane2Model = pane1Model.splitRight(items: [pane1Model.copyActiveItem()])
+5
Ver Arquivo
@@ -190,6 +190,11 @@ describe "Project", ->
expect(atom.project.getPath()?).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'))
expect(atom.project.getRootDirectory().path).toEqual path.dirname(require.resolve('./fixtures/dir/a'))
describe ".replace()", ->
[filePath, commentFilePath, sampleContent, sampleCommentContent] = []
+2 -2
Ver Arquivo
@@ -35,7 +35,7 @@ describe "Editor", ->
logLines()
throw new Error("Invalid buffer row #{actualBufferRow} for screen row #{screenRow}", )
actualScreenLine = editor.lineForScreenRow(screenRow)
actualScreenLine = editor.tokenizedLineForScreenRow(screenRow)
unless actualScreenLine.text is referenceScreenLine.text
logLines()
throw new Error("Invalid line text at screen row #{screenRow}")
@@ -83,7 +83,7 @@ describe "Editor", ->
screenLines = []
bufferRows = []
for bufferRow in [0..tokenizedBuffer.getLastRow()]
for screenLine in softWrapLine(tokenizedBuffer.lineForScreenRow(bufferRow))
for screenLine in softWrapLine(tokenizedBuffer.tokenizedLineForRow(bufferRow))
screenLines.push(screenLine)
bufferRows.push(bufferRow)
else
+1 -1
Ver Arquivo
@@ -6,7 +6,7 @@ describe "Selection", ->
beforeEach ->
buffer = atom.project.bufferForPathSync('sample.js')
editor = new Editor(buffer: buffer, tabLength: 2)
selection = editor.getSelection()
selection = editor.getLastSelection()
afterEach ->
buffer.destroy()
-1
Ver Arquivo
@@ -138,7 +138,6 @@ afterEach ->
jasmine.unspy(atom, 'saveSync')
ensureNoPathSubscriptions()
atom.syntax.off()
ensureNoDeprecatedFunctionsCalled() if isCoreSpec
waits(0) # yield to ui thread to make screen update more frequently
ensureNoPathSubscriptions = ->
+154 -155
Ver Arquivo
@@ -49,38 +49,38 @@ describe "TokenizedBuffer", ->
describe "on construction", ->
it "initially creates un-tokenized screen lines, then tokenizes lines chunk at a time in the background", ->
line0 = tokenizedBuffer.lineForScreenRow(0)
line0 = tokenizedBuffer.tokenizedLineForRow(0)
expect(line0.tokens.length).toBe 1
expect(line0.tokens[0]).toEqual(value: line0.text, scopes: ['source.js'])
line11 = tokenizedBuffer.lineForScreenRow(11)
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'])
# background tokenization has not begun
expect(tokenizedBuffer.lineForScreenRow(0).ruleStack).toBeUndefined()
expect(tokenizedBuffer.tokenizedLineForRow(0).ruleStack).toBeUndefined()
# tokenize chunk 1
advanceClock()
expect(tokenizedBuffer.lineForScreenRow(0).ruleStack?).toBeTruthy()
expect(tokenizedBuffer.lineForScreenRow(4).ruleStack?).toBeTruthy()
expect(tokenizedBuffer.lineForScreenRow(5).ruleStack?).toBeFalsy()
expect(tokenizedBuffer.tokenizedLineForRow(0).ruleStack?).toBeTruthy()
expect(tokenizedBuffer.tokenizedLineForRow(4).ruleStack?).toBeTruthy()
expect(tokenizedBuffer.tokenizedLineForRow(5).ruleStack?).toBeFalsy()
expect(changeHandler).toHaveBeenCalledWith(start: 0, end: 4, delta: 0)
changeHandler.reset()
# tokenize chunk 2
advanceClock()
expect(tokenizedBuffer.lineForScreenRow(5).ruleStack?).toBeTruthy()
expect(tokenizedBuffer.lineForScreenRow(9).ruleStack?).toBeTruthy()
expect(tokenizedBuffer.lineForScreenRow(10).ruleStack?).toBeFalsy()
expect(tokenizedBuffer.tokenizedLineForRow(5).ruleStack?).toBeTruthy()
expect(tokenizedBuffer.tokenizedLineForRow(9).ruleStack?).toBeTruthy()
expect(tokenizedBuffer.tokenizedLineForRow(10).ruleStack?).toBeFalsy()
expect(changeHandler).toHaveBeenCalledWith(start: 5, end: 9, delta: 0)
changeHandler.reset()
# tokenize last chunk
advanceClock()
expect(tokenizedBuffer.lineForScreenRow(10).ruleStack?).toBeTruthy()
expect(tokenizedBuffer.lineForScreenRow(12).ruleStack?).toBeTruthy()
expect(tokenizedBuffer.tokenizedLineForRow(10).ruleStack?).toBeTruthy()
expect(tokenizedBuffer.tokenizedLineForRow(12).ruleStack?).toBeTruthy()
expect(changeHandler).toHaveBeenCalledWith(start: 10, end: 12, delta: 0)
describe "when the buffer is partially tokenized", ->
@@ -134,8 +134,8 @@ describe "TokenizedBuffer", ->
expect(tokenizedBuffer.firstInvalidRow()).toBe 5
buffer.setTextInRange([[6, 0], [7, 0]], "\n\n\n")
expect(tokenizedBuffer.lineForScreenRow(6).ruleStack?).toBeFalsy()
expect(tokenizedBuffer.lineForScreenRow(7).ruleStack?).toBeFalsy()
expect(tokenizedBuffer.tokenizedLineForRow(6).ruleStack?).toBeFalsy()
expect(tokenizedBuffer.tokenizedLineForRow(7).ruleStack?).toBeFalsy()
changeHandler.reset()
expect(tokenizedBuffer.firstInvalidRow()).toBe 5
@@ -149,10 +149,10 @@ describe "TokenizedBuffer", ->
it "updates tokens to reflect the change", ->
buffer.setTextInRange([[0, 0], [2, 0]], "foo()\n7\n")
expect(tokenizedBuffer.lineForScreenRow(0).tokens[1]).toEqual(value: '(', scopes: ['source.js', 'meta.brace.round.js'])
expect(tokenizedBuffer.lineForScreenRow(1).tokens[0]).toEqual(value: '7', scopes: ['source.js', 'constant.numeric.js'])
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'])
# line 2 is unchanged
expect(tokenizedBuffer.lineForScreenRow(2).tokens[2]).toEqual(value: 'if', scopes: ['source.js', 'keyword.control.js'])
expect(tokenizedBuffer.tokenizedLineForRow(2).tokens[2]).toEqual(value: 'if', scopes: ['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.lineForScreenRow(3).tokens[0].scopes).toEqual ['source.js']
expect(tokenizedBuffer.tokenizedLineForRow(3).tokens[0].scopes).toEqual ['source.js']
expect(changeHandler).toHaveBeenCalled()
[event] = changeHandler.argsForCall[0]
delete event.bufferChange
@@ -172,9 +172,9 @@ describe "TokenizedBuffer", ->
changeHandler.reset()
advanceClock()
expect(tokenizedBuffer.lineForScreenRow(3).tokens[0].scopes).toEqual ['source.js', 'comment.block.js']
expect(tokenizedBuffer.lineForScreenRow(4).tokens[0].scopes).toEqual ['source.js', 'comment.block.js']
expect(tokenizedBuffer.lineForScreenRow(5).tokens[0].scopes).toEqual ['source.js', 'comment.block.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', '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.lineForScreenRow(1).tokens[0].scopes).toEqual ['source.js', 'comment.block.js']
expect(tokenizedBuffer.tokenizedLineForRow(1).tokens[0].scopes).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.lineForScreenRow(0).tokens[0]).toEqual(value: 'var', scopes: ['source.js', 'storage.modifier.js'])
expect(tokenizedBuffer.tokenizedLineForRow(0).tokens[0]).toEqual(value: 'var', scopes: ['source.js', 'storage.modifier.js'])
# previous line 3 should be combined with input to form line 1
expect(tokenizedBuffer.lineForScreenRow(1).tokens[0]).toEqual(value: 'foo', scopes: ['source.js'])
expect(tokenizedBuffer.lineForScreenRow(1).tokens[6]).toEqual(value: '=', scopes: ['source.js', 'keyword.operator.js'])
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'])
# lines below deleted regions should be shifted upward
expect(tokenizedBuffer.lineForScreenRow(2).tokens[2]).toEqual(value: 'while', scopes: ['source.js', 'keyword.control.js'])
expect(tokenizedBuffer.lineForScreenRow(3).tokens[4]).toEqual(value: '=', scopes: ['source.js', 'keyword.operator.js'])
expect(tokenizedBuffer.lineForScreenRow(4).tokens[4]).toEqual(value: '<', scopes: ['source.js', 'keyword.operator.js'])
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(changeHandler).toHaveBeenCalled()
[event] = changeHandler.argsForCall[0]
@@ -214,8 +214,8 @@ describe "TokenizedBuffer", ->
changeHandler.reset()
buffer.setTextInRange([[2, 0], [3, 0]], '/*')
expect(tokenizedBuffer.lineForScreenRow(2).tokens[0].scopes).toEqual ['source.js', 'comment.block.js', 'punctuation.definition.comment.js']
expect(tokenizedBuffer.lineForScreenRow(3).tokens[0].scopes).toEqual ['source.js']
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(changeHandler).toHaveBeenCalled()
[event] = changeHandler.argsForCall[0]
delete event.bufferChange
@@ -223,8 +223,8 @@ describe "TokenizedBuffer", ->
changeHandler.reset()
advanceClock()
expect(tokenizedBuffer.lineForScreenRow(3).tokens[0].scopes).toEqual ['source.js', 'comment.block.js']
expect(tokenizedBuffer.lineForScreenRow(4).tokens[0].scopes).toEqual ['source.js', 'comment.block.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(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.lineForScreenRow(0).tokens[0]).toEqual( value: 'var', scopes: ['source.js', 'storage.modifier.js'])
expect(tokenizedBuffer.tokenizedLineForRow(0).tokens[0]).toEqual( value: 'var', scopes: ['source.js', 'storage.modifier.js'])
# 3 new lines inserted
expect(tokenizedBuffer.lineForScreenRow(1).tokens[0]).toEqual(value: 'foo', scopes: ['source.js'])
expect(tokenizedBuffer.lineForScreenRow(2).tokens[0]).toEqual(value: 'bar', scopes: ['source.js'])
expect(tokenizedBuffer.lineForScreenRow(3).tokens[0]).toEqual(value: 'baz', scopes: ['source.js'])
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'])
# previous line 2 is joined with quux() on line 4
expect(tokenizedBuffer.lineForScreenRow(4).tokens[0]).toEqual(value: 'quux', scopes: ['source.js'])
expect(tokenizedBuffer.lineForScreenRow(4).tokens[4]).toEqual(value: 'if', scopes: ['source.js', 'keyword.control.js'])
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'])
# previous line 3 is pushed down to become line 5
expect(tokenizedBuffer.lineForScreenRow(5).tokens[4]).toEqual(value: '=', scopes: ['source.js', 'keyword.operator.js'])
expect(tokenizedBuffer.tokenizedLineForRow(5).tokens[4]).toEqual(value: '=', scopes: ['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.lineForScreenRow(2).tokens[0].scopes).toEqual ['source.js', 'comment.block.js', 'punctuation.definition.comment.js']
expect(tokenizedBuffer.lineForScreenRow(3).tokens[0].scopes).toEqual ['source.js', 'comment.block.js']
expect(tokenizedBuffer.lineForScreenRow(4).tokens[0].scopes).toEqual ['source.js', 'comment.block.js']
expect(tokenizedBuffer.lineForScreenRow(5).tokens[0].scopes).toEqual ['source.js']
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']
changeHandler.reset()
advanceClock() # tokenize invalidated lines in background
expect(tokenizedBuffer.lineForScreenRow(5).tokens[0].scopes).toEqual ['source.js', 'comment.block.js']
expect(tokenizedBuffer.lineForScreenRow(6).tokens[0].scopes).toEqual ['source.js', 'comment.block.js']
expect(tokenizedBuffer.lineForScreenRow(7).tokens[0].scopes).toEqual ['source.js', 'comment.block.js']
expect(tokenizedBuffer.lineForScreenRow(8).tokens[0].scopes).not.toBe ['source.js', 'comment.block.js']
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(changeHandler).toHaveBeenCalled()
[event] = changeHandler.argsForCall[0]
@@ -285,13 +285,13 @@ describe "TokenizedBuffer", ->
it "tokenizes the initial chunk synchronously, then tokenizes the remaining lines in the background", ->
commentBlock = _.multiplyString("// a comment\n", tokenizedBuffer.chunkSize + 2)
buffer.insert([0,0], commentBlock)
expect(tokenizedBuffer.lineForScreenRow(0).ruleStack?).toBeTruthy()
expect(tokenizedBuffer.lineForScreenRow(4).ruleStack?).toBeTruthy()
expect(tokenizedBuffer.lineForScreenRow(5).ruleStack?).toBeFalsy()
expect(tokenizedBuffer.tokenizedLineForRow(0).ruleStack?).toBeTruthy()
expect(tokenizedBuffer.tokenizedLineForRow(4).ruleStack?).toBeTruthy()
expect(tokenizedBuffer.tokenizedLineForRow(5).ruleStack?).toBeFalsy()
advanceClock()
expect(tokenizedBuffer.lineForScreenRow(5).ruleStack?).toBeTruthy()
expect(tokenizedBuffer.lineForScreenRow(6).ruleStack?).toBeTruthy()
expect(tokenizedBuffer.tokenizedLineForRow(5).ruleStack?).toBeTruthy()
expect(tokenizedBuffer.tokenizedLineForRow(6).ruleStack?).toBeTruthy()
describe ".findOpeningBracket(closingBufferPosition)", ->
it "returns the position of the matching bracket, skipping any nested brackets", ->
@@ -302,18 +302,18 @@ describe "TokenizedBuffer", ->
expect(tokenizedBuffer.findClosingBracket([1, 29])).toEqual [9, 2]
it "tokenizes leading whitespace based on the new tab length", ->
expect(tokenizedBuffer.lineForScreenRow(5).tokens[0].isAtomic).toBeTruthy()
expect(tokenizedBuffer.lineForScreenRow(5).tokens[0].value).toBe " "
expect(tokenizedBuffer.lineForScreenRow(5).tokens[1].isAtomic).toBeTruthy()
expect(tokenizedBuffer.lineForScreenRow(5).tokens[1].value).toBe " "
expect(tokenizedBuffer.tokenizedLineForRow(5).tokens[0].isAtomic).toBeTruthy()
expect(tokenizedBuffer.tokenizedLineForRow(5).tokens[0].value).toBe " "
expect(tokenizedBuffer.tokenizedLineForRow(5).tokens[1].isAtomic).toBeTruthy()
expect(tokenizedBuffer.tokenizedLineForRow(5).tokens[1].value).toBe " "
tokenizedBuffer.setTabLength(4)
fullyTokenize(tokenizedBuffer)
expect(tokenizedBuffer.lineForScreenRow(5).tokens[0].isAtomic).toBeTruthy()
expect(tokenizedBuffer.lineForScreenRow(5).tokens[0].value).toBe " "
expect(tokenizedBuffer.lineForScreenRow(5).tokens[1].isAtomic).toBeFalsy()
expect(tokenizedBuffer.lineForScreenRow(5).tokens[1].value).toBe " current "
expect(tokenizedBuffer.tokenizedLineForRow(5).tokens[0].isAtomic).toBeTruthy()
expect(tokenizedBuffer.tokenizedLineForRow(5).tokens[0].value).toBe " "
expect(tokenizedBuffer.tokenizedLineForRow(5).tokens[1].isAtomic).toBeFalsy()
expect(tokenizedBuffer.tokenizedLineForRow(5).tokens[1].value).toBe " current "
describe "when the buffer contains hard-tabs", ->
beforeEach ->
@@ -335,7 +335,7 @@ describe "TokenizedBuffer", ->
it "renders each tab as its own atomic token with a value of size tabLength", ->
tabAsSpaces = _.multiplyString(' ', tokenizedBuffer.getTabLength())
screenLine0 = tokenizedBuffer.lineForScreenRow(0)
screenLine0 = tokenizedBuffer.tokenizedLineForRow(0)
expect(screenLine0.text).toBe "# Econ 101#{tabAsSpaces}"
{ tokens } = screenLine0
@@ -347,7 +347,7 @@ describe "TokenizedBuffer", ->
expect(tokens[2].isAtomic).toBeTruthy()
expect(tokens[3].value).toBe ""
expect(tokenizedBuffer.lineForScreenRow(2).text).toBe "#{tabAsSpaces} buy()#{tabAsSpaces}while supply > demand"
expect(tokenizedBuffer.tokenizedLineForRow(2).text).toBe "#{tabAsSpaces} buy()#{tabAsSpaces}while supply > demand"
it "aligns the hard tabs to the correct tab stop column", ->
buffer.setText """
@@ -359,62 +359,62 @@ describe "TokenizedBuffer", ->
tokenizedBuffer.setTabLength(4)
fullyTokenize(tokenizedBuffer)
expect(tokenizedBuffer.lineForScreenRow(0).text).toBe "1 2 3 4"
expect(tokenizedBuffer.lineForScreenRow(0).tokens[1].bufferDelta).toBe 1
expect(tokenizedBuffer.lineForScreenRow(0).tokens[1].screenDelta).toBe 3
expect(tokenizedBuffer.tokenizedLineForRow(0).text).toBe "1 2 3 4"
expect(tokenizedBuffer.tokenizedLineForRow(0).tokens[1].bufferDelta).toBe 1
expect(tokenizedBuffer.tokenizedLineForRow(0).tokens[1].screenDelta).toBe 3
expect(tokenizedBuffer.lineForScreenRow(1).text).toBe "12 3 4 5"
expect(tokenizedBuffer.lineForScreenRow(1).tokens[1].bufferDelta).toBe 1
expect(tokenizedBuffer.lineForScreenRow(1).tokens[1].screenDelta).toBe 2
expect(tokenizedBuffer.tokenizedLineForRow(1).text).toBe "12 3 4 5"
expect(tokenizedBuffer.tokenizedLineForRow(1).tokens[1].bufferDelta).toBe 1
expect(tokenizedBuffer.tokenizedLineForRow(1).tokens[1].screenDelta).toBe 2
expect(tokenizedBuffer.lineForScreenRow(2).text).toBe "123 4 5 6"
expect(tokenizedBuffer.lineForScreenRow(2).tokens[1].bufferDelta).toBe 1
expect(tokenizedBuffer.lineForScreenRow(2).tokens[1].screenDelta).toBe 1
expect(tokenizedBuffer.tokenizedLineForRow(2).text).toBe "123 4 5 6"
expect(tokenizedBuffer.tokenizedLineForRow(2).tokens[1].bufferDelta).toBe 1
expect(tokenizedBuffer.tokenizedLineForRow(2).tokens[1].screenDelta).toBe 1
tokenizedBuffer.setTabLength(3)
fullyTokenize(tokenizedBuffer)
expect(tokenizedBuffer.lineForScreenRow(0).text).toBe "1 2 3 4"
expect(tokenizedBuffer.lineForScreenRow(0).tokens[1].bufferDelta).toBe 1
expect(tokenizedBuffer.lineForScreenRow(0).tokens[1].screenDelta).toBe 2
expect(tokenizedBuffer.tokenizedLineForRow(0).text).toBe "1 2 3 4"
expect(tokenizedBuffer.tokenizedLineForRow(0).tokens[1].bufferDelta).toBe 1
expect(tokenizedBuffer.tokenizedLineForRow(0).tokens[1].screenDelta).toBe 2
expect(tokenizedBuffer.lineForScreenRow(1).text).toBe "12 3 4 5"
expect(tokenizedBuffer.lineForScreenRow(1).tokens[1].bufferDelta).toBe 1
expect(tokenizedBuffer.lineForScreenRow(1).tokens[1].screenDelta).toBe 1
expect(tokenizedBuffer.tokenizedLineForRow(1).text).toBe "12 3 4 5"
expect(tokenizedBuffer.tokenizedLineForRow(1).tokens[1].bufferDelta).toBe 1
expect(tokenizedBuffer.tokenizedLineForRow(1).tokens[1].screenDelta).toBe 1
expect(tokenizedBuffer.lineForScreenRow(2).text).toBe "123 4 5 6"
expect(tokenizedBuffer.lineForScreenRow(2).tokens[1].bufferDelta).toBe 1
expect(tokenizedBuffer.lineForScreenRow(2).tokens[1].screenDelta).toBe 3
expect(tokenizedBuffer.tokenizedLineForRow(2).text).toBe "123 4 5 6"
expect(tokenizedBuffer.tokenizedLineForRow(2).tokens[1].bufferDelta).toBe 1
expect(tokenizedBuffer.tokenizedLineForRow(2).tokens[1].screenDelta).toBe 3
tokenizedBuffer.setTabLength(2)
fullyTokenize(tokenizedBuffer)
expect(tokenizedBuffer.lineForScreenRow(0).text).toBe "1 2 3 4"
expect(tokenizedBuffer.lineForScreenRow(0).tokens[1].bufferDelta).toBe 1
expect(tokenizedBuffer.lineForScreenRow(0).tokens[1].screenDelta).toBe 1
expect(tokenizedBuffer.tokenizedLineForRow(0).text).toBe "1 2 3 4"
expect(tokenizedBuffer.tokenizedLineForRow(0).tokens[1].bufferDelta).toBe 1
expect(tokenizedBuffer.tokenizedLineForRow(0).tokens[1].screenDelta).toBe 1
expect(tokenizedBuffer.lineForScreenRow(1).text).toBe "12 3 4 5"
expect(tokenizedBuffer.lineForScreenRow(1).tokens[1].bufferDelta).toBe 1
expect(tokenizedBuffer.lineForScreenRow(1).tokens[1].screenDelta).toBe 2
expect(tokenizedBuffer.tokenizedLineForRow(1).text).toBe "12 3 4 5"
expect(tokenizedBuffer.tokenizedLineForRow(1).tokens[1].bufferDelta).toBe 1
expect(tokenizedBuffer.tokenizedLineForRow(1).tokens[1].screenDelta).toBe 2
expect(tokenizedBuffer.lineForScreenRow(2).text).toBe "123 4 5 6"
expect(tokenizedBuffer.lineForScreenRow(2).tokens[1].bufferDelta).toBe 1
expect(tokenizedBuffer.lineForScreenRow(2).tokens[1].screenDelta).toBe 1
expect(tokenizedBuffer.tokenizedLineForRow(2).text).toBe "123 4 5 6"
expect(tokenizedBuffer.tokenizedLineForRow(2).tokens[1].bufferDelta).toBe 1
expect(tokenizedBuffer.tokenizedLineForRow(2).tokens[1].screenDelta).toBe 1
tokenizedBuffer.setTabLength(1)
fullyTokenize(tokenizedBuffer)
expect(tokenizedBuffer.lineForScreenRow(0).text).toBe "1 2 3 4"
expect(tokenizedBuffer.lineForScreenRow(0).tokens[1].bufferDelta).toBe 1
expect(tokenizedBuffer.lineForScreenRow(0).tokens[1].screenDelta).toBe 1
expect(tokenizedBuffer.tokenizedLineForRow(0).text).toBe "1 2 3 4"
expect(tokenizedBuffer.tokenizedLineForRow(0).tokens[1].bufferDelta).toBe 1
expect(tokenizedBuffer.tokenizedLineForRow(0).tokens[1].screenDelta).toBe 1
expect(tokenizedBuffer.lineForScreenRow(1).text).toBe "12 3 4 5"
expect(tokenizedBuffer.lineForScreenRow(1).tokens[1].bufferDelta).toBe 1
expect(tokenizedBuffer.lineForScreenRow(1).tokens[1].screenDelta).toBe 1
expect(tokenizedBuffer.tokenizedLineForRow(1).text).toBe "12 3 4 5"
expect(tokenizedBuffer.tokenizedLineForRow(1).tokens[1].bufferDelta).toBe 1
expect(tokenizedBuffer.tokenizedLineForRow(1).tokens[1].screenDelta).toBe 1
expect(tokenizedBuffer.lineForScreenRow(2).text).toBe "123 4 5 6"
expect(tokenizedBuffer.lineForScreenRow(2).tokens[1].bufferDelta).toBe 1
expect(tokenizedBuffer.lineForScreenRow(2).tokens[1].screenDelta).toBe 1
expect(tokenizedBuffer.tokenizedLineForRow(2).text).toBe "123 4 5 6"
expect(tokenizedBuffer.tokenizedLineForRow(2).tokens[1].bufferDelta).toBe 1
expect(tokenizedBuffer.tokenizedLineForRow(2).tokens[1].screenDelta).toBe 1
describe "when the buffer contains UTF-8 surrogate pairs", ->
beforeEach ->
@@ -435,7 +435,7 @@ describe "TokenizedBuffer", ->
buffer.release()
it "renders each UTF-8 surrogate pair as its own atomic token", ->
screenLine0 = tokenizedBuffer.lineForScreenRow(0)
screenLine0 = tokenizedBuffer.tokenizedLineForRow(0)
expect(screenLine0.text).toBe "'abc\uD835\uDF97def'"
{ tokens } = screenLine0
@@ -447,7 +447,7 @@ describe "TokenizedBuffer", ->
expect(tokens[3].value).toBe "def"
expect(tokens[4].value).toBe "'"
screenLine1 = tokenizedBuffer.lineForScreenRow(1)
screenLine1 = tokenizedBuffer.tokenizedLineForRow(1)
expect(screenLine1.text).toBe "//\uD835\uDF97xyz"
{ tokens } = screenLine1
@@ -525,7 +525,7 @@ describe "TokenizedBuffer", ->
tokenizedBuffer.setGrammar(atom.syntax.selectGrammar('test.erb'))
fullyTokenize(tokenizedBuffer)
{tokens} = tokenizedBuffer.lineForScreenRow(0)
{tokens} = tokenizedBuffer.tokenizedLineForRow(0)
expect(tokens[0]).toEqual value: "<div class='name'>", scopes: ["text.html.ruby"]
waitsForPromise ->
@@ -533,7 +533,7 @@ describe "TokenizedBuffer", ->
runs ->
fullyTokenize(tokenizedBuffer)
{tokens} = tokenizedBuffer.lineForScreenRow(0)
{tokens} = tokenizedBuffer.tokenizedLineForRow(0)
expect(tokens[0]).toEqual value: '<', scopes: ["text.html.ruby","meta.tag.block.any.html","punctuation.definition.tag.begin.html"]
describe ".tokenForPosition(position)", ->
@@ -599,9 +599,9 @@ describe "TokenizedBuffer", ->
tokenizedBuffer.setInvisibles(space: 'S', tab: 'T')
fullyTokenize(tokenizedBuffer)
expect(tokenizedBuffer.lineForScreenRow(0).text).toBe "SST Sa line with tabsTand T spacesSTS"
expect(tokenizedBuffer.tokenizedLineForRow(0).text).toBe "SST Sa line with tabsTand T spacesSTS"
# Also needs to work for copies
expect(tokenizedBuffer.lineForScreenRow(0).copy().text).toBe "SST Sa line with tabsTand T spacesSTS"
expect(tokenizedBuffer.tokenizedLineForRow(0).copy().text).toBe "SST Sa line with tabsTand T spacesSTS"
it "assigns endOfLineInvisibles to tokenized lines", ->
buffer = new TextBuffer(text: "a line that ends in a carriage-return-line-feed \r\na line that ends in just a line-feed\na line with no ending")
@@ -611,17 +611,17 @@ describe "TokenizedBuffer", ->
tokenizedBuffer.setInvisibles(cr: 'R', eol: 'N')
fullyTokenize(tokenizedBuffer)
expect(tokenizedBuffer.lineForScreenRow(0).endOfLineInvisibles).toEqual ['R', 'N']
expect(tokenizedBuffer.lineForScreenRow(1).endOfLineInvisibles).toEqual ['N']
expect(tokenizedBuffer.tokenizedLineForRow(0).endOfLineInvisibles).toEqual ['R', 'N']
expect(tokenizedBuffer.tokenizedLineForRow(1).endOfLineInvisibles).toEqual ['N']
# Lines ending in soft wraps get no invisibles
[left, right] = tokenizedBuffer.lineForScreenRow(0).softWrapAt(20)
[left, right] = tokenizedBuffer.tokenizedLineForRow(0).softWrapAt(20)
expect(left.endOfLineInvisibles).toBe null
expect(right.endOfLineInvisibles).toEqual ['R', 'N']
tokenizedBuffer.setInvisibles(cr: 'R', eol: false)
expect(tokenizedBuffer.lineForScreenRow(0).endOfLineInvisibles).toEqual ['R']
expect(tokenizedBuffer.lineForScreenRow(1).endOfLineInvisibles).toEqual []
expect(tokenizedBuffer.tokenizedLineForRow(0).endOfLineInvisibles).toEqual ['R']
expect(tokenizedBuffer.tokenizedLineForRow(1).endOfLineInvisibles).toEqual []
describe "leading and trailing whitespace", ->
beforeEach ->
@@ -630,41 +630,40 @@ describe "TokenizedBuffer", ->
fullyTokenize(tokenizedBuffer)
it "assigns ::firstNonWhitespaceIndex on tokens that have leading whitespace", ->
expect(tokenizedBuffer.lineForScreenRow(0).tokens[0].firstNonWhitespaceIndex).toBe null
expect(tokenizedBuffer.lineForScreenRow(1).tokens[0].firstNonWhitespaceIndex).toBe 2
expect(tokenizedBuffer.lineForScreenRow(1).tokens[1].firstNonWhitespaceIndex).toBe null
expect(tokenizedBuffer.tokenizedLineForRow(0).tokens[0].firstNonWhitespaceIndex).toBe null
expect(tokenizedBuffer.tokenizedLineForRow(1).tokens[0].firstNonWhitespaceIndex).toBe 2
expect(tokenizedBuffer.tokenizedLineForRow(1).tokens[1].firstNonWhitespaceIndex).toBe null
expect(tokenizedBuffer.lineForScreenRow(2).tokens[0].firstNonWhitespaceIndex).toBe 2
expect(tokenizedBuffer.lineForScreenRow(2).tokens[1].firstNonWhitespaceIndex).toBe 2
expect(tokenizedBuffer.lineForScreenRow(2).tokens[2].firstNonWhitespaceIndex).toBe null
expect(tokenizedBuffer.tokenizedLineForRow(2).tokens[0].firstNonWhitespaceIndex).toBe 2
expect(tokenizedBuffer.tokenizedLineForRow(2).tokens[1].firstNonWhitespaceIndex).toBe 2
expect(tokenizedBuffer.tokenizedLineForRow(2).tokens[2].firstNonWhitespaceIndex).toBe null
# The 4th token *has* leading whitespace, but isn't entirely whitespace
buffer.insert([5, 0], ' ')
expect(tokenizedBuffer.lineForScreenRow(5).tokens[3].firstNonWhitespaceIndex).toBe 1
expect(tokenizedBuffer.lineForScreenRow(5).tokens[4].firstNonWhitespaceIndex).toBe null
expect(tokenizedBuffer.tokenizedLineForRow(5).tokens[3].firstNonWhitespaceIndex).toBe 1
expect(tokenizedBuffer.tokenizedLineForRow(5).tokens[4].firstNonWhitespaceIndex).toBe null
# Lines that are *only* whitespace are not considered to have leading whitespace
buffer.insert([10, 0], ' ')
expect(tokenizedBuffer.lineForScreenRow(10).tokens[0].firstNonWhitespaceIndex).toBe null
expect(tokenizedBuffer.tokenizedLineForRow(10).tokens[0].firstNonWhitespaceIndex).toBe null
it "assigns ::firstTrailingWhitespaceIndex on tokens that have trailing whitespace", ->
buffer.insert([0, Infinity], ' ')
expect(tokenizedBuffer.lineForScreenRow(0).tokens[11].firstTrailingWhitespaceIndex).toBe null
expect(tokenizedBuffer.lineForScreenRow(0).tokens[12].firstTrailingWhitespaceIndex).toBe 0
expect(tokenizedBuffer.tokenizedLineForRow(0).tokens[11].firstTrailingWhitespaceIndex).toBe null
expect(tokenizedBuffer.tokenizedLineForRow(0).tokens[12].firstTrailingWhitespaceIndex).toBe 0
# The last token *has* trailing whitespace, but isn't entirely whitespace
buffer.setTextInRange([[2, 39], [2, 40]], ' ')
expect(tokenizedBuffer.lineForScreenRow(2).tokens[14].firstTrailingWhitespaceIndex).toBe null
console.log tokenizedBuffer.lineForScreenRow(2).tokens[15]
expect(tokenizedBuffer.lineForScreenRow(2).tokens[15].firstTrailingWhitespaceIndex).toBe 6
expect(tokenizedBuffer.tokenizedLineForRow(2).tokens[14].firstTrailingWhitespaceIndex).toBe null
expect(tokenizedBuffer.tokenizedLineForRow(2).tokens[15].firstTrailingWhitespaceIndex).toBe 6
# Lines that are *only* whitespace are considered to have trailing whitespace
buffer.insert([10, 0], ' ')
expect(tokenizedBuffer.lineForScreenRow(10).tokens[0].firstTrailingWhitespaceIndex).toBe 0
expect(tokenizedBuffer.tokenizedLineForRow(10).tokens[0].firstTrailingWhitespaceIndex).toBe 0
it "only marks trailing whitespace on the last segment of a soft-wrapped line", ->
buffer.insert([0, Infinity], ' ')
tokenizedLine = tokenizedBuffer.lineForScreenRow(0)
tokenizedLine = tokenizedBuffer.tokenizedLineForRow(0)
[segment1, segment2] = tokenizedLine.softWrapAt(16)
expect(segment1.tokens[5].value).toBe ' '
expect(segment1.tokens[5].firstTrailingWhitespaceIndex).toBe null
@@ -677,7 +676,7 @@ describe "TokenizedBuffer", ->
tokenizedBuffer.setInvisibles(space: 'S', tab: 'T')
fullyTokenize(tokenizedBuffer)
line = tokenizedBuffer.lineForScreenRow(0).copy()
line = tokenizedBuffer.tokenizedLineForRow(0).copy()
expect(line.tokens[0].firstNonWhitespaceIndex).toBe 2
expect(line.tokens[line.tokens.length - 1].firstTrailingWhitespaceIndex).toBe 0
@@ -704,55 +703,55 @@ describe "TokenizedBuffer", ->
describe "when the line is non-empty", ->
it "has an indent level based on the leading whitespace on the line", ->
expect(tokenizedBuffer.lineForScreenRow(0).indentLevel).toBe 0
expect(tokenizedBuffer.lineForScreenRow(1).indentLevel).toBe 1
expect(tokenizedBuffer.lineForScreenRow(2).indentLevel).toBe 2
expect(tokenizedBuffer.tokenizedLineForRow(0).indentLevel).toBe 0
expect(tokenizedBuffer.tokenizedLineForRow(1).indentLevel).toBe 1
expect(tokenizedBuffer.tokenizedLineForRow(2).indentLevel).toBe 2
buffer.insert([2, 0], ' ')
expect(tokenizedBuffer.lineForScreenRow(2).indentLevel).toBe 2.5
expect(tokenizedBuffer.tokenizedLineForRow(2).indentLevel).toBe 2.5
describe "when the line is empty", ->
it "assumes the indentation level of the first non-empty line below or above if one exists", ->
buffer.insert([12, 0], ' ')
buffer.insert([12, Infinity], '\n\n')
expect(tokenizedBuffer.lineForScreenRow(13).indentLevel).toBe 2
expect(tokenizedBuffer.lineForScreenRow(14).indentLevel).toBe 2
expect(tokenizedBuffer.tokenizedLineForRow(13).indentLevel).toBe 2
expect(tokenizedBuffer.tokenizedLineForRow(14).indentLevel).toBe 2
buffer.insert([1, Infinity], '\n\n')
expect(tokenizedBuffer.lineForScreenRow(2).indentLevel).toBe 2
expect(tokenizedBuffer.lineForScreenRow(3).indentLevel).toBe 2
expect(tokenizedBuffer.tokenizedLineForRow(2).indentLevel).toBe 2
expect(tokenizedBuffer.tokenizedLineForRow(3).indentLevel).toBe 2
buffer.setText('\n\n\n')
expect(tokenizedBuffer.lineForScreenRow(1).indentLevel).toBe 0
expect(tokenizedBuffer.tokenizedLineForRow(1).indentLevel).toBe 0
describe "when the changed lines are surrounded by whitespace-only lines", ->
it "updates the indentLevel of empty lines that precede the change", ->
expect(tokenizedBuffer.lineForScreenRow(12).indentLevel).toBe 0
expect(tokenizedBuffer.tokenizedLineForRow(12).indentLevel).toBe 0
buffer.insert([12, 0], '\n')
buffer.insert([13, 0], ' ')
expect(tokenizedBuffer.lineForScreenRow(12).indentLevel).toBe 1
expect(tokenizedBuffer.tokenizedLineForRow(12).indentLevel).toBe 1
it "updates empty line indent guides when the empty line is the last line", ->
buffer.insert([12, 2], '\n')
# The newline and he tab need to be in two different operations to surface the bug
buffer.insert([12, 0], ' ')
expect(tokenizedBuffer.lineForScreenRow(13).indentLevel).toBe 1
expect(tokenizedBuffer.tokenizedLineForRow(13).indentLevel).toBe 1
buffer.insert([12, 0], ' ')
expect(tokenizedBuffer.lineForScreenRow(13).indentLevel).toBe 2
expect(tokenizedBuffer.lineForScreenRow(14)).not.toBeDefined()
expect(tokenizedBuffer.tokenizedLineForRow(13).indentLevel).toBe 2
expect(tokenizedBuffer.tokenizedLineForRow(14)).not.toBeDefined()
it "updates the indentLevel of empty lines surrounding a change that inserts lines", ->
# create some new lines
buffer.insert([7, 0], '\n\n')
buffer.insert([5, 0], '\n\n')
expect(tokenizedBuffer.lineForScreenRow(5).indentLevel).toBe 3
expect(tokenizedBuffer.lineForScreenRow(6).indentLevel).toBe 3
expect(tokenizedBuffer.lineForScreenRow(9).indentLevel).toBe 3
expect(tokenizedBuffer.lineForScreenRow(10).indentLevel).toBe 3
expect(tokenizedBuffer.lineForScreenRow(11).indentLevel).toBe 2
expect(tokenizedBuffer.tokenizedLineForRow(5).indentLevel).toBe 3
expect(tokenizedBuffer.tokenizedLineForRow(6).indentLevel).toBe 3
expect(tokenizedBuffer.tokenizedLineForRow(9).indentLevel).toBe 3
expect(tokenizedBuffer.tokenizedLineForRow(10).indentLevel).toBe 3
expect(tokenizedBuffer.tokenizedLineForRow(11).indentLevel).toBe 2
tokenizedBuffer.on "changed", changeHandler = jasmine.createSpy('changeHandler')
@@ -761,11 +760,11 @@ describe "TokenizedBuffer", ->
delete changeHandler.argsForCall[0][0].bufferChange
expect(changeHandler).toHaveBeenCalledWith(start: 5, end: 10, delta: 2)
expect(tokenizedBuffer.lineForScreenRow(5).indentLevel).toBe 4
expect(tokenizedBuffer.lineForScreenRow(6).indentLevel).toBe 4
expect(tokenizedBuffer.lineForScreenRow(11).indentLevel).toBe 4
expect(tokenizedBuffer.lineForScreenRow(12).indentLevel).toBe 4
expect(tokenizedBuffer.lineForScreenRow(13).indentLevel).toBe 2
expect(tokenizedBuffer.tokenizedLineForRow(5).indentLevel).toBe 4
expect(tokenizedBuffer.tokenizedLineForRow(6).indentLevel).toBe 4
expect(tokenizedBuffer.tokenizedLineForRow(11).indentLevel).toBe 4
expect(tokenizedBuffer.tokenizedLineForRow(12).indentLevel).toBe 4
expect(tokenizedBuffer.tokenizedLineForRow(13).indentLevel).toBe 2
it "updates the indentLevel of empty lines surrounding a change that removes lines", ->
# create some new lines
@@ -779,9 +778,9 @@ describe "TokenizedBuffer", ->
delete changeHandler.argsForCall[0][0].bufferChange
expect(changeHandler).toHaveBeenCalledWith(start: 5, end: 10, delta: -1)
expect(tokenizedBuffer.lineForScreenRow(5).indentLevel).toBe 2
expect(tokenizedBuffer.lineForScreenRow(6).indentLevel).toBe 2
expect(tokenizedBuffer.lineForScreenRow(7).indentLevel).toBe 2 # new text
expect(tokenizedBuffer.lineForScreenRow(8).indentLevel).toBe 2
expect(tokenizedBuffer.lineForScreenRow(9).indentLevel).toBe 2
expect(tokenizedBuffer.lineForScreenRow(10).indentLevel).toBe 2 # }
expect(tokenizedBuffer.tokenizedLineForRow(5).indentLevel).toBe 2
expect(tokenizedBuffer.tokenizedLineForRow(6).indentLevel).toBe 2
expect(tokenizedBuffer.tokenizedLineForRow(7).indentLevel).toBe 2 # new text
expect(tokenizedBuffer.tokenizedLineForRow(8).indentLevel).toBe 2
expect(tokenizedBuffer.tokenizedLineForRow(9).indentLevel).toBe 2
expect(tokenizedBuffer.tokenizedLineForRow(10).indentLevel).toBe 2 # }
+7 -7
Ver Arquivo
@@ -10,13 +10,13 @@ describe "TokenizedLine", ->
atom.project.open('coffee.coffee').then (o) -> editor = o
it "returns true when the line is only whitespace", ->
expect(editor.lineForScreenRow(3).isOnlyWhitespace()).toBe true
expect(editor.lineForScreenRow(7).isOnlyWhitespace()).toBe true
expect(editor.lineForScreenRow(23).isOnlyWhitespace()).toBe true
expect(editor.tokenizedLineForScreenRow(3).isOnlyWhitespace()).toBe true
expect(editor.tokenizedLineForScreenRow(7).isOnlyWhitespace()).toBe true
expect(editor.tokenizedLineForScreenRow(23).isOnlyWhitespace()).toBe true
it "returns false when the line is not only whitespace", ->
expect(editor.lineForScreenRow(0).isOnlyWhitespace()).toBe false
expect(editor.lineForScreenRow(2).isOnlyWhitespace()).toBe false
expect(editor.tokenizedLineForScreenRow(0).isOnlyWhitespace()).toBe false
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", ->
@@ -35,6 +35,6 @@ describe "TokenizedLine", ->
runs ->
tokenIndex = 0
tokens = editor.lineForScreenRow(1).tokens
scopeTree = editor.lineForScreenRow(1).getScopeTree()
tokens = editor.tokenizedLineForScreenRow(1).tokens
scopeTree = editor.tokenizedLineForScreenRow(1).getScopeTree()
ensureValidScopeTree(scopeTree)
+95 -61
Ver Arquivo
@@ -8,8 +8,12 @@ describe "Workspace", ->
atom.workspace = workspace = new Workspace
describe "::open(uri, options)", ->
openEvents = null
beforeEach ->
spyOn(workspace.activePane, 'activate').andCallThrough()
openEvents = []
workspace.onDidOpen (event) -> openEvents.push(event)
spyOn(workspace.getActivePane(), 'activate').andCallThrough()
describe "when the 'searchAllPanes' option is false (default)", ->
describe "when called without a uri", ->
@@ -21,18 +25,21 @@ describe "Workspace", ->
runs ->
expect(editor1.getPath()).toBeUndefined()
expect(workspace.activePane.items).toEqual [editor1]
expect(workspace.activePaneItem).toBe editor1
expect(workspace.activePane.activate).toHaveBeenCalled()
expect(workspace.getActivePane().items).toEqual [editor1]
expect(workspace.getActivePaneItem()).toBe editor1
expect(workspace.getActivePane().activate).toHaveBeenCalled()
expect(openEvents).toEqual [{uri: undefined, pane: workspace.getActivePane(), item: editor1, index: 0}]
openEvents = []
waitsForPromise ->
workspace.open().then (editor) -> editor2 = editor
runs ->
expect(editor2.getPath()).toBeUndefined()
expect(workspace.activePane.items).toEqual [editor1, editor2]
expect(workspace.activePaneItem).toBe editor2
expect(workspace.activePane.activate).toHaveBeenCalled()
expect(workspace.getActivePane().items).toEqual [editor1, editor2]
expect(workspace.getActivePaneItem()).toBe editor2
expect(workspace.getActivePane().activate).toHaveBeenCalled()
expect(openEvents).toEqual [{uri: undefined, pane: workspace.getActivePane(), item: editor2, index: 1}]
describe "when called with a uri", ->
describe "when the active pane already has an editor for the given uri", ->
@@ -51,8 +58,29 @@ describe "Workspace", ->
runs ->
expect(editor).toBe editor1
expect(workspace.activePaneItem).toBe editor
expect(workspace.activePane.activate).toHaveBeenCalled()
expect(workspace.getActivePaneItem()).toBe editor
expect(workspace.getActivePane().activate).toHaveBeenCalled()
expect(openEvents).toEqual [
{
uri: atom.project.resolve('a')
item: editor1
pane: atom.workspace.getActivePane()
index: 0
}
{
uri: atom.project.resolve('b')
item: editor2
pane: atom.workspace.getActivePane()
index: 1
}
{
uri: atom.project.resolve('a')
item: editor1
pane: atom.workspace.getActivePane()
index: 0
}
]
describe "when the active pane does not have an editor for the given uri", ->
it "adds and activates a new editor for the given path on the active pane", ->
@@ -62,9 +90,9 @@ describe "Workspace", ->
runs ->
expect(editor.getUri()).toBe atom.project.resolve('a')
expect(workspace.activePaneItem).toBe editor
expect(workspace.activePane.items).toEqual [editor]
expect(workspace.activePane.activate).toHaveBeenCalled()
expect(workspace.getActivePaneItem()).toBe editor
expect(workspace.getActivePane().items).toEqual [editor]
expect(workspace.getActivePane().activate).toHaveBeenCalled()
describe "when the 'searchAllPanes' option is true", ->
describe "when an editor for the given uri is already open on an inactive pane", ->
@@ -83,14 +111,14 @@ describe "Workspace", ->
workspace.open('b').then (o) -> editor2 = o
runs ->
expect(workspace.activePaneItem).toBe editor2
expect(workspace.getActivePaneItem()).toBe editor2
waitsForPromise ->
workspace.open('a', searchAllPanes: true)
runs ->
expect(workspace.activePane).toBe pane1
expect(workspace.activePaneItem).toBe editor1
expect(workspace.getActivePane()).toBe pane1
expect(workspace.getActivePaneItem()).toBe editor1
describe "when no editor for the given uri is open in any pane", ->
it "opens an editor for the given uri in the active pane", ->
@@ -99,21 +127,21 @@ describe "Workspace", ->
workspace.open('a', searchAllPanes: true).then (o) -> editor = o
runs ->
expect(workspace.activePaneItem).toBe editor
expect(workspace.getActivePaneItem()).toBe editor
describe "when the 'split' option is set", ->
describe "when the 'split' option is 'left'", ->
it "opens the editor in the leftmost pane of the current pane axis", ->
pane1 = workspace.activePane
pane1 = workspace.getActivePane()
pane2 = pane1.splitRight()
expect(workspace.activePane).toBe pane2
expect(workspace.getActivePane()).toBe pane2
editor = null
waitsForPromise ->
workspace.open('a', split: 'left').then (o) -> editor = o
runs ->
expect(workspace.activePane).toBe pane1
expect(workspace.getActivePane()).toBe pane1
expect(pane1.items).toEqual [editor]
expect(pane2.items).toEqual []
@@ -123,37 +151,37 @@ describe "Workspace", ->
workspace.open('a', split: 'left').then (o) -> editor = o
runs ->
expect(workspace.activePane).toBe pane1
expect(workspace.getActivePane()).toBe pane1
expect(pane1.items).toEqual [editor]
expect(pane2.items).toEqual []
describe "when a pane axis is the leftmost sibling of the current pane", ->
it "opens the new item in the current pane", ->
editor = null
pane1 = workspace.activePane
pane1 = workspace.getActivePane()
pane2 = pane1.splitLeft()
pane3 = pane2.splitDown()
pane1.activate()
expect(workspace.activePane).toBe pane1
expect(workspace.getActivePane()).toBe pane1
waitsForPromise ->
workspace.open('a', split: 'left').then (o) -> editor = o
runs ->
expect(workspace.activePane).toBe pane1
expect(workspace.getActivePane()).toBe pane1
expect(pane1.items).toEqual [editor]
describe "when the 'split' option is 'right'", ->
it "opens the editor in the rightmost pane of the current pane axis", ->
editor = null
pane1 = workspace.activePane
pane1 = workspace.getActivePane()
pane2 = null
waitsForPromise ->
workspace.open('a', split: 'right').then (o) -> editor = o
runs ->
pane2 = workspace.getPanes().filter((p) -> p != pane1)[0]
expect(workspace.activePane).toBe pane2
expect(workspace.getActivePane()).toBe pane2
expect(pane1.items).toEqual []
expect(pane2.items).toEqual [editor]
@@ -163,18 +191,18 @@ describe "Workspace", ->
workspace.open('a', split: 'right').then (o) -> editor = o
runs ->
expect(workspace.activePane).toBe pane2
expect(workspace.getActivePane()).toBe pane2
expect(pane1.items).toEqual []
expect(pane2.items).toEqual [editor]
describe "when a pane axis is the rightmost sibling of the current pane", ->
it "opens the new item in a new pane split to the right of the current pane", ->
editor = null
pane1 = workspace.activePane
pane1 = workspace.getActivePane()
pane2 = pane1.splitRight()
pane3 = pane2.splitDown()
pane1.activate()
expect(workspace.activePane).toBe pane1
expect(workspace.getActivePane()).toBe pane1
pane4 = null
waitsForPromise ->
@@ -182,7 +210,7 @@ describe "Workspace", ->
runs ->
pane4 = workspace.getPanes().filter((p) -> p != pane1)[0]
expect(workspace.activePane).toBe pane4
expect(workspace.getActivePane()).toBe pane4
expect(pane4.items).toEqual [editor]
expect(workspace.paneContainer.root.children[0]).toBe pane1
expect(workspace.paneContainer.root.children[1]).toBe pane4
@@ -203,21 +231,21 @@ describe "Workspace", ->
workspace.open("bar://baz").then (item) ->
expect(item).toEqual { bar: "bar://baz" }
it "emits an 'editor-created' event", ->
it "notifies ::onDidAddTextEditor observers", ->
absolutePath = require.resolve('./fixtures/dir/a')
newEditorHandler = jasmine.createSpy('newEditorHandler')
workspace.on 'editor-created', newEditorHandler
workspace.onDidAddTextEditor newEditorHandler
editor = null
waitsForPromise ->
workspace.open(absolutePath).then (e) -> editor = e
runs ->
expect(newEditorHandler).toHaveBeenCalledWith editor
expect(newEditorHandler.argsForCall[0][0].textEditor).toBe editor
describe "::reopenItem()", ->
it "opens the uri associated with the last closed pane that isn't currently open", ->
pane = workspace.activePane
pane = workspace.getActivePane()
waitsForPromise ->
workspace.open('a').then ->
workspace.open('b').then ->
@@ -226,44 +254,44 @@ describe "Workspace", ->
runs ->
# does not reopen items with no uri
expect(workspace.activePaneItem.getUri()).toBeUndefined()
expect(workspace.getActivePaneItem().getUri()).toBeUndefined()
pane.destroyActiveItem()
waitsForPromise ->
workspace.reopenItem()
runs ->
expect(workspace.activePaneItem.getUri()).not.toBeUndefined()
expect(workspace.getActivePaneItem().getUri()).not.toBeUndefined()
# destroy all items
expect(workspace.activePaneItem.getUri()).toBe atom.project.resolve('file1')
expect(workspace.getActivePaneItem().getUri()).toBe atom.project.resolve('file1')
pane.destroyActiveItem()
expect(workspace.activePaneItem.getUri()).toBe atom.project.resolve('b')
expect(workspace.getActivePaneItem().getUri()).toBe atom.project.resolve('b')
pane.destroyActiveItem()
expect(workspace.activePaneItem.getUri()).toBe atom.project.resolve('a')
expect(workspace.getActivePaneItem().getUri()).toBe atom.project.resolve('a')
pane.destroyActiveItem()
# reopens items with uris
expect(workspace.activePaneItem).toBeUndefined()
expect(workspace.getActivePaneItem()).toBeUndefined()
waitsForPromise ->
workspace.reopenItem()
runs ->
expect(workspace.activePaneItem.getUri()).toBe atom.project.resolve('a')
expect(workspace.getActivePaneItem().getUri()).toBe atom.project.resolve('a')
# does not reopen items that are already open
waitsForPromise ->
workspace.open('b')
runs ->
expect(workspace.activePaneItem.getUri()).toBe atom.project.resolve('b')
expect(workspace.getActivePaneItem().getUri()).toBe atom.project.resolve('b')
waitsForPromise ->
workspace.reopenItem()
runs ->
expect(workspace.activePaneItem.getUri()).toBe atom.project.resolve('file1')
expect(workspace.getActivePaneItem().getUri()).toBe atom.project.resolve('file1')
describe "::increase/decreaseFontSize()", ->
it "increases/decreases the font size without going below 1", ->
@@ -282,7 +310,22 @@ describe "Workspace", ->
describe "::openLicense()", ->
it "opens the license as plain-text in a buffer", ->
waitsForPromise -> workspace.openLicense()
runs -> expect(workspace.activePaneItem.getText()).toMatch /Copyright/
runs -> expect(workspace.getActivePaneItem().getText()).toMatch /Copyright/
describe "::observeTextEditors()", ->
it "invokes the observer with current and future text editors", ->
observed = []
waitsForPromise -> workspace.open()
waitsForPromise -> workspace.open()
waitsForPromise -> workspace.openLicense()
runs ->
workspace.observeTextEditors (editor) -> observed.push(editor)
waitsForPromise -> workspace.open()
expect(observed).toEqual workspace.getTextEditors()
describe "when an editor is destroyed", ->
it "removes the editor", ->
@@ -292,23 +335,9 @@ describe "Workspace", ->
workspace.open("a").then (e) -> editor = e
runs ->
expect(workspace.getEditors()).toHaveLength 1
expect(workspace.getTextEditors()).toHaveLength 1
editor.destroy()
expect(workspace.getEditors()).toHaveLength 0
describe "when an editor is copied", ->
it "emits an 'editor-created' event", ->
editor = null
handler = jasmine.createSpy('editorCreatedHandler')
workspace.on 'editor-created', handler
waitsForPromise ->
workspace.open("a").then (o) -> editor = o
runs ->
expect(handler.callCount).toBe 1
editorCopy = editor.copy()
expect(handler.callCount).toBe 2
expect(workspace.getTextEditors()).toHaveLength 0
it "stores the active grammars used by all the open editors", ->
waitsForPromise ->
@@ -317,14 +346,19 @@ describe "Workspace", ->
waitsForPromise ->
atom.packages.activatePackage('language-coffee-script')
waitsForPromise ->
atom.packages.activatePackage('language-todo')
waitsForPromise ->
atom.workspace.open('sample.coffee')
runs ->
atom.workspace.getActiveEditor().setText('i = /test/;')
atom.workspace.getActiveEditor().setText """
i = /test/; #FIXME
"""
state = atom.workspace.serialize()
expect(state.packagesWithActiveGrammars).toEqual ['language-coffee-script', 'language-javascript']
expect(state.packagesWithActiveGrammars).toEqual ['language-coffee-script', 'language-javascript', 'language-todo']
jsPackage = atom.packages.getLoadedPackage('language-javascript')
coffeePackage = atom.packages.getLoadedPackage('language-coffee-script')
+79 -54
Ver Arquivo
@@ -17,29 +17,14 @@ WindowEventHandler = require './window-event-handler'
# Public: Atom global for dealing with packages, themes, menus, and the window.
#
# An instance of this class is always available as the `atom` global.
#
# ## Useful properties available:
#
# * `atom.clipboard` - A {Clipboard} instance
# * `atom.config` - A {Config} instance
# * `atom.contextMenu` - A {ContextMenuManager} instance
# * `atom.deserializers` - A {DeserializerManager} instance
# * `atom.keymaps` - A {KeymapManager} instance
# * `atom.menu` - A {MenuManager} instance
# * `atom.packages` - A {PackageManager} instance
# * `atom.project` - A {Project} instance
# * `atom.syntax` - A {Syntax} instance
# * `atom.themes` - A {ThemeManager} instance
# * `atom.workspace` - A {Workspace} instance
# * `atom.workspaceView` - A {WorkspaceView} instance
module.exports =
class Atom extends Model
@version: 1 # Increment this when the serialization format changes
# Public: Load or create the Atom environment in the given mode.
#
# mode - Pass 'editor' or 'spec' depending on the kind of environment you
# want to build.
# * `mode` A {String} mode that is either 'editor' or 'spec' depending on the
# kind of environment you want to build.
#
# Returns an Atom instance, fully initialized
@loadOrCreate: (mode) ->
@@ -113,6 +98,42 @@ class Atom extends Model
workspaceViewParentSelector: 'body'
lastUncaughtError: null
# Public: A {Clipboard} instance
clipboard: null
# Public: A {Config} instance
config: null
# Public: A {ContextMenuManager} instance
contextMenu: null
# Public: A {DeserializerManager} instance
deserializers: null
# Public: A {KeymapManager} instance
keymaps: null
# Public: A {MenuManager} instance
menu: null
# Public: A {PackageManager} instance
packages: null
# Public: A {Project} instance
project: null
# Public: A {Syntax} instance
syntax: null
# Public: A {ThemeManager} instance
themes: null
# Public: A {Workspace} instance
workspace: null
# Public: A {WorkspaceView} instance
workspaceView: null
# Call .loadOrCreate instead
constructor: (@state) ->
{@mode} = @state
@@ -120,8 +141,9 @@ class Atom extends Model
@deserializers = new DeserializerManager()
# Public: Sets up the basic services that should be available in all modes
# (both spec and application). Call after this instance has been assigned to
# the `atom` global.
# (both spec and application).
#
# Call after this instance has been assigned to the `atom` global.
initialize: ->
window.onerror = =>
@openDevTools()
@@ -159,7 +181,7 @@ class Atom extends Model
@keymap = @keymaps # Deprecated
@packages = new PackageManager({devMode, configDirPath, resourcePath, safeMode})
@themes = new ThemeManager({packageManager: @packages, configDirPath, resourcePath, safeMode})
@contextMenu = new ContextMenuManager(devMode)
@contextMenu = new ContextMenuManager({resourcePath, devMode})
@menu = new MenuManager({resourcePath})
@clipboard = new Clipboard()
@@ -193,7 +215,11 @@ class Atom extends Model
# Public: Get the dimensions of this window.
#
# Returns an object with x, y, width, and height keys.
# Returns an {Object} with the following keys:
# * `x` The window's x-position {Number}.
# * `y` The window's y-position {Number}.
# * `width` The window's width {Number}.
# * `height` The window's height {Number}.
getWindowDimensions: ->
browserWindow = @getCurrentWindow()
[x, y] = browserWindow.getPosition()
@@ -207,11 +233,11 @@ class Atom extends Model
# in the dimensions parameter. If x or y are omitted the window will be
# centered. If height or width are omitted only the position will be changed.
#
# dimensions - An {Object} with the following keys:
# :x - The new x coordinate.
# :y - The new y coordinate.
# :width - The new width.
# :height - The new height.
# * `dimensions` An {Object} with the following keys:
# * `x` The new x coordinate.
# * `y` The new y coordinate.
# * `width` The new width.
# * `height` The new height.
setWindowDimensions: ({x, y, width, height}) ->
if width? and height?
@setSize(width, height)
@@ -260,7 +286,7 @@ class Atom extends Model
# Public: Get the load settings for the current window.
#
# Returns an object containing all the load setting key/value pairs.
# Returns an {Object} containing all the load setting key/value pairs.
getLoadSettings: ->
@constructor.getLoadSettings()
@@ -295,8 +321,9 @@ class Atom extends Model
# Call this method when establishing a real application window.
startEditorWindow: ->
{resourcePath, safeMode} = @getLoadSettings()
CommandInstaller = require './command-installer'
resourcePath = atom.getLoadSettings().resourcePath
CommandInstaller.installAtomCommand resourcePath, false, (error) ->
console.warn error.message if error?
CommandInstaller.installApmCommand resourcePath, false, (error) ->
@@ -315,7 +342,7 @@ class Atom extends Model
@packages.activate()
@keymaps.loadUserKeymap()
@requireUserInitScript()
@requireUserInitScript() unless safeMode
@menu.update()
maximize = dimensions?.maximized and process.platform isnt 'darwin'
@@ -364,23 +391,21 @@ class Atom extends Model
# Calling this method without an options parameter will open a prompt to pick
# a file/folder to open in the new window.
#
# options - An {Object} with the following keys:
# :pathsToOpen - An {Array} of {String} paths to open.
# :newWindow - A {Boolean}, true to always open a new window instead of
# reusing existing windows depending on the paths to open.
# :devMode - A {Boolean}, true to open the window in development mode.
# Development mode loads the Atom source from the locally
# cloned repository and also loads all the packages in
# ~/.atom/dev/packages
# :safeMode - A {Boolean}, true to open the window in safe mode. Safe
# mode prevents all packages installed to ~/.atom/packages
# from loading.
# * `options` An {Object} with the following keys:
# * `pathsToOpen` An {Array} of {String} paths to open.
# * `newWindow` A {Boolean}, true to always open a new window instead of
# reusing existing windows depending on the paths to open.
# * `devMode` A {Boolean}, true to open the window in development mode.
# Development mode loads the Atom source from the locally cloned
# repository and also loads all the packages in ~/.atom/dev/packages
# * `safeMode` A {Boolean}, true to open the window in safe mode. Safe
# mode prevents all packages installed to ~/.atom/packages from loading.
open: (options) ->
ipc.send('open', options)
# Public: Open a confirm dialog.
#
# ## Example
# ## Examples
#
# ```coffee
# atom.confirm
@@ -391,12 +416,12 @@ class Atom extends Model
# Bad: -> window.alert('bummer')
# ```
#
# options - An {Object} with the following keys:
# :message - The {String} message to display.
# :detailedMessage - The {String} detailed message to display.
# :buttons - Either an array of strings or an object where keys are
# button names and the values are callbacks to invoke when
# clicked.
# * `options` An {Object} with the following keys:
# * `message` The {String} message to display.
# * `detailedMessage` The {String} detailed message to display.
# * `buttons` Either an array of strings or an object where keys are
# button names and the values are callbacks to invoke when
# clicked.
#
# Returns the chosen button index {Number} if the buttons option was an array.
confirm: ({message, detailedMessage, buttons}={}) ->
@@ -459,15 +484,15 @@ class Atom extends Model
# Public: Set the size of current window.
#
# width - The {Number} of pixels.
# height - The {Number} of pixels.
# * `width` The {Number} of pixels.
# * `height` The {Number} of pixels.
setSize: (width, height) ->
@getCurrentWindow().setSize(width, height)
# Public: Set the position of current window.
#
# x - The {Number} of pixels.
# y - The {Number} of pixels.
# * `x` The {Number} of pixels.
# * `y` The {Number} of pixels.
setPosition: (x, y) ->
ipc.send('call-window-method', 'setPosition', x, y)
@@ -554,7 +579,7 @@ class Atom extends Model
# This time include things like loading and activating packages, creating
# DOM elements for the editor, and reading the config.
#
# Returns the number of milliseconds taken to load the window or null
# Returns the {Number} of milliseconds taken to load the window or null
# if the window hasn't finished loading yet.
getWindowLoadTime: ->
@loadTime
@@ -586,8 +611,8 @@ class Atom extends Model
# The globals will be set on the `window` object and removed after the
# require completes.
#
# id - The {String} module name or path.
# globals - An {Object} to set as globals during require (default: {})
# * `id` The {String} module name or path.
# * `globals` An optinal {Object} to set as globals during require.
requireWithGlobals: (id, globals={}) ->
existingGlobals = {}
for key, value of globals
+4 -1
Ver Arquivo
@@ -345,7 +345,10 @@ class AtomApplication
if existingWindow?
openedWindow = existingWindow
openedWindow.openPath(pathToOpen, initialLine)
openedWindow.restore() if openedWindow.isMinimized()
if openedWindow.isMinimized()
openedWindow.restore()
else
openedWindow.focus()
else
if devMode
try
+22 -21
Ver Arquivo
@@ -6,34 +6,35 @@ path = require 'path'
#
# This is necessary on Windows since it doesn't support shebang `#!` lines.
#
# ## Requiring in packages
# ## Examples
#
# ```coffee
# {BufferedNodeProcess} = require 'atom'
# {BufferedNodeProcess} = require 'atom'
# ```
module.exports =
class BufferedNodeProcess extends BufferedProcess
# Public: Runs the given Node script by spawning a new child process.
#
# options - An {Object} with the following keys:
# :command - The {String} path to the JavaScript script to execute.
# :args - The {Array} of arguments to pass to the script (optional).
# :options - The options {Object} to pass to Node's `ChildProcess.spawn`
# method (optional).
# :stdout - The callback {Function} that receives a single argument which
# contains the standard output from the command. The callback is
# called as data is received but it's buffered to ensure only
# complete lines are passed until the source stream closes. After
# the source stream has closed all remaining data is sent in a
# final call (optional).
# :stderr - The callback {Function} that receives a single argument which
# contains the standard error output from the command. The
# callback is called as data is received but it's buffered to
# ensure only complete lines are passed until the source stream
# closes. After the source stream has closed all remaining data
# is sent in a final call (optional).
# :exit - The callback {Function} which receives a single argument
# containing the exit status (optional).
# * `options` An {Object} with the following keys:
# * `command` The {String} path to the JavaScript script to execute.
# * `args` The {Array} of arguments to pass to the script (optional).
# * `options` The options {Object} to pass to Node's `ChildProcess.spawn`
# method (optional).
# * `stdout` The callback {Function} that receives a single argument which
# contains the standard output from the command. The callback is
# called as data is received but it's buffered to ensure only
# complete lines are passed until the source stream closes. After
# the source stream has closed all remaining data is sent in a
# final call (optional).
# * `stderr` The callback {Function} that receives a single argument which
# contains the standard error output from the command. The
# callback is called as data is received but it's buffered to
# ensure only complete lines are passed until the source stream
# closes. After the source stream has closed all remaining data
# is sent in a final call (optional).
# * `exit` The callback {Function} which receives a single argument
# containing the exit status (optional).
constructor: ({command, args, options, stdout, stderr, exit}) ->
node =
if process.platform is 'darwin'
+23 -23
Ver Arquivo
@@ -4,7 +4,7 @@ ChildProcess = require 'child_process'
# Public: A wrapper which provides standard error/output line buffering for
# Node's ChildProcess.
#
# ## Requiring in packages
# ## Examples
#
# ```coffee
# {BufferedProcess} = require 'atom'
@@ -19,25 +19,25 @@ module.exports =
class BufferedProcess
# Public: Runs the given command by spawning a new child process.
#
# options - An {Object} with the following keys:
# :command - The {String} command to execute.
# :args - The {Array} of arguments to pass to the command (optional).
# :options - The options {Object} to pass to Node's `ChildProcess.spawn`
# method (optional).
# :stdout - The callback {Function} that receives a single argument which
# contains the standard output from the command. The callback is
# called as data is received but it's buffered to ensure only
# complete lines are passed until the source stream closes. After
# the source stream has closed all remaining data is sent in a
# final call (optional).
# :stderr - The callback {Function} that receives a single argument which
# contains the standard error output from the command. The
# callback is called as data is received but it's buffered to
# ensure only complete lines are passed until the source stream
# closes. After the source stream has closed all remaining data
# is sent in a final call (optional).
# :exit - The callback {Function} which receives a single argument
# containing the exit status (optional).
# * `options` An {Object} with the following keys:
# * `command` The {String} command to execute.
# * `args` The {Array} of arguments to pass to the command (optional).
# * `options` The options {Object} to pass to Node's `ChildProcess.spawn`
# method (optional).
# * `stdout` The callback {Function} that receives a single argument which
# contains the standard output from the command. The callback is
# called as data is received but it's buffered to ensure only
# complete lines are passed until the source stream closes. After
# the source stream has closed all remaining data is sent in a
# final call (optional).
# * `stderr` The callback {Function} that receives a single argument which
# contains the standard error output from the command. The
# callback is called as data is received but it's buffered to
# ensure only complete lines are passed until the source stream
# closes. After the source stream has closed all remaining data
# is sent in a final call (optional).
# * `exit` The callback {Function} which receives a single argument
# containing the exit status (optional).
constructor: ({command, args, options, stdout, stderr, exit}={}) ->
options ?= {}
# Related to joyent/node#2318
@@ -95,9 +95,9 @@ class BufferedProcess
# Helper method to pass data line by line.
#
# stream - The Stream to read from.
# onLines - The callback to call with each line of data.
# onDone - The callback to call when the stream has closed.
# * `stream` The Stream to read from.
# * `onLines` The callback to call with each line of data.
# * `onDone` The callback to call when the stream has closed.
bufferStream: (stream, onLines, onDone) ->
stream.setEncoding('utf8')
buffered = ''
+13 -5
Ver Arquivo
@@ -4,6 +4,14 @@ crypto = require 'crypto'
# Public: Represents the clipboard used for copying and pasting in Atom.
#
# An instance of this class is always available as the `atom.clipboard` global.
#
# ## Examples
#
# ```coffee
# atom.clipboard.write('hello')
#
# console.log(atom.clipboard.read()) # 'hello'
# ```
module.exports =
class Clipboard
metadata: null
@@ -11,7 +19,7 @@ class Clipboard
# Creates an `md5` hash of some text.
#
# text - A {String} to hash.
# * `text` A {String} to hash.
#
# Returns a hashed {String}.
md5: (text) ->
@@ -22,8 +30,8 @@ class Clipboard
# The metadata associated with the text is available by calling
# {::readWithMetadata}.
#
# text - The {String} to store.
# metadata - The additional info to associate with the text.
# * `text` The {String} to store.
# * `metadata` The additional info to associate with the text.
write: (text, metadata) ->
@signatureForMetadata = @md5(text)
@metadata = metadata
@@ -39,8 +47,8 @@ class Clipboard
# associated metadata.
#
# Returns an {Object} with the following keys:
# :text - The {String} clipboard text.
# :metadata - The metadata stored by an earlier call to {::write}.
# * `text` The {String} clipboard text.
# * `metadata` The metadata stored by an earlier call to {::write}.
readWithMetadata: ->
text = @read()
if @signatureForMetadata is @md5(text)
+40 -43
Ver Arquivo
@@ -15,9 +15,9 @@ pathWatcher = require 'pathwatcher'
# * Create your own root keypath using your package's name.
# * Don't depend on (or write to) configuration keys outside of your keypath.
#
# ## Example
# ## Examples
#
# ```coffeescript
# ```coffee
# atom.config.set('my-package.key', 'value')
# atom.config.observe 'my-package.key', ->
# console.log 'My configuration changed:', atom.config.get('my-package.key')
@@ -88,17 +88,17 @@ class Config
_.extend hash, defaults
@emit 'updated'
# Public: Get the {String} path to the config file being used.
# Extended: Get the {String} path to the config file being used.
getUserConfigPath: ->
@configFilePath
# Public: Returns a new {Object} containing all of settings and defaults.
# Extended: Returns a new {Object} containing all of settings and defaults.
getSettings: ->
_.deepExtend(@settings, @defaultSettings)
# Public: Retrieves the setting for the given key.
# Essential: Retrieves the setting for the given key.
#
# keyPath - The {String} name of the key to retrieve.
# * `keyPath` The {String} name of the key to retrieve.
#
# Returns the value from Atom's default settings, the user's configuration
# file, or `null` if the key doesn't exist in either.
@@ -117,19 +117,19 @@ class Config
value
# Public: Retrieves the setting for the given key as an integer.
# Extended: Retrieves the setting for the given key as an integer.
#
# keyPath - The {String} name of the key to retrieve
# * `keyPath` The {String} name of the key to retrieve
#
# Returns the value from Atom's default settings, the user's configuration
# file, or `NaN` if the key doesn't exist in either.
getInt: (keyPath) ->
parseInt(@get(keyPath))
# Public: Retrieves the setting for the given key as a positive integer.
# Extended: Retrieves the setting for the given key as a positive integer.
#
# keyPath - The {String} name of the key to retrieve
# defaultValue - The integer {Number} to fall back to if the value isn't
# * `keyPath` The {String} name of the key to retrieve
# * `defaultValue` The integer {Number} to fall back to if the value isn't
# positive, defaults to 0.
#
# Returns the value from Atom's default settings, the user's configuration
@@ -137,12 +137,12 @@ class Config
getPositiveInt: (keyPath, defaultValue=0) ->
Math.max(@getInt(keyPath), 0) or defaultValue
# Public: Sets the value for a configuration setting.
# Essential: Sets the value for a configuration setting.
#
# This value is stored in Atom's internal configuration file.
#
# keyPath - The {String} name of the key.
# value - The value of the setting.
# * `keyPath` The {String} name of the key.
# * `value` The value of the setting.
#
# Returns the `value`.
set: (keyPath, value) ->
@@ -153,47 +153,47 @@ class Config
@update()
value
# Public: Toggle the value at the key path.
# Extended: Toggle the value at the key path.
#
# The new value will be `true` if the value is currently falsy and will be
# `false` if the value is currently truthy.
#
# keyPath - The {String} name of the key.
# * `keyPath` The {String} name of the key.
#
# Returns the new value.
toggle: (keyPath) ->
@set(keyPath, !@get(keyPath))
# Public: Restore the key path to its default value.
# Extended: Restore the key path to its default value.
#
# keyPath - The {String} name of the key.
# * `keyPath` The {String} name of the key.
#
# Returns the new value.
restoreDefault: (keyPath) ->
@set(keyPath, _.valueForKeyPath(@defaultSettings, keyPath))
# Public: Get the default value of the key path.
# Extended: Get the default value of the key path.
#
# keyPath - The {String} name of the key.
# * `keyPath` The {String} name of the key.
#
# Returns the default value.
getDefault: (keyPath) ->
defaultValue = _.valueForKeyPath(@defaultSettings, keyPath)
_.deepClone(defaultValue)
# Public: Is the key path value its default value?
# Extended: Is the key path value its default value?
#
# keyPath - The {String} name of the key.
# * `keyPath` The {String} name of the key.
#
# Returns a {Boolean}, `true` if the current value is the default, `false`
# otherwise.
isDefault: (keyPath) ->
not _.valueForKeyPath(@settings, keyPath)?
# Public: Push the value to the array at the key path.
# Extended: Push the value to the array at the key path.
#
# keyPath - The {String} key path.
# value - The value to push to the array.
# * `keyPath` The {String} key path.
# * `value` The value to push to the array.
#
# Returns the new array length {Number} of the setting.
pushAtKeyPath: (keyPath, value) ->
@@ -202,10 +202,10 @@ class Config
@set(keyPath, arrayValue)
result
# Public: Add the value to the beginning of the array at the key path.
# Extended: Add the value to the beginning of the array at the key path.
#
# keyPath - The {String} key path.
# value - The value to shift onto the array.
# * `keyPath` The {String} key path.
# * `value` The value to shift onto the array.
#
# Returns the new array length {Number} of the setting.
unshiftAtKeyPath: (keyPath, value) ->
@@ -216,8 +216,8 @@ class Config
# Public: Remove the value from the array at the key path.
#
# keyPath - The {String} key path.
# value - The value to remove from the array.
# * `keyPath` The {String} key path.
# * `value` The value to remove from the array.
#
# Returns the new array value of the setting.
removeAtKeyPath: (keyPath, value) ->
@@ -226,20 +226,17 @@ class Config
@set(keyPath, arrayValue)
result
# Public: Establishes an event listener for a given key.
# Essential: Add a listener for changes to a given key path.
#
# `callback` is fired whenever the value of the key is changed and will
# be fired immediately unless the `callNow` option is `false`.
#
# keyPath - The {String} name of the key to observe
# options - An optional {Object} containing the `callNow` key.
# callback - The {Function} to call when the value of the key changes.
# The first argument will be the new value of the key and the
#   second argument will be an {Object} with a `previous` property
# that is the prior value of the key.
# * `keyPath` The {String} name of the key to observe
# * `options` An optional {Object} containing the `callNow` key.
# * `callback` The {Function} to call when the value of the key changes.
# The first argument will be the new value of the key and the
#   second argument will be an {Object} with a `previous` property
# that is the prior value of the key.
#
# Returns an {Object} with the following keys:
# :off - A {Function} that unobserves the `keyPath` when called.
# * `off` A {Function} that unobserves the `keyPath` when called.
observe: (keyPath, options={}, callback) ->
if _.isFunction(options)
callback = options
@@ -259,9 +256,9 @@ class Config
callback(value) if options.callNow ? true
subscription
# Public: Unobserve all callbacks on a given key.
# Unobserve all callbacks on a given key.
#
# keyPath - The {String} name of the key to unobserve.
# * `keyPath` The {String} name of the key to unobserve.
unobserve: (keyPath) ->
@off("updated.#{keyPath.replace(/\./, '-')}")
+30 -16
Ver Arquivo
@@ -1,6 +1,9 @@
{$} = require './space-pen-extensions'
_ = require 'underscore-plus'
remote = require 'remote'
path = require 'path'
CSON = require 'season'
fs = require 'fs-plus'
# Public: Provides a registry for commands that you'd like to appear in the
# context menu.
@@ -9,7 +12,7 @@ remote = require 'remote'
# global.
module.exports =
class ContextMenuManager
constructor: (@devMode=false) ->
constructor: ({@resourcePath, @devMode}) ->
@definitions = {}
@devModeDefinitions = {}
@activeElement = null
@@ -21,16 +24,22 @@ class ContextMenuManager
@commandOptions = x: e.pageX, y: e.pageY
]
atom.keymaps.on 'bundled-keymaps-loaded', => @loadPlatformItems()
loadPlatformItems: ->
menusDirPath = path.join(@resourcePath, 'menus')
platformMenuPath = fs.resolve(menusDirPath, process.platform, ['cson', 'json'])
map = CSON.readFileSync(platformMenuPath)
atom.contextMenu.add(platformMenuPath, map['context-menu'])
# Public: Creates menu definitions from the object specified by the menu
# cson API.
# JSON API.
#
# name - The path of the file that contains the menu definitions.
# object - The 'context-menu' object specified in the menu cson API.
# options - An {Object} with the following keys:
# :devMode - Determines whether the entries should only be shown when
# the window is in dev mode.
#
# Returns nothing.
# * `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
@@ -43,6 +52,8 @@ class ContextMenuManager
menuItem = @buildMenuItem(label, commandOrSubmenu)
@addBySelector(selector, menuItem, {devMode})
undefined
buildMenuItem: (label, command) ->
if command is '-'
{type: 'separator'}
@@ -52,12 +63,12 @@ class ContextMenuManager
# Registers a command to be displayed when the relevant item is right
# clicked.
#
# 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 {Object} with the following keys:
# :devMode - Indicates whether this command should only appear while the
# editor is in dev mode.
# * `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'})
@@ -79,7 +90,7 @@ class ContextMenuManager
# active element are listed first. The further down the list you go, the higher
# up the ancestor hierarchy they match.
#
# element - The DOM element to generate the menu template for.
# * `element` The DOM element to generate the menu template for.
menuTemplateForMostSpecificElement: (element, {devMode}={}) ->
menuTemplate = @definitionsForElement(element, {devMode})
if element.parentElement
@@ -109,9 +120,12 @@ class ContextMenuManager
delete template.executeAtBuild
# Public: Request a context menu to be displayed.
#
# * `event` A DOM event.
showForEvent: (event) ->
@activeElement = event.target
menuTemplate = @combinedMenuTemplateForElement(event.target)
return unless menuTemplate?.length > 0
@executeBuildHandlers(event, menuTemplate)
remote.getCurrentWindow().emit('context-menu', menuTemplate)
undefined
+126 -65
Ver Arquivo
@@ -2,11 +2,36 @@
{Model} = require 'theorist'
_ = require 'underscore-plus'
# Public: The `Cursor` class represents the little blinking line identifying
# Extended: The `Cursor` class represents the little blinking line identifying
# where text can be inserted.
#
# Cursors belong to {Editor}s and have some metadata attached in the form
# of a {Marker}.
#
# ## Events
#
# ### moved
#
# Extended: Emit when a cursor has been moved. If there are multiple cursors,
# it will be emit for each cursor.
#
# * `event` {Object}
# * `oldBufferPosition` {Point}
# * `oldScreenPosition` {Point}
# * `newBufferPosition` {Point}
# * `newScreenPosition` {Point}
# * `textChanged` {Boolean}
#
# ### destroyed
#
# Extended: Emit when the cursor is destroyed
#
# ### visibility-changed
#
# Extended: Emit when the Cursor is hidden or shown
#
# * `visible` {Boolean} true when cursor is visible
#
module.exports =
class Cursor extends Model
screenPosition: null
@@ -63,11 +88,10 @@ class Cursor extends Model
# Public: Moves a cursor to a given screen position.
#
# screenPosition - An {Array} of two numbers: the screen row, and the screen
# column.
# options - An {Object} with the following keys:
# :autoscroll - A Boolean which, if `true`, scrolls the {Editor} to wherever
# the cursor moves to.
# * `screenPosition` {Array} of two numbers: the screen row, and the screen column.
# * `options` (optional) {Object} with the following keys:
# * `autoscroll` A Boolean which, if `true`, scrolls the {Editor} to wherever
# the cursor moves to.
setScreenPosition: (screenPosition, options={}) ->
@changePosition options, =>
@marker.setHeadScreenPosition(screenPosition, options)
@@ -82,11 +106,10 @@ class Cursor extends Model
# Public: Moves a cursor to a given buffer position.
#
# bufferPosition - An {Array} of two numbers: the buffer row, and the buffer
# column.
# options - An {Object} with the following keys:
# :autoscroll - A Boolean which, if `true`, scrolls the {Editor} to wherever
# the cursor moves to.
# * `bufferPosition` {Array} of two numbers: the buffer row, and the buffer column.
# * `options` (optional) {Object} with the following keys:
# * `autoscroll` A Boolean which, if `true`, scrolls the {Editor} to wherever
# the cursor moves to.
setBufferPosition: (bufferPosition, options={}) ->
@changePosition options, =>
@marker.setHeadBufferPosition(bufferPosition, options)
@@ -114,10 +137,9 @@ class Cursor extends Model
# Public: Get the RegExp used by the cursor to determine what a "word" is.
#
# options: An optional {Object} with the following keys:
# :includeNonWordCharacters - A {Boolean} indicating whether to include
# non-word characters in the regex.
# (default: true)
# * `options` (optional) {Object} with the following keys:
# * `includeNonWordCharacters` A {Boolean} indicating whether to include
# non-word characters in the regex. (default: true)
#
# Returns a {RegExp}.
wordRegExp: ({includeNonWordCharacters}={}) ->
@@ -135,7 +157,7 @@ class Cursor extends Model
#
# Returns a {Boolean}.
isLastCursor: ->
this == @editor.getCursor()
this == @editor.getLastCursor()
# Public: Identifies if the cursor is surrounded by whitespace.
#
@@ -200,10 +222,15 @@ class Cursor extends Model
# Public: Returns the cursor's current buffer row of text excluding its line
# ending.
getCurrentBufferLine: ->
@editor.lineForBufferRow(@getBufferRow())
@editor.lineTextForBufferRow(@getBufferRow())
# Public: Moves the cursor up one screen row.
moveUp: (rowCount = 1, {moveToEndOfSelection}={}) ->
#
# * `rowCount` (optional) {Number} number of rows to move (default: 1)
# * `options` (optional) {Object} with the following keys:
# * `moveToEndOfSelection` if true, move to the left of the selection if a
# selection exists.
moveUp: (rowCount=1, {moveToEndOfSelection}={}) ->
range = @marker.getScreenRange()
if moveToEndOfSelection and not range.isEmpty()
{ row, column } = range.start
@@ -215,7 +242,12 @@ class Cursor extends Model
@goalColumn = column
# Public: Moves the cursor down one screen row.
moveDown: (rowCount = 1, {moveToEndOfSelection}={}) ->
#
# * `rowCount` (optional) {Number} number of rows to move (default: 1)
# * `options` (optional) {Object} with the following keys:
# * `moveToEndOfSelection` if true, move to the left of the selection if a
# selection exists.
moveDown: (rowCount=1, {moveToEndOfSelection}={}) ->
range = @marker.getScreenRange()
if moveToEndOfSelection and not range.isEmpty()
{ row, column } = range.end
@@ -228,30 +260,51 @@ class Cursor extends Model
# Public: Moves the cursor left one screen column.
#
# options - An {Object} with the following keys:
# :moveToEndOfSelection - if true, move to the left of the selection if a
# selection exists.
moveLeft: ({moveToEndOfSelection}={}) ->
# * `columnCount` (optional) {Number} number of columns to move (default: 1)
# * `options` (optional) {Object} with the following keys:
# * `moveToEndOfSelection` if true, move to the left of the selection if a
# selection exists.
moveLeft: (columnCount=1, {moveToEndOfSelection}={}) ->
range = @marker.getScreenRange()
if moveToEndOfSelection and not range.isEmpty()
@setScreenPosition(range.start)
else
{row, column} = @getScreenPosition()
[row, column] = if column > 0 then [row, column - 1] else [row - 1, Infinity]
while columnCount > column and row > 0
columnCount -= column
column = @editor.lineTextForScreenRow(--row).length
columnCount-- # subtract 1 for the row move
column = column - columnCount
@setScreenPosition({row, column})
# Public: Moves the cursor right one screen column.
#
# options - An {Object} with the following keys:
# :moveToEndOfSelection - if true, move to the right of the selection if a
# selection exists.
moveRight: ({moveToEndOfSelection}={}) ->
# * `columnCount` (optional) {Number} number of columns to move (default: 1)
# * `options` (optional) {Object} with the following keys:
# * `moveToEndOfSelection` if true, move to the right of the selection if a
# selection exists.
moveRight: (columnCount=1, {moveToEndOfSelection}={}) ->
range = @marker.getScreenRange()
if moveToEndOfSelection and not range.isEmpty()
@setScreenPosition(range.end)
else
{ row, column } = @getScreenPosition()
@setScreenPosition([row, column + 1], skipAtomicTokens: true, wrapBeyondNewlines: true, wrapAtSoftNewlines: true)
maxLines = @editor.getScreenLineCount()
rowLength = @editor.lineTextForScreenRow(row).length
columnsRemainingInLine = rowLength - column
while columnCount > columnsRemainingInLine and row < maxLines - 1
columnCount -= columnsRemainingInLine
columnCount-- # subtract 1 for the row move
column = 0
rowLength = @editor.lineTextForScreenRow(++row).length
columnsRemainingInLine = rowLength
column = column + columnCount
@setScreenPosition({row, column}, skipAtomicTokens: true, wrapBeyondNewlines: true, wrapAtSoftNewlines: true)
# Public: Moves the cursor to the top of the buffer.
moveToTop: ->
@@ -287,17 +340,6 @@ class Cursor extends Model
@setBufferPosition([lineBufferRange.start.row, targetBufferColumn])
# Public: Moves the cursor to the beginning of the buffer line, skipping all
# whitespace.
skipLeadingWhitespace: ->
position = @getBufferPosition()
scanRange = @getCurrentLineBufferRange()
endOfLeadingWhitespace = null
@editor.scanInBufferRange /^[ \t]*/, scanRange, ({range}) ->
endOfLeadingWhitespace = range.end
@setBufferPosition(endOfLeadingWhitespace) if endOfLeadingWhitespace.isGreaterThan(position)
# Public: Moves the cursor to the end of the line.
moveToEndOfScreenLine: ->
@setScreenPosition([@getScreenRow(), Infinity])
@@ -330,16 +372,27 @@ class Cursor extends Model
if position = @getMoveNextWordBoundaryBufferPosition()
@setBufferPosition(position)
# Public: Moves the cursor to the beginning of the buffer line, skipping all
# whitespace.
skipLeadingWhitespace: ->
position = @getBufferPosition()
scanRange = @getCurrentLineBufferRange()
endOfLeadingWhitespace = null
@editor.scanInBufferRange /^[ \t]*/, scanRange, ({range}) ->
endOfLeadingWhitespace = range.end
@setBufferPosition(endOfLeadingWhitespace) if endOfLeadingWhitespace.isGreaterThan(position)
# Public: Retrieves the buffer position of where the current word starts.
#
# options - An {Object} with the following keys:
# :wordRegex - A {RegExp} indicating what constitutes a "word"
# (default: {::wordRegExp}).
# :includeNonWordCharacters - A {Boolean} indicating whether to include
# non-word characters in the default word regex.
# Has no effect if wordRegex is set.
# :allowPrevious - A {Boolean} indicating whether the beginning of the
# previous word can be returned.
# * `options` (optional) An {Object} with the following keys:
# * `wordRegex` A {RegExp} indicating what constitutes a "word"
# (default: {::wordRegExp}).
# * `includeNonWordCharacters` A {Boolean} indicating whether to include
# non-word characters in the default word regex.
# Has no effect if wordRegex is set.
# * `allowPrevious` A {Boolean} indicating whether the beginning of the
# previous word can be returned.
#
# Returns a {Range}.
getBeginningOfCurrentWordBufferPosition: (options = {}) ->
@@ -407,12 +460,12 @@ class Cursor extends Model
# Public: Retrieves the buffer position of where the current word ends.
#
# options - An {Object} with the following keys:
# :wordRegex - A {RegExp} indicating what constitutes a "word"
# (default: {::wordRegExp})
# :includeNonWordCharacters - A Boolean indicating whether to include
# non-word characters in the default word regex.
# Has no effect if wordRegex is set.
# * `options` (optional) {Object} with the following keys:
# * `wordRegex` A {RegExp} indicating what constitutes a "word"
# (default: {::wordRegExp})
# * `includeNonWordCharacters` A Boolean indicating whether to include
# non-word characters in the default word regex. Has no effect if
# wordRegex is set.
#
# Returns a {Range}.
getEndOfCurrentWordBufferPosition: (options = {}) ->
@@ -431,11 +484,11 @@ class Cursor extends Model
# Public: Retrieves the buffer position of where the next word starts.
#
# options -
# :wordRegex - A {RegExp} indicating what constitutes a "word"
# (default: {::wordRegExp}).
# * `options` (optional) {Object}
# * `wordRegex` A {RegExp} indicating what constitutes a "word"
# (default: {::wordRegExp}).
#
# Returns a {Range}.
# Returns a {Range}
getBeginningOfNextWordBufferPosition: (options = {}) ->
currentBufferPosition = @getBufferPosition()
start = if @isInsideWord() then @getEndOfCurrentWordBufferPosition() else currentBufferPosition
@@ -450,9 +503,9 @@ class Cursor extends Model
# Public: Returns the buffer Range occupied by the word located under the cursor.
#
# options -
# :wordRegex - A {RegExp} indicating what constitutes a "word"
# (default: {::wordRegExp}).
# * `options` (optional) {Object}
# * `wordRegex` A {RegExp} indicating what constitutes a "word"
# (default: {::wordRegExp}).
getCurrentWordBufferRange: (options={}) ->
startOptions = _.extend(_.clone(options), allowPrevious: false)
endOptions = _.extend(_.clone(options), allowNext: false)
@@ -460,9 +513,9 @@ class Cursor extends Model
# Public: Returns the buffer Range for the current line.
#
# options -
# :includeNewline: - A {Boolean} which controls whether the Range should
# include the newline.
# * `options` (optional) {Object}
# * `includeNewline` A {Boolean} which controls whether the Range should
# include the newline.
getCurrentLineBufferRange: (options) ->
@editor.bufferRangeForBufferRow(@getBufferRow(), options)
@@ -540,10 +593,18 @@ class Cursor extends Model
# its current position.
hasPrecedingCharactersOnLine: ->
bufferPosition = @getBufferPosition()
line = @editor.lineForBufferRow(bufferPosition.row)
line = @editor.lineTextForBufferRow(bufferPosition.row)
firstCharacterColumn = line.search(/\S/)
if firstCharacterColumn is -1
false
else
bufferPosition.column > firstCharacterColumn
# Public: Compare this cursor's buffer position to another cursor's buffer position.
#
# See {Point::compare} for more details.
#
# * `otherCursor`{Cursor} to compare against
compare: (otherCursor) ->
@getBufferPosition().compare(otherCursor.getBufferPosition())
+53 -32
Ver Arquivo
@@ -4,7 +4,7 @@ _ = require 'underscore-plus'
idCounter = 0
nextId = -> idCounter++
# Public: Represents a decoration that follows a {Marker}. A decoration is
# Essential: Represents a decoration that follows a {Marker}. A decoration is
# basically a visual representation of a marker. It allows you to add CSS
# classes to line numbers in the gutter, lines, and add selection-line regions
# around marked ranges of text.
@@ -20,27 +20,39 @@ nextId = -> idCounter++
#
# Best practice for destorying the decoration is by destroying the {Marker}.
#
# ```
# ```coffee
# marker.destroy()
# ```
#
# You should only use {Decoration::destroy} when you still need or do not own
# the marker.
#
# ### IDs
# Each {Decoration} has a unique ID available via `decoration.id`.
# ## Events
#
# ### Events
# A couple of events are emitted:
# ### updated
#
# * `destroyed`: When the {Decoration} is destroyed
# * `updated`: When the {Decoration} is updated via {Decoration::update}.
# Event object has properties `oldParams` and `newParams`
# Extended: When the {Decoration} is updated via {Decoration::update}.
#
# * `event` {Object}
# * `oldParams` {Object} the old parameters the decoration used to have
# * `newParams` {Object} the new parameters the decoration now has
#
# ### destroyed
#
# Extended: When the {Decoration} is destroyed
#
module.exports =
class Decoration
Emitter.includeInto(this)
# Extended: Check if the `decorationParams.type` matches `type`
#
# * `decorationParams` {Object} eg. `{type: 'gutter', class: 'my-new-class'}`
# * `type` {String} type like `'gutter'`, `'line'`, etc. `type` can also
# be an {Array} of {String}s, where it will return true if the decoration's
# type matches any in the array.
#
# Returns {Boolean}
@isType: (decorationParams, type) ->
if _.isArray(decorationParams.type)
type in decorationParams.type
@@ -53,21 +65,34 @@ class Decoration
@flashQueue = null
@isDestroyed = false
# Public: Destroy this marker.
#
# If you own the marker, you should use {Marker::destroy} which will destroy
# this decoration.
destroy: ->
return if @isDestroyed
@isDestroyed = true
@displayBuffer.removeDecoration(this)
@emit 'destroyed'
# Essential: An id unique across all {Decoration} objects
getId: -> @id
# Public: Update the marker with new params. Allows you to change the decoration's class.
# Essential: Returns the marker associated with this {Decoration}
getMarker: -> @marker
# Essential: Returns the {Decoration}'s params.
getParams: -> @params
# Public: Check if this decoration is of type `type`
#
# ```
# * `type` {String} type like `'gutter'`, `'line'`, etc. `type` can also
# be an {Array} of {String}s, where it will return true if the decoration's
# type matches any in the array.
#
# Returns {Boolean}
isType: (type) ->
Decoration.isType(@params, type)
# Essential: Update the marker with new params. Allows you to change the decoration's class.
#
# ## Examples
#
# ```coffee
# decoration.update({type: 'gutter', class: 'my-new-class'})
# ```
#
# * `newParams` {Object} eg. `{type: 'gutter', class: 'my-new-class'}`
update: (newParams) ->
return if @isDestroyed
oldParams = @params
@@ -76,19 +101,15 @@ class Decoration
@displayBuffer.decorationUpdated(this)
@emit 'updated', {oldParams, newParams}
# Public: Returns the marker associated with this {Decoration}
getMarker: -> @marker
# Public: Returns the {Decoration}'s params.
getParams: -> @params
# Public: Check if this decoration is of type `type`
# Essential: Destroy this marker.
#
# type - A {String} type like `'gutter'`
#
# Returns a {Boolean}
isType: (type) ->
Decoration.isType(@params, type)
# If you own the marker, you should use {Marker::destroy} which will destroy
# this decoration.
destroy: ->
return if @isDestroyed
@isDestroyed = true
@displayBuffer.removeDecoration(this)
@emit 'destroyed'
matchesPattern: (decorationPattern) ->
return false unless decorationPattern?
+7 -7
Ver Arquivo
@@ -3,7 +3,7 @@
# An instance of this class is always available as the `atom.deserializers`
# global.
#
# ### Registering a deserializer
# ## Examples
#
# ```coffee
# class MyPackageView extends View
@@ -24,21 +24,21 @@ class DeserializerManager
# Public: Register the given class(es) as deserializers.
#
# classes - One or more classes to register.
# * `classes` One or more classes to register.
add: (classes...) ->
@deserializers[klass.name] = klass for klass in classes
# Public: Remove the given class(es) as deserializers.
#
# classes - One or more classes to remove.
# * `classes` One or more classes to remove.
remove: (classes...) ->
delete @deserializers[name] for {name} in classes
# Public: Deserialize the state and params.
#
# state - The state {Object} to deserialize.
# params - The params {Object} to pass as the second arguments to the
# deserialize method of the deserializer.
# * `state` The state {Object} to deserialize.
# * `params` The params {Object} to pass as the second arguments to the
# deserialize method of the deserializer.
deserialize: (state, params) ->
return unless state?
@@ -51,7 +51,7 @@ class DeserializerManager
# Get the deserializer for the state.
#
# state - The state {Object} being deserialized.
# * `state` The state {Object} being deserialized.
get: (state) ->
return unless state?
+2 -2
Ver Arquivo
@@ -22,8 +22,8 @@ class DisplayBufferMarker
@oldTailScreenPosition = @getTailScreenPosition()
@wasValid = @isValid()
@subscribe @bufferMarker, 'destroyed', => @destroyed()
@subscribe @bufferMarker, 'changed', (event) => @notifyObservers(event)
@subscribe @bufferMarker.onDidDestroy => @destroyed()
@subscribe @bufferMarker.onDidChange (event) => @notifyObservers(event)
copy: (attributes) ->
@displayBuffer.getMarker(@bufferMarker.copy(attributes).id)
+14 -14
Ver Arquivo
@@ -55,8 +55,8 @@ class DisplayBuffer extends Model
@subscribe @tokenizedBuffer, 'grammar-changed', (grammar) => @emit 'grammar-changed', grammar
@subscribe @tokenizedBuffer, 'tokenized', => @emit 'tokenized'
@subscribe @tokenizedBuffer, 'changed', @handleTokenizedBufferChange
@subscribe @buffer, 'markers-updated', @handleBufferMarkersUpdated
@subscribe @buffer, 'marker-created', @handleBufferMarkerCreated
@subscribe @buffer.onDidUpdateMarkers @handleBufferMarkersUpdated
@subscribe @buffer.onDidCreateMarker @handleBufferMarkerCreated
@subscribe @$softWrap, (softWrap) =>
@emit 'soft-wrap-changed', softWrap
@@ -377,25 +377,25 @@ class DisplayBuffer extends Model
# Gets the screen line for the given screen row.
#
# screenRow - A {Number} indicating the screen row.
# * `screenRow` - A {Number} indicating the screen row.
#
# Returns a {ScreenLine}.
lineForRow: (row) ->
@screenLines[row]
# Returns {TokenizedLine}
tokenizedLineForScreenRow: (screenRow) ->
@screenLines[screenRow]
# Gets the screen lines for the given screen row range.
#
# startRow - A {Number} indicating the beginning screen row.
# endRow - A {Number} indicating the ending screen row.
#
# Returns an {Array} of {ScreenLine}s.
linesForRows: (startRow, endRow) ->
# Returns an {Array} of {TokenizedLine}s.
tokenizedLinesForScreenRows: (startRow, endRow) ->
@screenLines[startRow..endRow]
# Gets all the screen lines.
#
# Returns an {Array} of {ScreenLines}s.
getLines: ->
# Returns an {Array} of {TokenizedLine}s.
getTokenizedLines: ->
new Array(@screenLines...)
indentLevelForLine: (line) ->
@@ -555,7 +555,7 @@ class DisplayBuffer extends Model
top = targetRow * @lineHeightInPixels
left = 0
column = 0
for token in @lineForRow(targetRow).tokens
for token in @tokenizedLineForScreenRow(targetRow).tokens
charWidths = @getScopedCharWidths(token.scopes)
for char in token.value
return {top, left} if column is targetColumn
@@ -573,7 +573,7 @@ class DisplayBuffer extends Model
left = 0
column = 0
for token in @lineForRow(row).tokens
for token in @tokenizedLineForScreenRow(row).tokens
charWidths = @getScopedCharWidths(token.scopes)
for char in token.value
charWidth = charWidths[char] ? defaultCharWidth
@@ -983,7 +983,7 @@ class DisplayBuffer extends Model
logLines: (start=0, end=@getLastRow()) ->
for row in [start..end]
line = @lineForRow(row).text
line = @tokenizedLineForScreenRow(row).text
console.log row, @bufferRowForScreenRow(row), line, line.length
handleTokenizedBufferChange: (tokenizedBufferChange) =>
@@ -1024,7 +1024,7 @@ class DisplayBuffer extends Model
bufferRow = startBufferRow
while bufferRow < endBufferRow
tokenizedLine = @tokenizedBuffer.lineForScreenRow(bufferRow)
tokenizedLine = @tokenizedBuffer.tokenizedLineForRow(bufferRow)
if fold = @largestFoldStartingAtBufferRow(bufferRow)
foldLine = tokenizedLine.copy()
+67 -34
Ver Arquivo
@@ -1,3 +1,4 @@
_ = require 'underscore-plus'
React = require 'react-atom-fork'
{div, span} = require 'reactionary-atom-fork'
{debounce, defaults, isEqualForProperties} = require 'underscore-plus'
@@ -51,7 +52,7 @@ EditorComponent = React.createClass
{focused, showIndentGuide, showLineNumbers, visible} = @state
{editor, mini, cursorBlinkPeriod, cursorBlinkResumeDelay} = @props
maxLineNumberDigits = editor.getLineCount().toString().length
hasSelection = editor.getSelection()? and !editor.getSelection().isEmpty()
hasSelection = editor.getLastSelection()? and !editor.getLastSelection().isEmpty()
style = {}
if @performedInitialMeasurement
@@ -59,7 +60,7 @@ EditorComponent = React.createClass
[renderedStartRow, renderedEndRow] = renderedRowRange
cursorPixelRects = @getCursorPixelRects(renderedRowRange)
tokenizedLines = editor.linesForScreenRows(renderedStartRow, renderedEndRow - 1)
tokenizedLines = editor.tokenizedLinesForScreenRows(renderedStartRow, renderedEndRow - 1)
decorations = editor.decorationsForScreenRowRange(renderedStartRow, renderedEndRow)
highlightDecorations = @getHighlightDecorations(decorations)
@@ -183,12 +184,13 @@ EditorComponent = React.createClass
@checkForVisibilityChange()
componentWillUnmount: ->
@props.parentView.trigger 'editor:will-be-removed', [@props.parentView]
{editor, parentView} = @props
parentView.trigger 'editor:will-be-removed', [parentView]
@unsubscribe()
window.removeEventListener 'resize', @requestHeightAndWidthMeasurement
clearInterval(@domPollingIntervalId)
@domPollingIntervalId = null
@props.editor.destroy()
componentWillReceiveProps: (newProps) ->
@props.editor.setMini(newProps.mini)
@@ -258,9 +260,9 @@ EditorComponent = React.createClass
getHiddenInputPosition: ->
{editor} = @props
{focused} = @state
return {top: 0, left: 0} unless @isMounted() and focused and editor.getCursor()?
return {top: 0, left: 0} unless @isMounted() and focused and editor.getLastCursor()?
{top, left, height, width} = editor.getCursor().getPixelRect()
{top, left, height, width} = editor.getLastCursor().getPixelRect()
width = 2 if width is 0 # Prevent autoscroll at the end of longest line
top -= editor.getScrollTop()
left -= editor.getScrollLeft()
@@ -403,8 +405,8 @@ EditorComponent = React.createClass
{parentView, editor, mini} = @props
@addCommandListeners
'core:move-left': -> editor.moveCursorLeft()
'core:move-right': -> editor.moveCursorRight()
'core:move-left': -> editor.moveLeft()
'core:move-right': -> editor.moveRight()
'core:select-left': -> editor.selectLeft()
'core:select-right': -> editor.selectRight()
'core:select-all': -> editor.selectAll()
@@ -415,8 +417,8 @@ EditorComponent = React.createClass
'core:cut': -> editor.cutSelectedText()
'core:copy': -> editor.copySelectedText()
'core:paste': -> editor.pasteText()
'editor:move-to-previous-word': -> editor.moveCursorToPreviousWord()
'editor:select-word': -> editor.selectWord()
'editor:move-to-previous-word': -> editor.moveToPreviousWord()
'editor:select-word': -> editor.selectWordsContainingCursors()
'editor:consolidate-selections': @consolidateSelections
'editor:delete-to-beginning-of-word': -> editor.deleteToBeginningOfWord()
'editor:delete-to-beginning-of-line': -> editor.deleteToBeginningOfLine()
@@ -424,18 +426,18 @@ EditorComponent = React.createClass
'editor:delete-to-end-of-word': -> editor.deleteToEndOfWord()
'editor:delete-line': -> editor.deleteLine()
'editor:cut-to-end-of-line': -> editor.cutToEndOfLine()
'editor:move-to-beginning-of-next-paragraph': -> editor.moveCursorToBeginningOfNextParagraph()
'editor:move-to-beginning-of-previous-paragraph': -> editor.moveCursorToBeginningOfPreviousParagraph()
'editor:move-to-beginning-of-screen-line': -> editor.moveCursorToBeginningOfScreenLine()
'editor:move-to-beginning-of-line': -> editor.moveCursorToBeginningOfLine()
'editor:move-to-end-of-screen-line': -> editor.moveCursorToEndOfScreenLine()
'editor:move-to-end-of-line': -> editor.moveCursorToEndOfLine()
'editor:move-to-first-character-of-line': -> editor.moveCursorToFirstCharacterOfLine()
'editor:move-to-beginning-of-word': -> editor.moveCursorToBeginningOfWord()
'editor:move-to-end-of-word': -> editor.moveCursorToEndOfWord()
'editor:move-to-beginning-of-next-word': -> editor.moveCursorToBeginningOfNextWord()
'editor:move-to-previous-word-boundary': -> editor.moveCursorToPreviousWordBoundary()
'editor:move-to-next-word-boundary': -> editor.moveCursorToNextWordBoundary()
'editor:move-to-beginning-of-next-paragraph': -> editor.moveToBeginningOfNextParagraph()
'editor:move-to-beginning-of-previous-paragraph': -> editor.moveToBeginningOfPreviousParagraph()
'editor:move-to-beginning-of-screen-line': -> editor.moveToBeginningOfScreenLine()
'editor:move-to-beginning-of-line': -> editor.moveToBeginningOfLine()
'editor:move-to-end-of-screen-line': -> editor.moveToEndOfScreenLine()
'editor:move-to-end-of-line': -> editor.moveToEndOfLine()
'editor:move-to-first-character-of-line': -> editor.moveToFirstCharacterOfLine()
'editor:move-to-beginning-of-word': -> editor.moveToBeginningOfWord()
'editor:move-to-end-of-word': -> editor.moveToEndOfWord()
'editor:move-to-beginning-of-next-word': -> editor.moveToBeginningOfNextWord()
'editor:move-to-previous-word-boundary': -> editor.moveToPreviousWordBoundary()
'editor:move-to-next-word-boundary': -> editor.moveToNextWordBoundary()
'editor:select-to-beginning-of-next-paragraph': -> editor.selectToBeginningOfNextParagraph()
'editor:select-to-beginning-of-previous-paragraph': -> editor.selectToBeginningOfPreviousParagraph()
'editor:select-to-end-of-line': -> editor.selectToEndOfLine()
@@ -446,17 +448,17 @@ EditorComponent = React.createClass
'editor:select-to-next-word-boundary': -> editor.selectToNextWordBoundary()
'editor:select-to-previous-word-boundary': -> editor.selectToPreviousWordBoundary()
'editor:select-to-first-character-of-line': -> editor.selectToFirstCharacterOfLine()
'editor:select-line': -> editor.selectLine()
'editor:select-line': -> editor.selectLinesContainingCursors()
'editor:transpose': -> editor.transpose()
'editor:upper-case': -> editor.upperCase()
'editor:lower-case': -> editor.lowerCase()
unless mini
@addCommandListeners
'core:move-up': -> editor.moveCursorUp()
'core:move-down': -> editor.moveCursorDown()
'core:move-to-top': -> editor.moveCursorToTop()
'core:move-to-bottom': -> editor.moveCursorToBottom()
'core:move-up': -> editor.moveUp()
'core:move-down': -> editor.moveDown()
'core:move-to-top': -> editor.moveToTop()
'core:move-to-bottom': -> editor.moveToBottom()
'core:page-up': -> editor.pageUp()
'core:page-down': -> editor.pageDown()
'core:select-up': -> editor.selectUp()
@@ -614,6 +616,9 @@ EditorComponent = React.createClass
# CTRL+click brings up the context menu on OSX, so don't handle those either
return if ctrlKey and process.platform is 'darwin'
# Prevent focusout event on hidden input if editor is already focused
event.preventDefault() if @state.focused
screenPosition = @screenPositionForMouseEvent(event)
if event.target?.classList.contains('fold-marker')
@@ -640,8 +645,12 @@ EditorComponent = React.createClass
onGutterMouseDown: (event) ->
return unless event.button is 0 # only handle the left mouse button
if event.shiftKey
{shiftKey, metaKey, ctrlKey} = event
if shiftKey
@onGutterShiftClick(event)
else if metaKey or (ctrlKey and process.platform isnt 'darwin')
@onGutterMetaClick(event)
else
@onGutterClick(event)
@@ -649,19 +658,43 @@ EditorComponent = React.createClass
{editor} = @props
clickedRow = @screenPositionForMouseEvent(event).row
editor.setCursorScreenPosition([clickedRow, 0])
editor.setSelectedScreenRange([[clickedRow, 0], [clickedRow + 1, 0]], preserveFolds: true)
@handleDragUntilMouseUp event, (screenPosition) ->
dragRow = screenPosition.row
if dragRow < clickedRow # dragging up
editor.setSelectedScreenRange([[dragRow, 0], [clickedRow + 1, 0]])
editor.setSelectedScreenRange([[dragRow, 0], [clickedRow + 1, 0]], preserveFolds: true)
else
editor.setSelectedScreenRange([[clickedRow, 0], [dragRow + 1, 0]])
editor.setSelectedScreenRange([[clickedRow, 0], [dragRow + 1, 0]], preserveFolds: true)
onGutterMetaClick: (event) ->
{editor} = @props
clickedRow = @screenPositionForMouseEvent(event).row
bufferRange = editor.bufferRangeForScreenRange([[clickedRow, 0], [clickedRow + 1, 0]])
rowSelection = editor.addSelectionForBufferRange(bufferRange, preserveFolds: true)
@handleDragUntilMouseUp event, (screenPosition) ->
dragRow = screenPosition.row
if dragRow < clickedRow # dragging up
rowSelection.setScreenRange([[dragRow, 0], [clickedRow + 1, 0]], preserveFolds: true)
else
rowSelection.setScreenRange([[clickedRow, 0], [dragRow + 1, 0]], preserveFolds: true)
# After updating the selected screen range, merge overlapping selections
editor.mergeIntersectingSelections(preserveFolds: true)
# The merge process will possibly destroy the current selection because
# it will be merged into another one. Therefore, we need to obtain a
# reference to the new selection that contains the originally selected row
rowSelection = _.find editor.getSelections(), (selection) ->
selection.intersectsBufferRange(bufferRange)
onGutterShiftClick: (event) ->
{editor} = @props
clickedRow = @screenPositionForMouseEvent(event).row
tailPosition = editor.getSelection().getTailScreenPosition()
tailPosition = editor.getLastSelection().getTailScreenPosition()
if clickedRow < tailPosition.row
editor.selectToScreenPosition([clickedRow, 0])
@@ -671,9 +704,9 @@ EditorComponent = React.createClass
@handleDragUntilMouseUp event, (screenPosition) ->
dragRow = screenPosition.row
if dragRow < tailPosition.row # dragging up
editor.setSelectedScreenRange([[dragRow, 0], tailPosition])
editor.setSelectedScreenRange([[dragRow, 0], tailPosition], preserveFolds: true)
else
editor.setSelectedScreenRange([tailPosition, [dragRow + 1, 0]])
editor.setSelectedScreenRange([tailPosition, [dragRow + 1, 0]], preserveFolds: true)
onStylesheetsChanged: (stylesheet) ->
return unless @performedInitialMeasurement
+65 -61
Ver Arquivo
@@ -10,7 +10,9 @@ EditorComponent = require './editor-component'
#
# The EditorView manages the {Editor}, which manages the file buffers.
#
# ## Requiring in packages
# ## Examples
#
# Requiring in packages
#
# ```coffee
# {EditorView} = require 'atom'
@@ -18,14 +20,14 @@ EditorComponent = require './editor-component'
# miniEditorView = new EditorView(mini: true)
# ```
#
# ## Iterating over the open editor views
# Iterating over the open editor views
#
# ```coffee
# for editorView in atom.workspaceView.getEditorViews()
# console.log(editorView.getModel().getPath())
# ```
#
# ## Subscribing to every current and future editor
# Subscribing to every current and future editor
#
# ```coffee
# atom.workspace.eachEditorView (editorView) ->
@@ -67,10 +69,10 @@ class EditorView extends View
# The constructor for setting up an `EditorView` instance.
#
# editorOrParams - Either an {Editor}, or an object with one property, `mini`.
# If `mini` is `true`, a "miniature" `Editor` is constructed.
# Typically, this is ideal for scenarios where you need an Atom editor,
# but without all the chrome, like scrollbars, gutter, _e.t.c._.
# * `editorOrParams` Either an {Editor}, or an object with one property, `mini`.
# If `mini` is `true`, a "miniature" `Editor` is constructed.
# Typically, this is ideal for scenarios where you need an Atom editor,
# but without all the chrome, like scrollbars, gutter, _e.t.c._.
#
constructor: (editorOrParams, props) ->
super
@@ -99,7 +101,6 @@ class EditorView extends View
@overlayer = $(node).find('.lines').addClass('overlayer')
@hiddenInput = $(node).find('.hidden-input')
# FIXME: there should be a better way to deal with the gutter element
@subscribe atom.config.observe 'editor.showLineNumbers', =>
@gutter = $(node).find('.gutter')
@@ -125,7 +126,7 @@ class EditorView extends View
# Public: Get the underlying editor model for this view.
#
# Returns an {Editor}.
# Returns an {Editor}
getModel: -> @editor
getEditor: -> @editor
@@ -167,45 +168,28 @@ class EditorView extends View
else
@editor.getScrollLeft()
# Public: Scrolls the editor to the bottom.
scrollToBottom: ->
deprecate 'Use Editor::scrollToBottom instead. You can get the editor via editorView.getModel()'
@editor.setScrollBottom(Infinity)
# Public: Scrolls the editor to the given screen position.
#
# screenPosition - An object that represents a buffer position. It can be either
# an {Object} (`{row, column}`), {Array} (`[row, column]`), or {Point}
# options - A hash matching the options available to {::scrollToScreenPosition}
scrollToScreenPosition: (screenPosition, options) ->
deprecate 'Use Editor::scrollToScreenPosition instead. You can get the editor via editorView.getModel()'
@editor.scrollToScreenPosition(screenPosition, options)
# Public: Scrolls the editor to the given buffer position.
#
# bufferPosition - An object that represents a buffer position. It can be either
# an {Object} (`{row, column}`), {Array} (`[row, column]`), or {Point}
# options - A hash matching the options available to {::scrollToBufferPosition}
scrollToBufferPosition: (bufferPosition, options) ->
deprecate 'Use Editor::scrollToBufferPosition instead. You can get the editor via editorView.getModel()'
@editor.scrollToBufferPosition(bufferPosition, options)
scrollToCursorPosition: ->
deprecate 'Use Editor::scrollToCursorPosition instead. You can get the editor via editorView.getModel()'
@editor.scrollToCursorPosition()
# Public: Converts a buffer position to a pixel position.
#
# position - An object that represents a buffer position. It can be either
# an {Object} (`{row, column}`), {Array} (`[row, column]`), or {Point}
#
# Returns an object with two values: `top` and `left`, representing the pixel positions.
pixelPositionForBufferPosition: (bufferPosition) ->
deprecate 'Use Editor::pixelPositionForBufferPosition instead. You can get the editor via editorView.getModel()'
@editor.pixelPositionForBufferPosition(bufferPosition)
# Public: Converts a screen position to a pixel position.
#
# position - An object that represents a screen position. It can be either
# an {Object} (`{row, column}`), {Array} (`[row, column]`), or {Point}
#
# Returns an object with two values: `top` and `left`, representing the pixel positions.
pixelPositionForScreenPosition: (screenPosition) ->
deprecate 'Use Editor::pixelPositionForScreenPosition instead. You can get the editor via editorView.getModel()'
@editor.pixelPositionForScreenPosition(screenPosition)
appendToLinesView: (view) ->
@@ -213,37 +197,66 @@ class EditorView extends View
view.css('z-index', 1)
@find('.lines').prepend(view)
detach: ->
return unless @attached
super
@attached = false
@unmountComponent()
beforeRemove: ->
return unless @attached
@attached = false
React.unmountComponentAtNode(@element) if @component.isMounted()
@unmountComponent()
@editor.destroy()
@trigger 'editor:detached', this
# Public: Split the editor view left.
unmountComponent: ->
React.unmountComponentAtNode(@element) if @component.isMounted()
splitLeft: ->
deprecate """
Use Pane::splitLeft instead.
To duplicate this editor into the split use:
editorView.getPaneView().getModel().splitLeft(copyActiveItem: true)
"""
pane = @getPane()
pane?.splitLeft(pane?.copyActiveItem()).activeView
# Public: Split the editor view right.
splitRight: ->
deprecate """
Use Pane::splitRight instead.
To duplicate this editor into the split use:
editorView.getPaneView().getModel().splitRight(copyActiveItem: true)
"""
pane = @getPane()
pane?.splitRight(pane?.copyActiveItem()).activeView
# Public: Split the editor view up.
splitUp: ->
deprecate """
Use Pane::splitUp instead.
To duplicate this editor into the split use:
editorView.getPaneView().getModel().splitUp(copyActiveItem: true)
"""
pane = @getPane()
pane?.splitUp(pane?.copyActiveItem()).activeView
# Public: Split the editor view down.
splitDown: ->
deprecate """
Use Pane::splitDown instead.
To duplicate this editor into the split use:
editorView.getPaneView().getModel().splitDown(copyActiveItem: true)
"""
pane = @getPane()
pane?.splitDown(pane?.copyActiveItem()).activeView
# Public: Get this view's pane.
# Public: Get this {EditorView}'s {PaneView}.
#
# Returns a {Pane}.
getPane: ->
# Returns a {PaneView}
getPaneView: ->
@parent('.item-views').parents('.pane').view()
getPane: ->
deprecate 'Use EditorView::getPaneView() instead'
@getPaneView()
show: ->
super
@@ -261,19 +274,13 @@ class EditorView extends View
deprecate('Use editorView.getModel().pageUp()')
@editor.pageUp()
# Public: Retrieves the number of the row that is visible and currently at the
# top of the editor.
#
# Returns a {Number}.
getFirstVisibleScreenRow: ->
@editor.getVisibleRowRange()[0]
deprecate 'Use Editor::getFirstVisibleScreenRow instead. You can get the editor via editorView.getModel()'
@editor.getFirstVisibleScreenRow()
# Public: Retrieves the number of the row that is visible and currently at the
# bottom of the editor.
#
# Returns a {Number}.
getLastVisibleScreenRow: ->
@editor.getVisibleRowRange()[1]
deprecate 'Use Editor::getLastVisibleScreenRow instead. You can get the editor via editorView.getModel()'
@editor.getLastVisibleScreenRow()
# Public: Gets the font family for the editor.
#
@@ -283,7 +290,7 @@ class EditorView extends View
# Public: Sets the font family for the editor.
#
# fontFamily - A {String} identifying the CSS `font-family`.
# * `fontFamily` A {String} identifying the CSS `font-family`.
setFontFamily: (fontFamily) ->
@component?.setFontFamily(fontFamily)
@@ -295,7 +302,7 @@ class EditorView extends View
# Public: Sets the font size for the editor.
#
# fontSize - A {Number} indicating the font size in pixels.
# * `fontSize` A {Number} indicating the font size in pixels.
setFontSize: (fontSize) ->
@component?.setFontSize(fontSize)
@@ -306,27 +313,24 @@ class EditorView extends View
#
# Calling this method has no effect when called on a mini editor.
#
# lineHeight - A {Number} without a unit suffix identifying the CSS
# `line-height`.
# * `lineHeight` A {Number} without a unit suffix identifying the CSS `line-height`.
setLineHeight: (lineHeight) ->
@component.setLineHeight(lineHeight)
# Public: Sets whether you want to show the indentation guides.
#
# showIndentGuide - A {Boolean} you can set to `true` if you want to see the
# indentation guides.
# * `showIndentGuide` A {Boolean} you can set to `true` if you want to see the
# indentation guides.
setShowIndentGuide: (showIndentGuide) ->
@component.setShowIndentGuide(showIndentGuide)
# Public: Enables/disables soft wrap on the editor.
#
# softWrap - A {Boolean} which, if `true`, enables soft wrap
setSoftWrap: (softWrap) ->
deprecate 'Use Editor::setSoftWrap instead. You can get the editor via editorView.getModel()'
@editor.setSoftWrap(softWrap)
# Public: Set whether invisible characters are shown.
#
# showInvisibles - A {Boolean} which, if `true`, show invisible characters.
# * `showInvisibles` A {Boolean} which, if `true`, show invisible characters.
setShowInvisibles: (showInvisibles) ->
@component.setShowInvisibles(showInvisibles)
@@ -361,7 +365,7 @@ class EditorView extends View
#
# This only affects mini editors.
#
# placeholderText - A {String} of text to display when empty.
# * `placeholderText` A {String} of text to display when empty.
setPlaceholderText: (placeholderText) ->
if @component?
@component.setProps({placeholderText})
+1941 -1537
Ver Arquivo
Diferenças do arquivo suprimidas por serem muito extensas Carregar Diff
+2 -2
Ver Arquivo
@@ -14,8 +14,8 @@ class Fold
@id = @marker.id
@displayBuffer.foldsByMarkerId[@marker.id] = this
@updateDisplayBuffer()
@marker.on 'destroyed', => @destroyed()
@marker.on 'changed', ({isValid}) => @destroy() unless isValid
@marker.onDidDestroy => @destroyed()
@marker.onDidChange ({isValid}) => @destroy() unless isValid
# Returns whether this fold is contained within another fold
isInsideLargerFold: ->
+65 -57
Ver Arquivo
@@ -25,17 +25,19 @@ Task = require './task'
# repo.getShortHead('vendor/path/to/a/submodule') # 'dead1234'
# ```
#
# ## Example
# ## Examples
#
# ```coffeescript
# ### Logging the URL of the origin remote
#
# ```coffee
# git = atom.project.getRepo()
# console.log git.getOriginUrl()
# ```
#
# ## Requiring in packages
# ### Requiring in packages
#
# ```coffee
# {Git} = require 'atom'
# {Git} = require 'atom'
# ```
module.exports =
class Git
@@ -44,12 +46,12 @@ class Git
# Public: Creates a new Git instance.
#
# path - The path to the Git repository to open.
# options - An object with the following keys (default: {}):
# :refreshOnWindowFocus - `true` to refresh the index and statuses when the
# window is focused.
# * `path` The {String} path to the Git repository to open.
# * `options` An optinal {Object} with the following keys:
# * `refreshOnWindowFocus` A {Boolean}, `true` to refresh the index and
# statuses when the window is focused.
#
# Returns a Git instance or null if the repository could not be opened.
# Returns a {Git} instance or `null` if the repository could not be opened.
@open: (path, options) ->
return null unless path
try
@@ -88,10 +90,14 @@ class Git
# Subscribes to buffer events.
subscribeToBuffer: (buffer) ->
@subscribe buffer, 'saved reloaded path-changed', =>
getBufferPathStatus = =>
if path = buffer.getPath()
@getPathStatus(path)
@subscribe buffer, 'destroyed', => @unsubscribe(buffer)
@subscribe buffer.onDidSave(getBufferPathStatus)
@subscribe buffer.onDidReload(getBufferPathStatus)
@subscribe buffer.onDidChangePath(getBufferPathStatus)
@subscribe buffer.onDidDestroy => @unsubscribe(buffer)
# Subscribes to editor view event.
checkoutHeadForEditor: (editor) ->
@@ -114,8 +120,10 @@ class Git
else
checkoutHead()
# Public: Destroy this `Git` object. This destroys any tasks and subscriptions
# and releases the underlying libgit2 repository handle.
# Public: Destroy this {Git} object.
#
# This destroys any tasks and subscriptions and releases the underlying
# libgit2 repository handle.
destroy: ->
if @statusTask?
@statusTask.terminate()
@@ -147,7 +155,7 @@ class Git
# Public: Get the status of a single path in the repository.
#
# path - A {String} repository-relative path.
# `path` A {String} repository-relative path.
#
# Returns a {Number} representing the status. This value can be passed to
# {::isStatusModified} or {::isStatusNew} to get more information.
@@ -196,8 +204,8 @@ class Git
# `refs/remotes`. It also shortens the SHA-1 of a detached `HEAD` to 7
# characters.
#
# path - An optional {String} path in the repository to get this information
# for, only needed if the repository contains submodules.
# * `path` An optional {String} path in the repository to get this information
# for, only needed if the repository contains submodules.
#
# Returns a {String}.
getShortHead: (path) -> @getRepo(path).getShortHead()
@@ -207,12 +215,12 @@ class Git
#
# This is essentially the same as running:
#
# ```
# git reset HEAD -- <path>
# git checkout HEAD -- <path>
# ```sh
# git reset HEAD -- <path>
# git checkout HEAD -- <path>
# ```
#
# path - The {String} path to checkout.
# * `path` The {String} path to checkout.
#
# Returns a {Boolean} that's true if the method was successful.
checkoutHead: (path) ->
@@ -223,9 +231,9 @@ class Git
# Public: Checks out a branch in your repository.
#
# reference - The String reference to checkout
# create - A Boolean value which, if true creates the new reference if it
# doesn't exist.
# * `reference` The {String} reference to checkout.
# * `create` A {Boolean} value which, if true creates the new reference if
# it doesn't exist.
#
# Returns a Boolean that's true if the method was successful.
checkoutReference: (reference, create) ->
@@ -236,18 +244,18 @@ class Git
# This compares the working directory contents of the path to the `HEAD`
# version.
#
# path - The {String} path to check.
# * `path` The {String} path to check.
#
# Returns an {Object} with the following keys:
# :added - The {Number} of added lines.
# :deleted - The {Number} of deleted lines.
# * `added` The {Number} of added lines.
# * `deleted` The {Number} of deleted lines.
getDiffStats: (path) ->
repo = @getRepo(path)
repo.getDiffStats(repo.relativize(path))
# Public: Is the given path a submodule in the repository?
#
# path - The {String} path to check.
# * `path` The {String} path to check.
#
# Returns a {Boolean}.
isSubmodule: (path) ->
@@ -262,7 +270,7 @@ class Git
# Public: Get the status of a directory in the repository's working directory.
#
# path - The {String} path to check.
# * `path` The {String} path to check.
#
# Returns a {Number} representing the status. This value can be passed to
# {::isStatusModified} or {::isStatusNew} to get more information.
@@ -276,14 +284,14 @@ class Git
# Public: Retrieves the line diffs comparing the `HEAD` version of the given
# path and the given text.
#
# path - The {String} path relative to the repository.
# text - The {String} to compare against the `HEAD` contents
# * `path` The {String} path relative to the repository.
# * `text` The {String} to compare against the `HEAD` contents
#
# Returns an {Array} of hunk {Object}s with the following keys:
# :oldStart - The line {Number} of the old hunk.
# :newStart - The line {Number} of the new hunk.
# :oldLines - The {Number} of lines in the old hunk.
# :newLines - The {Number} of lines in the new hunk
# * `oldStart` The line {Number} of the old hunk.
# * `newStart` The line {Number} of the new hunk.
# * `oldLines` The {Number} of lines in the old hunk.
# * `newLines` The {Number} of lines in the new hunk
getLineDiffs: (path, text) ->
# Ignore eol of line differences on windows so that files checked in as
# LF don't report every line modified when the text contains CRLF endings.
@@ -293,68 +301,68 @@ class Git
# Public: Returns the git configuration value specified by the key.
#
# path - An optional {String} path in the repository to get this information
# for, only needed if the repository has submodules.
# * `path` An optional {String} path in the repository to get this information
# for, only needed if the repository has submodules.
getConfigValue: (key, path) -> @getRepo(path).getConfigValue(key)
# Public: Returns the origin url of the repository.
#
# path - An optional {String} path in the repository to get this information
# for, only needed if the repository has submodules.
# * `path` An optional {String} path in the repository to get this information
# for, only needed if the repository has submodules.
getOriginUrl: (path) -> @getConfigValue('remote.origin.url', path)
# Public: Returns the upstream branch for the current HEAD, or null if there
# is no upstream branch for the current HEAD.
#
# path - An optional {String} path in the repo to get this information for,
# only needed if the repository contains submodules.
# * `path` An optional {String} path in the repo to get this information for,
# only needed if the repository contains submodules.
#
# Returns a {String} branch name such as `refs/remotes/origin/master`.
getUpstreamBranch: (path) -> @getRepo(path).getUpstreamBranch()
# Public: Returns the current SHA for the given reference.
# Public: Returns the current {String} SHA for the given reference.
#
# reference - The {String} reference to get the target of.
# path - An optional {String} path in the repo to get the reference target
# for. Only needed if the repository contains submodules.
# * `reference` The {String} reference to get the target of.
# * `path` An optional {String} path in the repo to get the reference target
# for. Only needed if the repository contains submodules.
getReferenceTarget: (reference, path) ->
@getRepo(path).getReferenceTarget(reference)
# Public: Gets all the local and remote references.
#
# path - An optional {String} path in the repository to get this information
# for, only needed if the repository has submodules.
# * `path` An optional {String} path in the repository to get this information
# for, only needed if the repository has submodules.
#
# Returns an {Object} with the following keys:
# :heads - An {Array} of head reference names.
# :remotes - An {Array} of remote reference names.
# :tags - An {Array} of tag reference names.
# * `heads` An {Array} of head reference names.
# * `remotes` An {Array} of remote reference names.
# * `tags` An {Array} of tag reference names.
getReferences: (path) -> @getRepo(path).getReferences()
# Public: Returns the number of commits behind the current branch is from the
# its upstream remote branch.
#
# reference - The {String} branch reference name.
# path - The {String} path in the repository to get this information for,
# only needed if the repository contains submodules.
# * `reference` The {String} branch reference name.
# * `path` The {String} path in the repository to get this information for,
# only needed if the repository contains submodules.
getAheadBehindCount: (reference, path) ->
@getRepo(path).getAheadBehindCount(reference)
# Public: Get the cached ahead/behind commit counts for the current branch's
# upstream branch.
#
# path - An optional {String} path in the repository to get this information
# for, only needed if the repository has submodules.
# * `path` An optional {String} path in the repository to get this information
# for, only needed if the repository has submodules.
#
# Returns an {Object} with the following keys:
# :ahead - The {Number} of commits ahead.
# :behind - The {Number} of commits behind.
# * `ahead` The {Number} of commits ahead.
# * `behind` The {Number} of commits behind.
getCachedUpstreamAheadBehindCount: (path) ->
@getRepo(path).upstream ? @upstream
# Public: Get the cached status for the given path.
#
# path - A {String} path in the repository, relative or absolute.
# * `path` A {String} path in the repository, relative or absolute.
#
# Returns a status {Number} or null if the path is not in the cache.
getCachedPathStatus: (path) ->
+9 -1
Ver Arquivo
@@ -21,7 +21,7 @@ GutterComponent = React.createClass
if gutterBackgroundColor isnt 'rbga(0, 0, 0, 0)'
backgroundColor = gutterBackgroundColor
div className: 'gutter', onClick: @onClick, onMouseDown: onMouseDown,
div className: 'gutter', onClick: @onClick, onMouseDown: @onMouseDown,
div className: 'line-numbers', ref: 'lineNumbers', style:
height: Math.max(scrollHeight, scrollViewHeight)
WebkitTransform: @getTransform()
@@ -215,6 +215,14 @@ GutterComponent = React.createClass
lineNumberNodeForScreenRow: (screenRow) ->
@lineNumberNodesById[@lineNumberIdsByScreenRow[screenRow]]
onMouseDown: (event) ->
{editor} = @props
{target} = event
lineNumber = target.parentNode
unless target.classList.contains('icon-right') and lineNumber.classList.contains('foldable')
@props.onMouseDown(event)
onClick: (event) ->
{editor} = @props
{target} = event
+9 -9
Ver Arquivo
@@ -145,17 +145,17 @@ class LanguageMode
rowRange
rowRangeForCommentAtBufferRow: (bufferRow) ->
return unless @editor.displayBuffer.tokenizedBuffer.lineForScreenRow(bufferRow).isComment()
return unless @editor.displayBuffer.tokenizedBuffer.tokenizedLineForRow(bufferRow).isComment()
startRow = bufferRow
for currentRow in [bufferRow-1..0]
break if @buffer.isRowBlank(currentRow)
break unless @editor.displayBuffer.tokenizedBuffer.lineForScreenRow(currentRow).isComment()
break unless @editor.displayBuffer.tokenizedBuffer.tokenizedLineForRow(currentRow).isComment()
startRow = currentRow
endRow = bufferRow
for currentRow in [bufferRow+1..@buffer.getLastRow()]
break if @buffer.isRowBlank(currentRow)
break unless @editor.displayBuffer.tokenizedBuffer.lineForScreenRow(currentRow).isComment()
break unless @editor.displayBuffer.tokenizedBuffer.tokenizedLineForRow(currentRow).isComment()
endRow = currentRow
return [startRow, endRow] if startRow isnt endRow
@@ -168,7 +168,7 @@ class LanguageMode
continue if @editor.isBufferRowBlank(row)
indentation = @editor.indentationForBufferRow(row)
if indentation <= startIndentLevel
includeRowInFold = indentation == startIndentLevel and @foldEndRegexForScopes(scopes)?.searchSync(@editor.lineForBufferRow(row))
includeRowInFold = indentation == startIndentLevel and @foldEndRegexForScopes(scopes)?.searchSync(@editor.lineTextForBufferRow(row))
foldEndRow = row if includeRowInFold
break
@@ -201,13 +201,13 @@ class LanguageMode
# row is a comment.
isLineCommentedAtBufferRow: (bufferRow) ->
return false unless 0 <= bufferRow <= @editor.getLastBufferRow()
@editor.displayBuffer.tokenizedBuffer.lineForScreenRow(bufferRow).isComment()
@editor.displayBuffer.tokenizedBuffer.tokenizedLineForRow(bufferRow).isComment()
# Find a row range for a 'paragraph' around specified bufferRow.
# Right now, a paragraph is a block of text bounded by and empty line or a
# block of text that is not the same type (comments next to source code).
rowRangeForParagraphAtBufferRow: (bufferRow) ->
return unless /\w/.test(@editor.lineForBufferRow(bufferRow))
return unless /\w/.test(@editor.lineTextForBufferRow(bufferRow))
if @isLineCommentedAtBufferRow(bufferRow)
isOriginalRowComment = true
@@ -220,17 +220,17 @@ class LanguageMode
startRow = bufferRow
while startRow > firstRow
break if @isLineCommentedAtBufferRow(startRow - 1) != isOriginalRowComment
break unless /\w/.test(@editor.lineForBufferRow(startRow - 1))
break unless /\w/.test(@editor.lineTextForBufferRow(startRow - 1))
startRow--
endRow = bufferRow
lastRow = @editor.getLastBufferRow()
while endRow < lastRow
break if @isLineCommentedAtBufferRow(endRow + 1) != isOriginalRowComment
break unless /\w/.test(@editor.lineForBufferRow(endRow + 1))
break unless /\w/.test(@editor.lineTextForBufferRow(endRow + 1))
endRow++
new Range([startRow, 0], [endRow, @editor.lineLengthForBufferRow(endRow)])
new Range([startRow, 0], [endRow, @editor.lineTextForBufferRow(endRow).length])
# Given a buffer row, this returns a suggested indentation level.
#
+10 -11
Ver Arquivo
@@ -17,9 +17,9 @@ class MenuManager
atom.keymaps.on 'bundled-keymaps-loaded', => @loadPlatformItems()
atom.packages.on 'activated', => @sortPackagesMenu()
# Public: Adds the given item definition to the existing template.
# Public: Adds the given items to the application menu.
#
# ## Example
# ## Examples
# ```coffee
# atom.menu.add [
# {
@@ -29,23 +29,22 @@ class MenuManager
# ]
# ```
#
# items - An {Array} of menu item {Object}s containing the keys:
# :label - The {String} menu label.
# :submenu - An optional {Array} of sub menu items.
# :command - An optional {String} command to trigger when the item is
# clicked.
#
# Returns nothing.
# * `items` An {Array} of menu item {Object}s containing the keys:
# * `label` The {String} menu label.
# * `submenu` An optional {Array} of sub menu items.
# * `command` An optional {String} command to trigger when the item is
# clicked.
add: (items) ->
@merge(@template, item) for item in items
@update()
undefined
# Should the binding for the given selector be included in the menu
# commands.
#
# selector - A {String} selector to check.
# * `selector` A {String} selector to check.
#
# Returns true to include the selector, false otherwise.
# Returns a {Boolean}, true to include the selector, false otherwise.
includeSelector: (selector) ->
try
return true if document.body.webkitMatchesSelector(selector)
+53 -19
Ver Arquivo
@@ -21,7 +21,7 @@ ThemePackage = require './theme-package'
# `deactivate()` on the package's main module.
# * Unloading a package removes it completely from the package manager.
#
# Packages can also be enabled/disabled via the `core.disabledPackages` config
# Packages can be enabled/disabled via the `core.disabledPackages` config
# settings and also by calling `enablePackage()/disablePackage()`.
module.exports =
class PackageManager
@@ -41,15 +41,17 @@ class PackageManager
@packageActivators = []
@registerPackageActivator(this, ['atom', 'textmate'])
# Public: Get the path to the apm command
# Extended: Get the path to the apm command.
#
# Return a {String} file path to apm.
getApmPath: ->
commandName = 'apm'
commandName += '.cmd' if process.platform is 'win32'
@apmPath ?= path.resolve(__dirname, '..', 'apm', 'node_modules', 'atom-package-manager', 'bin', commandName)
# Public: Get the paths being used to look for packages.
# Extended: Get the paths being used to look for packages.
#
# Returns an Array of String directory paths.
# Returns an {Array} of {String} directory paths.
getPackageDirPaths: ->
_.clone(@packageDirPaths)
@@ -59,13 +61,17 @@ class PackageManager
setPackageState: (name, state) ->
@packageStates[name] = state
# Public: Enable the package with the given name
# Extended: Enable the package with the given name.
#
# Returns the {Package} that was enabled or null if it isn't loaded.
enablePackage: (name) ->
pack = @loadPackage(name)
pack?.enable()
pack
# Public: Disable the package with the given name
# Extended: Disable the package with the given name.
#
# Returns the {Package} that was disabled or null if it isn't loaded.
disablePackage: (name) ->
pack = @loadPackage(name)
pack?.disable()
@@ -110,15 +116,23 @@ class PackageManager
pack.deactivate()
delete @activePackages[pack.name]
# Public: Get an array of all the active packages
# Essential: Get an {Array} of all the active {Package}s.
getActivePackages: ->
_.values(@activePackages)
# Public: Get the active package with the given name
# Essential: Get the active {Package} with the given name.
#
# * `name` - The {String} package name.
#
# Returns a {Package} or undefined.
getActivePackage: (name) ->
@activePackages[name]
# Public: Is the package with the given name active?
# Public: Is the {Package} with the given name active?
#
# * `name` - The {String} package name.
#
# Returns a {Boolean}.
isPackageActive: (name) ->
@getActivePackage(name)?
@@ -179,25 +193,37 @@ class PackageManager
else
throw new Error("No loaded package for name '#{name}'")
# Public: Get the loaded package with the given name
# Essential: Get the loaded {Package} with the given name.
#
# * `name` - The {String} package name.
#
# Returns a {Package} or undefined.
getLoadedPackage: (name) ->
@loadedPackages[name]
# Public: Is the package with the given name loaded?
# Essential: Is the package with the given name loaded?
#
# * `name` - The {String} package name.
#
# Returns a {Boolean}.
isPackageLoaded: (name) ->
@getLoadedPackage(name)?
# Public: Get an array of all the loaded packages
# Essential: Get an {Array} of all the loaded {Package}s
getLoadedPackages: ->
_.values(@loadedPackages)
# Get packages for a certain package type
#
# types - an {Array} of {String}s like ['atom', 'textmate'].
# * `types` an {Array} of {String}s like ['atom', 'textmate'].
getLoadedPackagesForTypes: (types) ->
pack for pack in @getLoadedPackages() when pack.getType() in types
# Public: Resolve the given package name to a path on disk.
# Extended: Resolve the given package name to a path on disk.
#
# * `name` - The {String} package name.
#
# Return a {String} folder path or undefined if it could not be resolved.
resolvePackagePath: (name) ->
return name if fs.isDirectorySync(name)
@@ -207,7 +233,11 @@ class PackageManager
packagePath = path.join(@resourcePath, 'node_modules', name)
return packagePath if @hasAtomEngine(packagePath)
# Public: Is the package with the given name disabled?
# Essential: Is the package with the given name disabled?
#
# * `name` - The {String} package name.
#
# Returns a {Boolean}.
isPackageDisabled: (name) ->
_.include(atom.config.get('core.disabledPackages') ? [], name)
@@ -215,7 +245,11 @@ class PackageManager
metadata = Package.loadMetadata(packagePath, true)
metadata?.engines?.atom?
# Public: Is the package with the given name bundled with Atom?
# Extended: Is the package with the given name bundled with Atom?
#
# * `name` - The {String} package name.
#
# Returns a {Boolean}.
isBundledPackage: (name) ->
@getPackageDependencies().hasOwnProperty(name)
@@ -228,7 +262,7 @@ class PackageManager
@packageDependencies
# Public: Get an array of all the available package paths.
# Extended: Get an {Array} of {String}s of all the available package paths.
getAvailablePackagePaths: ->
packagePaths = []
@@ -243,11 +277,11 @@ class PackageManager
_.uniq(packagePaths)
# Public: Get an array of all the available package names.
# Extended: Get an {Array} of {String}s of all the available package names.
getAvailablePackageNames: ->
_.uniq _.map @getAvailablePackagePaths(), (packagePath) -> path.basename(packagePath)
# Public: Get an array of all the available package metadata.
# Extended: Get an {Array} of {String}s of all the available package metadata.
getAvailablePackageMetadata: ->
packages = []
for packagePath in @getAvailablePackagePaths()
+16 -7
Ver Arquivo
@@ -1,11 +1,17 @@
{CompositeDisposable} = require 'event-kit'
{View} = require './space-pen-extensions'
PaneView = null
module.exports =
class PaneAxisView extends View
initialize: (@model) ->
@onChildAdded(child) for child in @model.children
@subscribe @model.children, 'changed', @onChildrenChanged
@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()
@@ -14,19 +20,22 @@ class PaneAxisView extends View
viewClass = model.getViewClass()
model._view ?= new viewClass(model)
onChildrenChanged: ({index, removedValues, insertedValues}) =>
onChildReplaced: ({index, oldChild, newChild}) =>
focusedElement = document.activeElement if @hasFocus()
@onChildRemoved(child, index) for child in removedValues
@onChildAdded(child, index + i) for child, i in insertedValues
@onChildRemoved({child: oldChild, index})
@onChildAdded({child: newChild, index})
focusedElement?.focus() if document.activeElement is document.body
onChildAdded: (child, index) =>
onChildAdded: ({child, index}) =>
view = @viewForModel(child)
@insertAt(index, view)
onChildRemoved: (child) =>
onChildRemoved: ({child}) =>
view = @viewForModel(child)
view.detach()
PaneView ?= require './pane-view'
if view instanceof PaneView and view.model.isDestroyed()
@container?.trigger 'pane:removed', [view]
beforeRemove: ->
@subscriptions.dispose()
+76 -18
Ver Arquivo
@@ -1,4 +1,5 @@
{Model, Sequence} = require 'theorist'
{Model} = require 'theorist'
{Emitter, CompositeDisposable} = require 'event-kit'
{flatten} = require 'underscore-plus'
Serializable = require 'serializable'
@@ -10,18 +11,17 @@ class PaneAxis extends Model
atom.deserializers.add(this)
Serializable.includeInto(this)
parent: null
container: null
orientation: null
constructor: ({@container, @orientation, children}) ->
@children = Sequence.fromArray(children ? [])
@subscribe @children.onEach (child) =>
child.parent = this
child.container = @container
@subscribe child, 'destroyed', => @removeChild(child)
@subscribe @children.onRemoval (child) => @unsubscribe(child)
@when @children.$length.becomesLessThan(2), 'reparentLastChild'
@when @children.$length.becomesLessThan(1), 'destroy'
@emitter = new Emitter
@subscriptionsByChild = new WeakMap
@subscriptions = new CompositeDisposable
@children = []
if children?
@addChild(child) for child in children
deserializeParams: (params) ->
{container} = params
@@ -32,35 +32,93 @@ class PaneAxis extends Model
children: @children.map (child) -> child.serialize()
orientation: @orientation
getParent: -> @parent
setParent: (@parent) -> @parent
getContainer: -> @container
setContainer: (@container) -> @container
getViewClass: ->
if @orientation is 'vertical'
PaneColumnView ?= require './pane-column-view'
else
PaneRowView ?= require './pane-row-view'
getChildren: -> @children.slice()
getPanes: ->
flatten(@children.map (child) -> child.getPanes())
addChild: (child, index=@children.length) ->
@children.splice(index, 0, child)
getItems: ->
flatten(@children.map (child) -> child.getItems())
removeChild: (child) ->
onDidAddChild: (fn) ->
@emitter.on 'did-add-child', fn
onDidRemoveChild: (fn) ->
@emitter.on 'did-remove-child', fn
onDidReplaceChild: (fn) ->
@emitter.on 'did-replace-child', fn
onDidDestroy: (fn) ->
@emitter.on 'did-destroy', fn
addChild: (child, index=@children.length) ->
child.setParent(this)
child.setContainer(@container)
@subscribeToChild(child)
@children.splice(index, 0, child)
@emitter.emit 'did-add-child', {child, index}
removeChild: (child, replacing=false) ->
index = @children.indexOf(child)
throw new Error("Removing non-existent child") if index is -1
@unsubscribeFromChild(child)
@children.splice(index, 1)
@emitter.emit 'did-remove-child', {child, index}
@reparentLastChild() if not replacing and @children.length < 2
replaceChild: (oldChild, newChild) ->
@unsubscribeFromChild(oldChild)
@subscribeToChild(newChild)
newChild.setParent(this)
newChild.setContainer(@container)
index = @children.indexOf(oldChild)
throw new Error("Replacing non-existent child") if index is -1
@children.splice(index, 1, newChild)
@emitter.emit 'did-replace-child', {oldChild, newChild, index}
insertChildBefore: (currentChild, newChild) ->
index = @children.indexOf(currentChild)
@children.splice(index, 0, newChild)
@addChild(newChild, index)
insertChildAfter: (currentChild, newChild) ->
index = @children.indexOf(currentChild)
@children.splice(index + 1, 0, newChild)
@addChild(newChild, index + 1)
reparentLastChild: ->
@parent.replaceChild(this, @children[0])
@destroy()
subscribeToChild: (child) ->
subscription = child.onDidDestroy => @removeChild(child)
@subscriptionsByChild.set(child, subscription)
@subscriptions.add(subscription)
unsubscribeFromChild: (child) ->
subscription = @subscriptionsByChild.get(child)
@subscriptions.remove(subscription)
subscription.dispose()
destroyed: ->
@subscriptions.dispose()
@emitter.emit 'did-destroy'
@emitter.dispose()
+9 -3
Ver Arquivo
@@ -1,5 +1,6 @@
{deprecate} = require 'grim'
Delegator = require 'delegato'
{CompositeDisposable} = require 'event-kit'
{$, View} = require './space-pen-extensions'
PaneView = require './pane-view'
PaneContainer = require './pane-container'
@@ -15,13 +16,15 @@ class PaneContainerView extends View
@div class: 'panes'
initialize: (params) ->
@subscriptions = new CompositeDisposable
if params instanceof PaneContainer
@model = params
else
@model = new PaneContainer({root: params?.root?.model})
@subscribe @model.$root, @onRootChanged
@subscribe @model.$activePaneItem.changes, @onActivePaneItemChanged
@subscriptions.add @model.observeRoot(@onRootChanged)
@subscriptions.add @model.onDidChangeActivePaneItem(@onActivePaneItemChanged)
viewForModel: (model) ->
if model?
@@ -88,7 +91,7 @@ class PaneContainerView extends View
@viewForModel(@model.activePane)
getActivePaneItem: ->
@model.activePaneItem
@model.getActivePaneItem()
getActiveView: ->
@getActivePaneView()?.activeView
@@ -153,3 +156,6 @@ class PaneContainerView extends View
getPanes: ->
deprecate("Use PaneContainerView::getPaneViews() instead")
@getPaneViews()
beforeRemove: ->
@subscriptions.dispose()
+99 -22
Ver Arquivo
@@ -1,5 +1,6 @@
{find} = require 'underscore-plus'
{find, flatten} = require 'underscore-plus'
{Model} = require 'theorist'
{Emitter, CompositeDisposable} = require 'event-kit'
Serializable = require 'serializable'
Pane = require './pane'
@@ -11,10 +12,9 @@ class PaneContainer extends Model
@version: 1
@properties
root: -> new Pane
activePane: null
previousRoot: null
root: null
@behavior 'activePaneItem', ->
@$activePane
@@ -23,9 +23,16 @@ class PaneContainer extends Model
constructor: (params) ->
super
@subscribe @$root, @onRootChanged
@emitter = new Emitter
@subscriptions = new CompositeDisposable
@setRoot(params?.root ? new Pane)
@destroyEmptyPanes() if params?.destroyEmptyPanes
@monitorActivePaneItem()
@monitorPaneItems()
deserializeParams: (params) ->
params.root = atom.deserializers.deserialize(params.root, container: this)
params.destroyEmptyPanes = atom.config.get('core.destroyEmptyPanes')
@@ -36,16 +43,75 @@ class PaneContainer extends Model
root: @root?.serialize()
activePaneId: @activePane.id
onDidChangeRoot: (fn) ->
@emitter.on 'did-change-root', fn
observeRoot: (fn) ->
fn(@getRoot())
@onDidChangeRoot(fn)
onDidAddPane: (fn) ->
@emitter.on 'did-add-pane', fn
observePanes: (fn) ->
fn(pane) for pane in @getPanes()
@onDidAddPane ({pane}) -> fn(pane)
onDidChangeActivePane: (fn) ->
@emitter.on 'did-change-active-pane', fn
observeActivePane: (fn) ->
fn(@getActivePane())
@onDidChangeActivePane(fn)
onDidAddPaneItem: (fn) ->
@emitter.on 'did-add-pane-item', fn
observePaneItems: (fn) ->
fn(item) for item in @getPaneItems()
@onDidAddPaneItem ({item}) -> fn(item)
onDidChangeActivePaneItem: (fn) ->
@emitter.on 'did-change-active-pane-item', fn
observeActivePaneItem: (fn) ->
fn(@getActivePaneItem())
@onDidChangeActivePaneItem(fn)
onDidDestroyPaneItem: (fn) ->
@emitter.on 'did-destroy-pane-item', fn
getRoot: -> @root
setRoot: (@root) ->
@root.setParent(this)
@root.setContainer(this)
@emitter.emit 'did-change-root', @root
if not @getActivePane()? and @root instanceof Pane
@setActivePane(@root)
replaceChild: (oldChild, newChild) ->
throw new Error("Replacing non-existent child") if oldChild isnt @root
@root = newChild
@setRoot(newChild)
getPanes: ->
@root?.getPanes() ? []
@getRoot().getPanes()
getPaneItems: ->
@getRoot().getItems()
getActivePane: ->
@activePane
setActivePane: (activePane) ->
if activePane isnt @activePane
@activePane = activePane
@emitter.emit 'did-change-active-pane', @activePane
@activePane
getActivePaneItem: ->
@getActivePane().getActiveItem()
paneForUri: (uri) ->
find @getPanes(), (pane) -> pane.itemForUri(uri)?
@@ -73,26 +139,37 @@ class PaneContainer extends Model
else
false
onRootChanged: (root) =>
@unsubscribe(@previousRoot) if @previousRoot?
@previousRoot = root
unless root?
@activePane = null
return
root.parent = this
root.container = this
@activePane ?= root if root instanceof Pane
destroyEmptyPanes: ->
pane.destroy() for pane in @getPanes() when pane.items.length is 0
itemDestroyed: (item) ->
@emit 'item-destroyed', item
paneItemDestroyed: (item) ->
@emitter.emit 'did-destroy-pane-item', item
didAddPane: (pane) ->
@emitter.emit 'did-add-pane', pane
# Called by Model superclass when destroyed
destroyed: ->
pane.destroy() for pane in @getPanes()
@subscriptions.dispose()
@emitter.dispose()
monitorActivePaneItem: ->
childSubscription = null
@subscriptions.add @observeActivePane (activePane) =>
if childSubscription?
@subscriptions.remove(childSubscription)
childSubscription.dispose()
childSubscription = activePane.observeActiveItem (activeItem) =>
@emitter.emit 'did-change-active-pane-item', activeItem
@subscriptions.add(childSubscription)
monitorPaneItems: ->
@subscriptions.add @observePanes (pane) =>
for item, index in pane.getItems()
@emitter.emit 'did-add-pane-item', {item, pane, index}
pane.onDidAddItem ({item, index}) =>
@emitter.emit 'did-add-pane-item', {item, pane, index}
+22 -15
Ver Arquivo
@@ -1,11 +1,12 @@
{$, View} = require './space-pen-extensions'
Delegator = require 'delegato'
{deprecate} = require 'grim'
{CompositeDisposable} = require 'event-kit'
PropertyAccessors = require 'property-accessors'
Pane = require './pane'
# Public: A container which can contains multiple items to be switched between.
# Extended: A container which can contains multiple items to be switched between.
#
# Items can be almost anything however most commonly they're {EditorView}s.
#
@@ -33,6 +34,8 @@ class PaneView extends View
previousActiveItem: null
initialize: (args...) ->
@subscriptions = new CompositeDisposable
if args[0] instanceof Pane
@model = args[0]
else
@@ -44,13 +47,13 @@ class PaneView extends View
@handleEvents()
handleEvents: ->
@subscribe @model.$activeItem, @onActiveItemChanged
@subscribe @model, 'item-added', @onItemAdded
@subscribe @model, 'item-removed', @onItemRemoved
@subscribe @model, 'item-moved', @onItemMoved
@subscribe @model, 'before-item-destroyed', @onBeforeItemDestroyed
@subscribe @model, 'activated', @onActivated
@subscribe @model.$active, @onActiveStatusChanged
@subscriptions.add @model.observeActiveItem(@onActiveItemChanged)
@subscriptions.add @model.onDidAddItem(@onItemAdded)
@subscriptions.add @model.onDidRemoveItem(@onItemRemoved)
@subscriptions.add @model.onDidMoveItem(@onItemMoved)
@subscriptions.add @model.onWillDestroyItem(@onBeforeItemDestroyed)
@subscriptions.add @model.onDidActivate(@onActivated)
@subscriptions.add @model.observeActive(@onActiveStatusChanged)
@subscribe this, 'focusin', => @model.focus()
@subscribe this, 'focusout', => @model.blur()
@@ -72,15 +75,18 @@ class PaneView extends View
@command 'pane:show-item-8', => @activateItemAtIndex(7)
@command 'pane:show-item-9', => @activateItemAtIndex(8)
@command 'pane:split-left', => @splitLeft(@copyActiveItem())
@command 'pane:split-right', => @splitRight(@copyActiveItem())
@command 'pane:split-up', => @splitUp(@copyActiveItem())
@command 'pane:split-down', => @splitDown(@copyActiveItem())
@command 'pane:split-left', => @model.splitLeft(copyActiveItem: true)
@command 'pane:split-right', => @model.splitRight(copyActiveItem: true)
@command 'pane:split-up', => @model.splitUp(copyActiveItem: true)
@command 'pane:split-down', => @model.splitDown(copyActiveItem: true)
@command 'pane:close', =>
@model.destroyItems()
@model.destroy()
@command 'pane:close-other-items', => @destroyInactiveItems()
# Essential: Returns the {Pane} model underlying this pane view
getModel: -> @model
# Deprecated: Use ::destroyItem
removeItem: (item) ->
deprecate("Use PaneView::destroyItem instead")
@@ -160,10 +166,10 @@ class PaneView extends View
@trigger 'pane:active-item-changed', [item]
onItemAdded: (item, index) =>
onItemAdded: ({item, index}) =>
@trigger 'pane:item-added', [item, index]
onItemRemoved: (item, index, destroyed) =>
onItemRemoved: ({item, index, destroyed}) =>
if item instanceof $
viewToRemove = item
else if viewToRemove = @viewsByItem.get(item)
@@ -177,7 +183,7 @@ class PaneView extends View
@trigger 'pane:item-removed', [item, index]
onItemMoved: (item, newIndex) =>
onItemMoved: ({item, newIndex}) =>
@trigger 'pane:item-moved', [item, newIndex]
onBeforeItemDestroyed: (item) =>
@@ -219,6 +225,7 @@ class PaneView extends View
@closest('.panes').view()
beforeRemove: ->
@subscriptions.dispose()
@model.destroy() unless @model.isDestroyed()
remove: (selector, keepData) ->
+334 -94
Ver Arquivo
@@ -1,13 +1,16 @@
{find, compact, extend, last} = require 'underscore-plus'
{Model, Sequence} = require 'theorist'
{Model} = require 'theorist'
{Emitter} = require 'event-kit'
Serializable = require 'serializable'
Grim = require 'grim'
PaneAxis = require './pane-axis'
Editor = require './editor'
PaneView = null
# Public: A container for multiple items, one of which is *active* at a given
# time. With the default packages, a tab is displayed for each item and the
# active item's view is displayed.
# Extended: A container for presenting content in the center of the workspace.
# Panes can contain multiple items, one of which is *active* at a given time.
# The view corresponding to the active item is displayed in the interface. In
# the default configuration, tabs are also displayed for each item.
module.exports =
class Pane extends Model
atom.deserializers.add(this)
@@ -30,15 +33,11 @@ class Pane extends Model
constructor: (params) ->
super
@items = Sequence.fromArray(compact(params?.items ? []))
@activeItem ?= @items[0]
@emitter = new Emitter
@items = []
@subscribe @items.onEach (item) =>
if typeof item.on is 'function'
@subscribe item, 'destroyed', => @removeItem(item, true)
@subscribe @items.onRemoval (item, index) =>
@unsubscribe item if typeof item.on is 'function'
@addItems(compact(params?.items ? []))
@setActiveItem(@items[0]) unless @getActiveItem()?
# Called by the Serializable mixin during serialization.
serializeParams: ->
@@ -57,7 +56,174 @@ class Pane extends Model
# Called by the view layer to construct a view for this model.
getViewClass: -> PaneView ?= require './pane-view'
isActive: -> @active
getParent: -> @parent
setParent: (@parent) -> @parent
getContainer: -> @container
setContainer: (container) ->
container.didAddPane({pane: this}) unless container is @container
@container = container
###
Section: Event Subscription
###
# Public: Invoke the given callback when the pane is activated.
#
# The given callback will be invoked whenever {::activate} is called on the
# pane, even if it is already active at the time.
#
# * `callback` {Function} to be called when the pane is activated.
#
# Returns a {Disposable} on which `.dispose()` can be called to unsubscribe.
onDidActivate: (callback) ->
@emitter.on 'did-activate', callback
# Public: Invoke the given callback when the pane is destroyed.
#
# * `callback` {Function} to be called when the pane is destroyed.
#
# Returns a {Disposable} on which `.dispose()` can be called to unsubscribe.
onDidDestroy: (callback) ->
@emitter.on 'did-destroy', callback
# Public: Invoke the given callback when the value of the {::isActive}
# property changes.
#
# * `callback` {Function} to be called when the value of the {::isActive}
# property changes.
# * `active` {Boolean} indicating whether the pane is active.
#
# Returns a {Disposable} on which `.dispose()` can be called to unsubscribe.
onDidChangeActive: (callback) ->
@container.onDidChangeActivePane (activePane) =>
callback(this is activePane)
# Public: Invoke the given callback with the current and future values of the
# {::isActive} property.
#
# * `callback` {Function} to be called with the current and future values of
# the {::isActive} property.
# * `active` {Boolean} indicating whether the pane is active.
#
# Returns a {Disposable} on which `.dispose()` can be called to unsubscribe.
observeActive: (callback) ->
callback(@isActive())
@onDidChangeActive(callback)
# Public: Invoke the given callback when an item is added to the pane.
#
# * `callback` {Function} to be called with when items are added.
# * `event` {Object} with the following keys:
# * `item` The added pane item.
# * `index` {Number} indicating where the item is located.
#
# Returns a {Disposable} on which `.dispose()` can be called to unsubscribe.
onDidAddItem: (callback) ->
@emitter.on 'did-add-item', callback
# Public: Invoke the given callback when an item is removed from the pane.
#
# * `callback` {Function} to be called with when items are removed.
# * `event` {Object} with the following keys:
# * `item` The removed pane item.
# * `index` {Number} indicating where the item was located.
#
# Returns a {Disposable} on which `.dispose()` can be called to unsubscribe.
onDidRemoveItem: (callback) ->
@emitter.on 'did-remove-item', callback
# Public: Invoke the given callback when an item is moved within the pane.
#
# * `callback` {Function} to be called with when items are moved.
# * `event` {Object} with the following keys:
# * `item` The removed pane item.
# * `oldIndex` {Number} indicating where the item was located.
# * `newIndex` {Number} indicating where the item is now located.
#
# Returns a {Disposable} on which `.dispose()` can be called to unsubscribe.
onDidMoveItem: (callback) ->
@emitter.on 'did-move-item', callback
# Public: Invoke the given callback with all current and future items.
#
# * `callback` {Function} to be called with current and future items.
# * `item` An item that is present in {::getItems} at the time of
# subscription or that is added at some later time.
#
# Returns a {Disposable} on which `.dispose()` can be called to unsubscribe.
observeItems: (callback) ->
callback(item) for item in @getItems()
@onDidAddItem ({item}) -> callback(item)
# Public: Invoke the given callback when the value of {::getActiveItem}
# changes.
#
# * `callback` {Function} to be called with when the active item changes.
# * `activeItem` The current active item.
#
# Returns a {Disposable} on which `.dispose()` can be called to unsubscribe.
onDidChangeActiveItem: (callback) ->
@emitter.on 'did-change-active-item', callback
# Public: Invoke the given callback with the current and future values of
# {::getActiveItem}.
#
# * `callback` {Function} to be called with the current and future active
# items.
# * `activeItem` The current active item.
#
# Returns a {Disposable} on which `.dispose()` can be called to unsubscribe.
observeActiveItem: (callback) ->
callback(@getActiveItem())
@onDidChangeActiveItem(callback)
# Public: Invoke the given callback before items are destroyed.
#
# * `callback` {Function} to be called before items are destroyed.
# * `event` {Object} with the following keys:
# * `item` The item that will be destroyed.
# * `index` The location of the item.
#
# Returns a {Disposable} on which `.dispose()` can be called to
# unsubscribe.
onWillDestroyItem: (callback) ->
@emitter.on 'will-destroy-item', callback
on: (eventName) ->
switch eventName
when 'activated'
Grim.deprecate("Use Pane::onDidActivate instead")
when 'destroyed'
Grim.deprecate("Use Pane::onDidDestroy instead")
when 'item-added'
Grim.deprecate("Use Pane::onDidAddItem instead")
when 'item-removed'
Grim.deprecate("Use Pane::onDidRemoveItem instead")
when 'item-moved'
Grim.deprecate("Use Pane::onDidMoveItem instead")
when 'before-item-destroyed'
Grim.deprecate("Use Pane::onWillDestroyItem instead")
else
Grim.deprecate("Subscribing via ::on is deprecated. Use documented event subscription methods instead.")
super
behavior: (behaviorName) ->
switch behaviorName
when 'active'
Grim.deprecate("The $active behavior property is deprecated. Use ::observeActive or ::onDidChangeActive instead.")
when 'container'
Grim.deprecate("The $container behavior property is deprecated.")
when 'activeItem'
Grim.deprecate("The $activeItem behavior property is deprecated. Use ::observeActiveItem or ::onDidChangeActiveItem instead.")
when 'focused'
Grim.deprecate("The $focused behavior property is deprecated.")
else
Grim.deprecate("Pane::behavior is deprecated. Use event subscription methods instead.")
super
# Called by the view layer to indicate that the pane has gained focus.
focus: ->
@@ -69,14 +235,12 @@ class Pane extends Model
@focused = false
true # if this is called from an event handler, don't cancel it
# Public: Makes this pane the *active* pane, causing it to gain focus
# immediately.
activate: ->
@container?.activePane = this
@emit 'activated'
getPanes: -> [this]
###
Section: Items
###
# Public: Get the items in this pane.
#
# Returns an {Array} of items.
@@ -86,15 +250,23 @@ class Pane extends Model
# Public: Get the active pane item in this pane.
#
# Returns a pane item.
getActiveItem: ->
getActiveItem: -> @activeItem
setActiveItem: (activeItem) ->
unless activeItem is @activeItem
@activeItem = activeItem
@emitter.emit 'did-change-active-item', @activeItem
@activeItem
# Public: Returns an {Editor} if the pane item is an {Editor}, or null
# otherwise.
# Return an {Editor} if the pane item is an {Editor}, or null otherwise.
getActiveEditor: ->
@activeItem if @activeItem instanceof Editor
# Public: Returns the item at the specified index.
# Public: Return the item at the given index.
#
# * `index` {Number}
#
# Returns an item or `null` if no item exists at the given index.
itemAtIndex: (index) ->
@items[index]
@@ -114,86 +286,115 @@ class Pane extends Model
else
@activateItemAtIndex(@items.length - 1)
# Returns the index of the current active item.
# Public: Get the index of the active item.
#
# Returns a {Number}.
getActiveItemIndex: ->
@items.indexOf(@activeItem)
# Makes the item at the given index active.
# Public: Activate the item at the given index.
#
# * `index` {Number}
activateItemAtIndex: (index) ->
@activateItem(@itemAtIndex(index))
# Makes the given item active, adding the item if necessary.
# Public: Make the given item *active*, causing it to be displayed by
# the pane's view.
activateItem: (item) ->
if item?
@addItem(item)
@activeItem = item
@setActiveItem(item)
# Public: Adds the item to the pane.
# Public: Add the given item to the pane.
#
# item - The item to add. It can be a model with an associated view or a view.
# index - An optional index at which to add the item. If omitted, the item is
# added after the current active item.
# * `item` The item to add. It can be a model with an associated view or a
# view.
# * `index` (optional) {Number} indicating the index at which to add the item.
# If omitted, the item is added after the current active item.
#
# Returns the added item
# Returns the added item.
addItem: (item, index=@getActiveItemIndex() + 1) ->
return if item in @items
if typeof item.on is 'function'
@subscribe item, 'destroyed', => @removeItem(item, true)
@items.splice(index, 0, item)
@emit 'item-added', item, index
@activeItem ?= item
@emitter.emit 'did-add-item', {item, index}
@setActiveItem(item) unless @getActiveItem()?
item
# Public: Adds the given items to the pane.
# Public: Add the given items to the pane.
#
# items - An {Array} of items to add. Items can be models with associated
# views or views. Any items that are already present in items will
# not be added.
# index - An optional index at which to add the item. If omitted, the item is
# added after the current active item.
# * `items` An {Array} of items to add. Items can be views or models with
# associated views. Any objects that are already present in the pane's
# current items will not be added again.
# * `index` (optional) {Number} index at which to add the items. If omitted,
# the item is # added after the current active item.
#
# Returns an {Array} of the added items
# Returns an {Array} of added items.
addItems: (items, index=@getActiveItemIndex() + 1) ->
items = items.filter (item) => not (item in @items)
@addItem(item, index + i) for item, i in items
items
removeItem: (item, destroying) ->
removeItem: (item, destroyed=false) ->
index = @items.indexOf(item)
return if index is -1
if typeof item.on is 'function'
@unsubscribe item
if item is @activeItem
if @items.length is 1
@activeItem = undefined
@setActiveItem(undefined)
else if index is 0
@activateNextItem()
else
@activatePreviousItem()
@items.splice(index, 1)
@emit 'item-removed', item, index, destroying
@container?.itemDestroyed(item) if destroying
@emit 'item-removed', item, index, destroyed
@emitter.emit 'did-remove-item', {item, index, destroyed}
@container?.paneItemDestroyed(item) if destroyed
@destroy() if @items.length is 0 and atom.config.get('core.destroyEmptyPanes')
# Public: Moves the given item to the specified index.
# Public: Move the given item to the given index.
#
# * `item` The item to move.
# * `index` {Number} indicating the index to which to move the item.
moveItem: (item, newIndex) ->
oldIndex = @items.indexOf(item)
@items.splice(oldIndex, 1)
@items.splice(newIndex, 0, item)
@emit 'item-moved', item, newIndex
@emitter.emit 'did-move-item', {item, oldIndex, newIndex}
# Public: Moves the given item to the given index at another pane.
# Public: Move the given item to the given index on another pane.
#
# * `item` The item to move.
# * `pane` {Pane} to which to move the item.
# * `index` {Number} indicating the index to which to move the item in the
# given pane.
moveItemToPane: (item, pane, index) ->
pane.addItem(item, index)
@removeItem(item)
# Public: Destroys the currently active item and make the next item active.
# Public: Destroy the active item and activate the next item.
destroyActiveItem: ->
@destroyItem(@activeItem)
false
# Public: Destroys the given item. If it is the active item, activate the next
# one. If this is the last item, also destroys the pane.
# Public: Destroy the given item.
#
# If the item is active, the next item will be activated. If the item is the
# last item, the pane will be destroyed if the `core.destroyEmptyPanes` config
# setting is `true`.
destroyItem: (item) ->
if item?
index = @items.indexOf(item)
if index isnt -1
@emit 'before-item-destroyed', item
@emitter.emit 'will-destroy-item', {item, index}
if @promptToSaveItem(item)
@removeItem(item, true)
item.destroy?()
@@ -201,27 +402,14 @@ class Pane extends Model
else
false
# Public: Destroys all items and destroys the pane.
# Public: Destroy all items.
destroyItems: ->
@destroyItem(item) for item in @getItems()
# Public: Destroys all items but the active one.
# Public: Destroy all items except for the active item.
destroyInactiveItems: ->
@destroyItem(item) for item in @getItems() when item isnt @activeItem
destroy: ->
if @container?.isAlive() and @container.getPanes().length is 1
@destroyItems()
else
super
# Called by model superclass.
destroyed: ->
@container.activateNextPane() if @isActive()
item.destroy?() for item in @items.slice()
# Public: Prompts the user to save the given item if it can be saved and is
# currently unsaved.
promptToSaveItem: (item) ->
return true unless item.shouldPromptToSave?()
@@ -236,19 +424,23 @@ class Pane extends Model
when 1 then false
when 2 then true
# Public: Saves the active item.
saveActiveItem: ->
@saveItem(@activeItem)
# Public: Save the active item.
saveActiveItem: (nextAction) ->
@saveItem(@getActiveItem(), nextAction)
# Public: Saves the active item at a prompted-for location.
saveActiveItemAs: ->
@saveItemAs(@activeItem)
# Public: Saves the specified item.
# Public: Prompt the user for a location and save the active item with the
# path they select.
#
# item - The item to save.
# nextAction - An optional function which will be called after the item is
# saved.
# * `nextAction` (optional) {Function} which will be called after the item is
# successfully saved.
saveActiveItemAs: (nextAction) ->
@saveItemAs(@getActiveItem(), nextAction)
# Public: Save the given item.
#
# * `item` The item to save.
# * `nextAction` (optional) {Function} which will be called after the item is
# successfully saved.
saveItem: (item, nextAction) ->
if item?.getUri?()
item.save?()
@@ -256,11 +448,12 @@ class Pane extends Model
else
@saveItemAs(item, nextAction)
# Public: Saves the given item at a prompted-for location.
# Public: Prompt the user for a location and save the active item with the
# path they select.
#
# item - The item to save.
# nextAction - An optional function which will be called after the item is
# saved.
# * `item` The item to save.
# * `nextAction` (optional) {Function} which will be called after the item is
# successfully saved.
saveItemAs: (item, nextAction) ->
return unless item?.saveAs?
@@ -270,17 +463,20 @@ class Pane extends Model
item.saveAs(newItemPath)
nextAction?()
# Public: Saves all items.
# Public: Save all items.
saveItems: ->
@saveItem(item) for item in @getItems()
# Public: Returns the first item that matches the given URI or undefined if
# Public: Return the first item that matches the given URI or undefined if
# none exists.
#
# * `uri` {String} containing a URI.
itemForUri: (uri) ->
find @items, (item) -> item.getUri?() is uri
# Public: Activates the first item that matches the given URI. Returns a
# boolean indicating whether a matching item was found.
# Public: Activate the first item that matches the given URI.
#
# Returns a {Boolean} indicating whether an item matching the URI was found.
activateItemForUri: (uri) ->
if item = @itemForUri(uri)
@activateItem(item)
@@ -292,19 +488,57 @@ class Pane extends Model
if @activeItem?
@activeItem.copy?() ? atom.deserializers.deserialize(@activeItem.serialize())
# Public: Creates a new pane to the left of the receiver.
###
Section: Lifecycle
###
# Public: Determine whether the pane is active.
#
# params - An object with keys:
# :items - An optional array of items with which to construct the new pane.
# Returns a {Boolean}.
isActive: ->
@container?.getActivePane() is this
# Public: Makes this pane the *active* pane, causing it to gain focus.
activate: ->
@container?.setActivePane(this)
@emit 'activated'
@emitter.emit 'did-activate'
# Public: Close the pane and destroy all its items.
#
# If this is the last pane, all the items will be destroyed but the pane
# itself will not be destroyed.
destroy: ->
if @container?.isAlive() and @container.getPanes().length is 1
@destroyItems()
else
super
# Called by model superclass.
destroyed: ->
@container.activateNextPane() if @isActive()
@emitter.emit 'did-destroy'
item.destroy?() for item in @items.slice()
###
Section: Splitting
###
# Public: Create a new pane to the left of this pane.
#
# * `params` (optional) {Object} with the following keys:
# * `items` (optional) {Array} of items to add to the new pane.
# * `copyActiveItem` (optional) {Boolean} true will copy the active item into the new split pane
#
# Returns the new {Pane}.
splitLeft: (params) ->
@split('horizontal', 'before', params)
# Public: Creates a new pane to the right of the receiver.
# Public: Create a new pane to the right of this pane.
#
# params - An object with keys:
# :items - An optional array of items with which to construct the new pane.
# * `params` (optional) {Object} with the following keys:
# * `items` (optional) {Array} of items to add to the new pane.
# * `copyActiveItem` (optional) {Boolean} true will copy the active item into the new split pane
#
# Returns the new {Pane}.
splitRight: (params) ->
@@ -312,8 +546,9 @@ class Pane extends Model
# Public: Creates a new pane above the receiver.
#
# params - An object with keys:
# :items - An optional array of items with which to construct the new pane.
# * `params` (optional) {Object} with the following keys:
# * `items` (optional) {Array} of items to add to the new pane.
# * `copyActiveItem` (optional) {Boolean} true will copy the active item into the new split pane
#
# Returns the new {Pane}.
splitUp: (params) ->
@@ -321,14 +556,19 @@ class Pane extends Model
# Public: Creates a new pane below the receiver.
#
# params - An object with keys:
# :items - An optional array of items with which to construct the new pane.
# * `params` (optional) {Object} with the following keys:
# * `items` (optional) {Array} of items to add to the new pane.
# * `copyActiveItem` (optional) {Boolean} true will copy the active item into the new split pane
#
# Returns the new {Pane}.
splitDown: (params) ->
@split('vertical', 'after', params)
split: (orientation, side, params) ->
if params?.copyActiveItem
params.items ?= []
params.items.push(@copyActiveItem())
if @parent.orientation isnt orientation
@parent.replaceChild(this, new PaneAxis({@container, orientation, children: [this]}))
+42 -20
Ver Arquivo
@@ -15,15 +15,30 @@ Editor = require './editor'
Task = require './task'
Git = require './git'
# Public: Represents a project that's opened in Atom.
# Extended: Represents a project that's opened in Atom.
#
# An instance of this class is always available as the `atom.project` global.
#
# ## Events
#
# ### path-changed
#
# Extended: Emit when the project's path has changed. Use {::getPath} to get the new path
#
# ### buffer-created
#
# Extended: Emit when a buffer is created. For example, when {::open} is called, this is fired.
#
# * `buffer` {TextBuffer} the new buffer that was created.
#
module.exports =
class Project extends Model
atom.deserializers.add(this)
Serializable.includeInto(this)
# Public: Find the local path for the given repository URL.
#
# * `repoUrl` {String} url to a git repository
@pathForRepositoryUrl: (repoUrl) ->
[repoName] = url.parse(repoUrl).path.split('/')[-1..]
repoName = repoName.replace(/\.git$/, '')
@@ -34,7 +49,7 @@ class Project extends Model
for buffer in @buffers
do (buffer) =>
buffer.once 'destroyed', => @removeBuffer(buffer)
buffer.onDidDestroy => @removeBuffer(buffer)
@setPath(path)
@@ -61,12 +76,15 @@ class Project extends Model
# Public: Returns the {Git} repository if available.
getRepo: -> @repo
# Public: Returns the project's fullpath.
# Public: Returns the project's {String} fullpath.
getPath: ->
@rootDirectory?.path
# Public: Sets the project's fullpath.
#
# * `projectPath` {String} path
setPath: (projectPath) ->
projectPath = path.normalize(projectPath) if projectPath
@path = projectPath
@rootDirectory?.off()
@@ -90,7 +108,7 @@ class Project extends Model
# the path is already absolute or if it is prefixed with a scheme, it is
# returned unchanged.
#
# uri - The {String} name of the path to convert.
# * `uri` The {String} name of the path to convert.
#
# Returns a {String} or undefined if the uri is not missing or empty.
resolve: (uri) ->
@@ -107,19 +125,23 @@ class Project extends Model
undefined
# Public: Make the given path relative to the project directory.
#
# * `fullPath` {String} full path
relativize: (fullPath) ->
return fullPath if fullPath?.match(/[A-Za-z0-9+-.]+:\/\//) # leave path alone if it has a scheme
@rootDirectory?.relativize(fullPath) ? fullPath
# Public: Returns whether the given path is inside this project.
#
# * `pathToCheck` {String} path
contains: (pathToCheck) ->
@rootDirectory?.contains(pathToCheck) ? false
# Given a path to a file, this constructs and associates a new
# {Editor}, showing the file.
#
# filePath - The {String} path of the file to associate with.
# options - Options that you can pass to the {Editor} constructor.
# * `filePath` The {String} path of the file to associate with.
# * `options` Options that you can pass to the {Editor} constructor.
#
# Returns a promise that resolves to an {Editor}.
open: (filePath, options={}) ->
@@ -158,7 +180,7 @@ class Project extends Model
# If the `filePath` already has a `buffer`, that value is used instead. Otherwise,
# `text` is used as the contents of the new buffer.
#
# filePath - A {String} representing a path. If `null`, an "Untitled" buffer is created.
# * `filePath` A {String} representing a path. If `null`, an "Untitled" buffer is created.
#
# Returns a promise that resolves to the {TextBuffer}.
bufferForPath: (filePath) ->
@@ -178,8 +200,8 @@ class Project extends Model
# Given a file path, this sets its {TextBuffer}.
#
# absoluteFilePath - A {String} representing a path.
# text - The {String} text to use as a buffer.
# * `absoluteFilePath` A {String} representing a path.
# * `text` The {String} text to use as a buffer.
#
# Returns a promise that resolves to the {TextBuffer}.
buildBuffer: (absoluteFilePath) ->
@@ -194,11 +216,11 @@ class Project extends Model
addBuffer: (buffer, options={}) ->
@addBufferAtIndex(buffer, @buffers.length, options)
buffer.once 'destroyed', => @removeBuffer(buffer)
buffer.onDidDestroy => @removeBuffer(buffer)
addBufferAtIndex: (buffer, index, options={}) ->
@buffers.splice(index, 0, buffer)
buffer.once 'destroyed', => @removeBuffer(buffer)
buffer.onDidDestroy => @removeBuffer(buffer)
@emit 'buffer-created', buffer
buffer
@@ -215,10 +237,10 @@ class Project extends Model
# Public: Performs a search across all the files in the project.
#
# regex - A {RegExp} to search with.
# options - An optional options {Object} (default: {}):
# :paths - An {Array} of glob patterns to search within
# iterator - A {Function} callback on each file found
# * `regex` {RegExp} to search with.
# * `options` (optional) {Object} (default: {})
# * `paths` An {Array} of glob patterns to search within
# * `iterator` {Function} callback on each file found
scan: (regex, options={}, iterator) ->
if _.isFunction(options)
iterator = options
@@ -261,11 +283,11 @@ class Project extends Model
# Public: Performs a replace across all the specified files in the project.
#
# regex - A {RegExp} to search with.
# replacementText - Text to replace all matches of regex with
# filePaths - List of file path strings to run the replace on.
# iterator - A {Function} callback on each file with replacements:
# `({filePath, replacements}) ->`.
# * `regex` A {RegExp} to search with.
# * `replacementText` Text to replace all matches of regex with
# * `filePaths` List of file path strings to run the replace on.
# * `iterator` A {Function} callback on each file with replacements:
# * `options` {Object} with keys `filePath` and `replacements`
replace: (regex, replacementText, filePaths, iterator) ->
deferred = Q.defer()
+20 -11
Ver Arquivo
@@ -2,22 +2,31 @@
# Public: Represents a view that scrolls.
#
# Subclasses must call `super` if overriding the `initialize` method or else
# the following events won't be handled by the ScrollView.
# Handles several core events to update scroll position:
#
# ## Events
# * `core:move-up`
# * `core:move-down`
# * `core:page-up`
# * `core:page-down`
# * `core:move-to-top`
# * `core:move-to-bottom`
# * `core:move-up` Scrolls the view up
# * `core:move-down` Scrolls the view down
# * `core:page-up` Scrolls the view up by the height of the page
# * `core:page-down` Scrolls the view down by the height of the page
# * `core:move-to-top` Scrolls the editor to the top
# * `core:move-to-bottom` Scroll the editor to the bottom
#
# ## Requiring in packages
# Subclasses must call `super` if overriding the `initialize` method.
#
# ## Examples
#
# ```coffee
# {ScrollView} = require 'atom'
# {ScrollView} = require 'atom'
#
# class MyView extends ScrollView
# @content: ->
# @div()
#
# initialize: ->
# super
# @text('super long content that will scroll')
# ```
#
module.exports =
class ScrollView extends View
initialize: ->
+12 -12
Ver Arquivo
@@ -2,7 +2,7 @@
EditorView = require './editor-view'
fuzzyFilter = require('fuzzaldrin').filter
# Public: Provides a view that renders a list of items with an editor that
# Essential: Provides a view that renders a list of items with an editor that
# filters the items. Used by many packages such as the fuzzy-finder,
# command-palette, symbols-view and autocomplete.
#
@@ -51,7 +51,7 @@ class SelectListView extends View
# This method can be overridden by subclasses but `super` should always
# be called.
initialize: ->
@filterEditorView.getEditor().getBuffer().on 'changed', =>
@filterEditorView.getEditor().getBuffer().onDidChange =>
@schedulePopulateList()
@filterEditorView.hiddenInput.on 'focusout', =>
@cancel() unless @cancelling
@@ -96,14 +96,14 @@ class SelectListView extends View
# This should be model items not actual views. {::viewForItem} will be
# called to render the item when it is being appended to the list view.
#
# items - The {Array} of model items to display in the list (default: []).
# * `items` The {Array} of model items to display in the list (default: []).
setItems: (@items=[]) ->
@populateList()
@setLoading()
# Public: Set the error message to display.
#
# message - The {String} error message (default: '').
# * `message` The {String} error message (default: '').
setError: (message='') ->
if message.length is 0
@error.text('').hide()
@@ -113,7 +113,7 @@ class SelectListView extends View
# Public: Set the loading message to display.
#
# message - The {String} loading message (default: '').
# * `message` The {String} loading message (default: '').
setLoading: (message='') ->
if message.length is 0
@loading.text("")
@@ -165,15 +165,15 @@ class SelectListView extends View
#
# Subclasses may override this method to customize the message.
#
# itemCount - The {Number} of items in the array specified to {::setItems}
# filteredItemCount - The {Number} of items that pass the fuzzy filter test.
# * `itemCount` The {Number} of items in the array specified to {::setItems}
# * `filteredItemCount` The {Number} of items that pass the fuzzy filter test.
#
# Returns a {String} message (default: 'No matches found').
getEmptyMessage: (itemCount, filteredItemCount) -> 'No matches found'
# Public: Set the maximum numbers of items to display in the list.
#
# maxItems - The maximum {Number} of items to display.
# * `maxItems` The maximum {Number} of items to display.
setMaxItems: (@maxItems) ->
selectPreviousItemView: ->
@@ -224,8 +224,8 @@ class SelectListView extends View
#
# This is called when the item is about to appended to the list view.
#
# item - The model item being rendered. This will always be one of the items
# previously passed to {::setItems}.
# * `item` The model item being rendered. This will always be one of the items
# previously passed to {::setItems}.
#
# Returns a String of HTML, DOM element, jQuery object, or View.
viewForItem: (item) ->
@@ -235,8 +235,8 @@ class SelectListView extends View
#
# This method must be overridden by subclasses.
#
# item - The selected model item. This will always be one of the items
# previously passed to {::setItems}.
# * `item` The selected model item. This will always be one of the items
# previously passed to {::setItems}.
#
# Returns a DOM element, jQuery object, or {View}.
confirmed: (item) ->
+63 -41
Ver Arquivo
@@ -2,7 +2,20 @@
{Model} = require 'theorist'
{pick} = require 'underscore-plus'
# Public: Represents a selection in the {Editor}.
# Extended: Represents a selection in the {Editor}.
#
# ## Events
#
# ### screen-range-changed
#
# Extended: Emit when the selection was moved.
#
# * `screenRange` {Range} indicating the new screenrange
#
# ### destroyed
#
# Extended: Emit when the selection was destroyed
#
module.exports =
class Selection extends Model
cursor: null
@@ -56,8 +69,8 @@ class Selection extends Model
# Public: Modifies the screen range for the selection.
#
# screenRange - The new {Range} to use.
# options - A hash of options matching those found in {::setBufferRange}.
# * `screenRange` The new {Range} to use.
# * `options` (optional) {Object} options matching those found in {::setBufferRange}.
setScreenRange: (screenRange, options) ->
@setBufferRange(@editor.bufferRangeForScreenRange(screenRange), options)
@@ -67,11 +80,10 @@ class Selection extends Model
# Public: Modifies the buffer {Range} for the selection.
#
# screenRange - The new {Range} to select.
# options - An {Object} with the keys:
# :preserveFolds - if `true`, the fold settings are preserved after the
# selection moves.
# :autoscroll - if `true`, the {Editor} scrolls to the new selection.
# * `screenRange` The new {Range} to select.
# * `options` (optional) {Object} with the keys:
# * `preserveFolds` if `true`, the fold settings are preserved after the selection moves.
# * `autoscroll` if `true`, the {Editor} scrolls to the new selection.
setBufferRange: (bufferRange, options={}) ->
bufferRange = Range.fromObject(bufferRange)
@needsAutoscroll = options.autoscroll
@@ -141,7 +153,7 @@ class Selection extends Model
# Public: Selects an entire line in the buffer.
#
# row - The line {Number} to select (default: the row of the cursor).
# * `row` The line {Number} to select (default: the row of the cursor).
selectLine: (row=@cursor.getBufferPosition().row) ->
range = @editor.bufferRangeForBufferRow(row, includeNewline: true)
@setBufferRange(@getBufferRange().union(range))
@@ -160,7 +172,7 @@ class Selection extends Model
# Public: Selects the text from the current cursor position to a given screen
# position.
#
# position - An instance of {Point}, with a given `row` and `column`.
# * `position` An instance of {Point}, with a given `row` and `column`.
selectToScreenPosition: (position) ->
position = Point.fromObject(position)
@@ -181,23 +193,31 @@ class Selection extends Model
# Public: Selects the text from the current cursor position to a given buffer
# position.
#
# position - An instance of {Point}, with a given `row` and `column`.
# * `position` An instance of {Point}, with a given `row` and `column`.
selectToBufferPosition: (position) ->
@modifySelection => @cursor.setBufferPosition(position)
# Public: Selects the text one position right of the cursor.
selectRight: ->
@modifySelection => @cursor.moveRight()
#
# * `columnCount` (optional) {Number} number of columns to select (default: 1)
selectRight: (columnCount) ->
@modifySelection => @cursor.moveRight(columnCount)
# Public: Selects the text one position left of the cursor.
selectLeft: ->
@modifySelection => @cursor.moveLeft()
#
# * `columnCount` (optional) {Number} number of columns to select (default: 1)
selectLeft: (columnCount) ->
@modifySelection => @cursor.moveLeft(columnCount)
# Public: Selects all the text one position above the cursor.
#
# * `rowCount` (optional) {Number} number of rows to select (default: 1)
selectUp: (rowCount) ->
@modifySelection => @cursor.moveUp(rowCount)
# Public: Selects all the text one position below the cursor.
#
# * `rowCount` (optional) {Number} number of rows to select (default: 1)
selectDown: (rowCount) ->
@modifySelection => @cursor.moveDown(rowCount)
@@ -306,14 +326,14 @@ class Selection extends Model
# Public: Replaces text at the current selection.
#
# text - A {String} representing the text to add
# options - An {Object} with keys:
# :select - if `true`, selects the newly added text.
# :autoIndent - if `true`, indents all inserted text appropriately.
# :autoIndentNewline - if `true`, indent newline appropriately.
# :autoDecreaseIndent - if `true`, decreases indent level appropriately
# (for example, when a closing bracket is inserted).
# :undo - if `skip`, skips the undo stack for this operation.
# * `text` A {String} representing the text to add
# * `options` (optional) {Object} with keys:
# * `select` if `true`, selects the newly added text.
# * `autoIndent` if `true`, indents all inserted text appropriately.
# * `autoIndentNewline` if `true`, indent newline appropriately.
# * `autoDecreaseIndent` if `true`, decreases indent level appropriately
# (for example, when a closing bracket is inserted).
# * `undo` if `skip`, skips the undo stack for this operation.
insertText: (text, options={}) ->
oldBufferRange = @getBufferRange()
@editor.unfoldBufferRow(oldBufferRange.end.row)
@@ -345,8 +365,8 @@ class Selection extends Model
# Public: Indents the given text to the suggested level based on the grammar.
#
# text - The {String} to indent within the selection.
# indentBasis - The beginning indent level.
# * `text` The {String} to indent within the selection.
# * `indentBasis` The beginning indent level.
normalizeIndents: (text, indentBasis) ->
textPrecedingCursor = @cursor.getCurrentBufferLine()[0...@cursor.getBufferColumn()]
isCursorInsideExistingLine = /\S/.test(textPrecedingCursor)
@@ -378,9 +398,9 @@ class Selection extends Model
# non-whitespace characters, and otherwise inserts a tab. If the selection is
# non empty, calls {::indentSelectedRows}.
#
# options - A {Object} with the keys:
# :autoIndent - If `true`, the line is indented to an automatically-inferred
# level. Otherwise, {Editor::getTabText} is inserted.
# * `options` (optional) {Object} with the keys:
# * `autoIndent` If `true`, the line is indented to an automatically-inferred
# level. Otherwise, {Editor::getTabText} is inserted.
indent: ({ autoIndent }={}) ->
{ row, column } = @cursor.getBufferPosition()
@@ -549,16 +569,18 @@ class Selection extends Model
@cut(maintainClipboard)
# Public: Copies the selection to the clipboard and then deletes it.
#
# * `maintainClipboard` {Boolean} (default: false) See {::copy}
cut: (maintainClipboard=false) ->
@copy(maintainClipboard)
@delete()
# Public: Copies the current selection to the clipboard.
#
# If the `maintainClipboard` is set to `true`, a specific metadata property
# is created to store each content copied to the clipboard. The clipboard
# `text` still contains the concatenation of the clipboard with the
# current selection.
# * `maintainClipboard` {Boolean} if `true`, a specific metadata property
# is created to store each content copied to the clipboard. The clipboard
# `text` still contains the concatenation of the clipboard with the
# current selection. (default: false)
copy: (maintainClipboard=false) ->
return if @isEmpty()
text = @editor.buffer.getTextInRange(@getBufferRange())
@@ -598,9 +620,9 @@ class Selection extends Model
# Public: Identifies if a selection intersects with a given buffer range.
#
# bufferRange - A {Range} to check against.
# * `bufferRange` A {Range} to check against.
#
# Returns a Boolean.
# Returns a {Boolean}
intersectsBufferRange: (bufferRange) ->
@getBufferRange().intersectsWith(bufferRange)
@@ -612,17 +634,17 @@ class Selection extends Model
# Public: Identifies if a selection intersects with another selection.
#
# otherSelection - A {Selection} to check against.
# * `otherSelection` A {Selection} to check against.
#
# Returns a Boolean.
intersectsWith: (otherSelection) ->
@getBufferRange().intersectsWith(otherSelection.getBufferRange())
# Returns a {Boolean}
intersectsWith: (otherSelection, exclusive) ->
@getBufferRange().intersectsWith(otherSelection.getBufferRange(), exclusive)
# Public: Combines the given selection into this selection and then destroys
# the given selection.
#
# otherSelection - A {Selection} to merge with.
# options - A hash of options matching those found in {::setBufferRange}.
# * `otherSelection` A {Selection} to merge with.
# * `options` (optional) {Object} options matching those found in {::setBufferRange}.
merge: (otherSelection, options) ->
myGoalBufferRange = @getGoalBufferRange()
otherGoalBufferRange = otherSelection.getGoalBufferRange()
@@ -638,7 +660,7 @@ class Selection extends Model
#
# See {Range::compare} for more details.
#
# otherSelection - A {Selection} to compare against.
# * `otherSelection` A {Selection} to compare against
compare: (otherSelection) ->
@getBufferRange().compare(otherSelection.getBufferRange())
+5 -4
Ver Arquivo
@@ -14,7 +14,7 @@ Token = require './token'
# An instance of this class is always available as the `atom.syntax` global.
#
# The Syntax class also contains properties for things such as the
# language-specific comment regexes.
# language-specific comment regexes. See {::getProperty} for more details.
module.exports =
class Syntax extends GrammarRegistry
PropertyAccessors.includeInto(this)
@@ -55,14 +55,15 @@ class Syntax extends GrammarRegistry
# Public: Get a property for the given scope and key path.
#
# ## Example
# ## Examples
#
# ```coffee
# comment = atom.syntax.getProperty(['.source.ruby'], 'editor.commentStart')
# console.log(comment) # '# '
# ```
#
# scope - An {Array} of {String} scopes.
# keyPath - A {String} key path.
# * `scope` An {Array} of {String} scopes.
# * `keyPath` A {String} key path.
#
# Returns a {String} property value or undefined.
getProperty: (scope, keyPath) ->
+40 -21
Ver Arquivo
@@ -6,27 +6,41 @@ child_process = require 'child_process'
#
# Used by the fuzzy-finder.
#
# ## Events
#
# * task:log - Emitted when console.log is called within the task.
# * task:warn - Emitted when console.warn is called within the task.
# * task:error - Emitted when console.error is called within the task.
# * task:completed - Emitted when the task has succeeded or failed.
#
# ## Requiring in packages
# ## Examples
#
# ```coffee
# {Task} = require 'atom'
# {Task} = require 'atom'
# ```
#
# ## Events
#
# ### task:log
#
# Emitted when console.log is called within the task.
#
# ### task:warn
#
# Emitted when console.warn is called within the task.
#
# ### task:error
#
# Emitted when console.error is called within the task.
#
# ### task:completed
#
# Emitted when the task has succeeded or failed.
#
module.exports =
class Task
Emitter.includeInto(this)
# Public: A helper method to easily launch and run a task once.
#
# taskPath - The {String} path to the CoffeeScript/JavaScript file which
# exports a single {Function} to execute.
# args - The arguments to pass to the exported function.
# * `taskPath` The {String} path to the CoffeeScript/JavaScript file which
# exports a single {Function} to execute.
# * `args` The arguments to pass to the exported function.
#
# Returns the created {Task}.
@once: (taskPath, args...) ->
task = new Task(taskPath)
task.once 'task:completed', -> task.terminate()
@@ -43,8 +57,8 @@ class Task
# Public: Creates a task.
#
# taskPath - The {String} path to the CoffeeScript/JavaScript file that
# exports a single {Function} to execute.
# * `taskPath` The {String} path to the CoffeeScript/JavaScript file that
# exports a single {Function} to execute.
constructor: (taskPath) ->
coffeeCacheRequire = "require('#{require.resolve('./coffee-cache')}').register();"
coffeeScriptRequire = "require('#{require.resolve('coffee-script')}').register();"
@@ -81,10 +95,10 @@ class Task
# Throws an error if this task has already been terminated or if sending a
# message to the child process fails.
#
# args - The arguments to pass to the function exported by this task's script.
# callback - An optional {Function} to call when the task completes.
# * `args` The arguments to pass to the function exported by this task's script.
# * `callback` (optional) A {Function} to call when the task completes.
start: (args..., callback) ->
throw new Error("Cannot start terminated process") unless @childProcess?
throw new Error('Cannot start terminated process') unless @childProcess?
@handleEvents()
if _.isFunction(callback)
@@ -92,20 +106,24 @@ class Task
else
args.push(callback)
@send({event: 'start', args})
undefined
# Public: Send message to the task.
#
# Throws an error if this task has already been terminated or if sending a
# message to the child process fails.
#
# message - The message to send to the task.
# * `message` The message to send to the task.
send: (message) ->
throw new Error("Cannot send message to terminated process") unless @childProcess?
@childProcess.send(message)
if @childProcess?
@childProcess.send(message)
else
throw new Error('Cannot send message to terminated process')
undefined
# Public: Forcefully stop the running task.
#
# No events are emitted.
# No more events are emitted once this method is called.
terminate: ->
return unless @childProcess?
@@ -114,3 +132,4 @@ class Task
@childProcess = null
@off()
undefined
+28 -6
Ver Arquivo
@@ -9,9 +9,32 @@ Q = require 'q'
Package = require './package'
{File} = require 'pathwatcher'
# Public: Handles loading and activating available themes.
# Extended: Handles loading and activating available themes.
#
# An instance of this class is always available as the `atom.themes` global.
#
# ## Events
#
# ### reloaded
#
# Extended: Emit when all styles have been reloaded.
#
# ### stylesheet-added
#
# Extended: Emit when a stylesheet has been added.
#
# * `stylesheet` {StyleSheet} object that was removed
#
# ### stylesheet-removed
#
# Extended: Emit when a stylesheet has been removed.
#
# * `stylesheet` {StyleSheet} object that was removed
#
# ### stylesheets-changed
#
# Extended: Emit anytime any style sheet is added or removed from the editor
#
module.exports =
class ThemeManager
Emitter.includeInto(this)
@@ -98,7 +121,7 @@ class ThemeManager
@refreshLessCache() # Update cache again now that @getActiveThemes() is populated
@loadUserStylesheet()
@reloadBaseStylesheets()
@emit('reloaded')
@emit 'reloaded'
deferred.resolve()
deferred.promise
@@ -124,7 +147,7 @@ class ThemeManager
# Public: Set the list of enabled themes.
#
# enabledThemeNames - An {Array} of {String} theme names.
# * `enabledThemeNames` An {Array} of {String} theme names.
setEnabledThemes: (enabledThemeNames) ->
atom.config.set('core.themes', enabledThemeNames)
@@ -187,9 +210,8 @@ class ThemeManager
#
# This supports both CSS and LESS stylsheets.
#
# stylesheetPath - A {String} path to the stylesheet that can be an absolute
# path or a relative path that will be resolved against the
# load path.
# * `stylesheetPath` A {String} path to the stylesheet that can be an absolute
# path or a relative path that will be resolved against the load path.
#
# Returns the absolute path to the required stylesheet.
requireStylesheet: (stylesheetPath, type = 'bundled', htmlElement) ->
+11 -20
Ver Arquivo
@@ -30,10 +30,8 @@ class TokenizedBuffer extends Model
@setGrammar(grammar, newScore) if newScore > @currentGrammarScore
@on 'grammar-changed grammar-updated', => @retokenizeLines()
@subscribe @buffer, "changed", (e) => @handleBufferChange(e)
@subscribe @buffer, "path-changed", =>
@bufferPath = @buffer.getPath()
@reloadGrammar()
@subscribe @buffer.onDidChange (e) => @handleBufferChange(e)
@subscribe @buffer.onDidChangePath (@bufferPath) => @reloadGrammar()
@subscribe @$tabLength.changes, (tabLength) => @retokenizeLines()
@@ -221,25 +219,18 @@ class TokenizedBuffer extends Model
{tokens, ruleStack} = @grammar.tokenizeLine(line, ruleStack, row is 0)
new TokenizedLine({tokens, ruleStack, tabLength, lineEnding, indentLevel, @invisibles})
# FIXME: benogle says: These are actually buffer rows as all buffer rows are
# accounted for in @tokenizedLines
lineForScreenRow: (row) ->
@linesForScreenRows(row, row)[0]
tokenizedLineForRow: (bufferRow) ->
@tokenizedLines[bufferRow]
# FIXME: benogle says: These are actually buffer rows as all buffer rows are
# accounted for in @tokenizedLines
linesForScreenRows: (startRow, endRow) ->
@tokenizedLines[startRow..endRow]
stackForRow: (bufferRow) ->
@tokenizedLines[bufferRow]?.ruleStack
stackForRow: (row) ->
@tokenizedLines[row]?.ruleStack
indentLevelForRow: (row) ->
line = @buffer.lineForRow(row)
indentLevelForRow: (bufferRow) ->
line = @buffer.lineForRow(bufferRow)
indentLevel = 0
if line is ''
nextRow = row + 1
nextRow = bufferRow + 1
lineCount = @getLineCount()
while nextRow < lineCount
nextLine = @buffer.lineForRow(nextRow)
@@ -248,7 +239,7 @@ class TokenizedBuffer extends Model
break
nextRow++
previousRow = row - 1
previousRow = bufferRow - 1
while previousRow >= 0
previousLine = @buffer.lineForRow(previousRow)
unless previousLine is ''
@@ -373,5 +364,5 @@ class TokenizedBuffer extends Model
logLines: (start=0, end=@buffer.getLastRow()) ->
for row in [start..end]
line = @lineForScreenRow(row).text
line = @tokenizedLineForRow(row).text
console.log row, line, line.length
+24 -6
Ver Arquivo
@@ -15,7 +15,7 @@ PaneRowView = require './pane-row-view'
PaneContainerView = require './pane-container-view'
Editor = require './editor'
# Public: The top-level view for the entire window. An instance of this class is
# Essential: The top-level view for the entire window. An instance of this class is
# available via the `atom.workspaceView` global.
#
# It is backed by a model object, an instance of {Workspace}, which is available
@@ -44,7 +44,7 @@ Editor = require './editor'
# the built-in `atom` module.
#
# ```coffee
# {WorkspaceView} = require 'atom'
# {WorkspaceView} = require 'atom'
# ```
#
# You can assign it to the `atom.workspaceView` global in the spec or just use
@@ -84,7 +84,7 @@ class WorkspaceView extends View
@panes.replaceWith(panes)
@panes = panes
@subscribe @model, 'uri-opened', => @trigger 'uri-opened'
@subscribe @model.onDidOpen => @trigger 'uri-opened'
@subscribe scrollbarStyle, (style) =>
@removeClass('scrollbars-visible-always scrollbars-visible-when-scrolling')
@@ -244,40 +244,56 @@ class WorkspaceView extends View
# Public: Prepend an element or view to the panels at the top of the
# workspace.
#
# * `element` jQuery object or DOM element
prependToTop: (element) ->
@vertical.prepend(element)
# Public: Append an element or view to the panels at the top of the workspace.
#
# * `element` jQuery object or DOM element
appendToTop: (element) ->
@panes.before(element)
# Public: Prepend an element or view to the panels at the bottom of the
# workspace.
#
# * `element` jQuery object or DOM element
prependToBottom: (element) ->
@panes.after(element)
# Public: Append an element or view to the panels at the bottom of the
# workspace.
#
# * `element` jQuery object or DOM element
appendToBottom: (element) ->
@vertical.append(element)
# Public: Prepend an element or view to the panels at the left of the
# workspace.
#
# * `element` jQuery object or DOM element
prependToLeft: (element) ->
@horizontal.prepend(element)
# Public: Append an element or view to the panels at the left of the
# workspace.
#
# * `element` jQuery object or DOM element
appendToLeft: (element) ->
@vertical.before(element)
# Public: Prepend an element or view to the panels at the right of the
# workspace.
#
# * `element` jQuery object or DOM element
prependToRight: (element) ->
@vertical.after(element)
# Public: Append an element or view to the panels at the right of the
# workspace.
#
# * `element` jQuery object or DOM element
appendToRight: (element) ->
@horizontal.append(element)
@@ -317,7 +333,8 @@ class WorkspaceView extends View
# Public: Register a function to be called for every current and future
# pane view in the workspace.
#
# callback - A {Function} with a {PaneView} as its only argument.
# * `callback` A {Function} with a {PaneView} as its only argument.
# * `paneView` {PaneView}
#
# Returns a subscription object with an `.off` method that you can call to
# unregister the callback.
@@ -338,7 +355,8 @@ class WorkspaceView extends View
# editor view in the workspace (only includes {EditorView}s that are pane
# items).
#
# callback - A {Function} with an {EditorView} as its only argument.
# * `callback` A {Function} with an {EditorView} as its only argument.
# * `editorView` {EditorView}
#
# Returns a subscription object with an `.off` method that you can call to
# unregister the callback.
@@ -391,4 +409,4 @@ class WorkspaceView extends View
# Deprecated: Call {Workspace::getActivePaneItem} instead.
getActivePaneItem: ->
deprecate("Use Workspace::getActivePaneItem instead")
@model.activePaneItem
@model.getActivePaneItem()
+229 -92
Ver Arquivo
@@ -5,6 +5,7 @@ _ = require 'underscore-plus'
Q = require 'q'
Serializable = require 'serializable'
Delegator = require 'delegato'
{Emitter} = require 'event-kit'
Editor = require './editor'
PaneContainer = require './pane-container'
Pane = require './pane'
@@ -15,6 +16,9 @@ Pane = require './pane'
# Interact with this object to open files, be notified of current and future
# editors, and manipulate panes. To add panels, you'll need to use the
# {WorkspaceView} class for now until we establish APIs at the model layer.
#
# * `editor` {Editor} the new editor
#
module.exports =
class Workspace extends Model
atom.deserializers.add(this)
@@ -30,9 +34,11 @@ class Workspace extends Model
constructor: ->
super
@emitter = new Emitter
@openers = []
@subscribe @paneContainer, 'item-destroyed', @onPaneItemDestroyed
@paneContainer.onDidDestroyPaneItem(@onPaneItemDestroyed)
@registerOpener (filePath) =>
switch filePath
when 'atom://.atom/stylesheet'
@@ -69,51 +75,152 @@ class Workspace extends Model
for scopeName in includedGrammarScopes ? []
addGrammar(atom.syntax.grammarForScopeName(scopeName))
addGrammar(editor.getGrammar()) for editor in @getEditors()
editors = @getTextEditors()
addGrammar(editor.getGrammar()) for editor in editors
if editors.length > 0
for grammar in atom.syntax.getGrammars() when grammar.injectionSelector
addGrammar(grammar)
_.uniq(packageNames)
editorAdded: (editor) ->
@emit 'editor-created', editor
# Public: Register a function to be called for every current and future
# {Editor} in the workspace.
###
Section: Event Subscription
###
# Extended: Invoke the given callback when a pane is added to the workspace.
#
# callback - A {Function} with an {Editor} as its only argument.
# * `callback` {Function} to be called panes are added.
# * `event` {Object} with the following keys:
# * `pane` The added pane.
#
# Returns a subscription object with an `.off` method that you can call to
# unregister the callback.
# Returns a {Disposable} on which `.dispose()` can be called to unsubscribe.
onDidAddPane: (callback) -> @paneContainer.onDidAddPane(callback)
# Extended: Invoke the given callback with all current and future panes in the
# workspace.
#
# * `callback` {Function} to be called with current and future panes.
# * `pane` A {Pane} that is present in {::getPanes} at the time of
# subscription or that is added at some later time.
#
# Returns a {Disposable} on which `.dispose()` can be called to unsubscribe.
observePanes: (callback) -> @paneContainer.observePanes(callback)
# Extended: Invoke the given callback when a pane item is added to the
# workspace.
#
# * `callback` {Function} to be called panes are added.
# * `event` {Object} with the following keys:
# * `item` The added pane item.
# * `pane` {Pane} containing the added item.
# * `index` {Number} indicating the index of the added item in its pane.
#
# Returns a {Disposable} on which `.dispose()` can be called to unsubscribe.
onDidAddPaneItem: (callback) -> @paneContainer.onDidAddPaneItem(callback)
# Extended: Invoke the given callback with all current and future panes items in
# the workspace.
#
# * `callback` {Function} to be called with current and future pane items.
# * `item` An item that is present in {::getPaneItems} at the time of
# subscription or that is added at some later time.
#
# Returns a {Disposable} on which `.dispose()` can be called to unsubscribe.
observePaneItems: (callback) -> @paneContainer.observePaneItems(callback)
# Extended: Invoke the given callback when a text editor is added to the
# workspace.
#
# * `callback` {Function} to be called panes are added.
# * `event` {Object} with the following keys:
# * `textEditor` {Editor} that was added.
# * `pane` {Pane} containing the added text editor.
# * `index` {Number} indicating the index of the added text editor in its
# pane.
#
# Returns a {Disposable} on which `.dispose()` can be called to unsubscribe.
onDidAddTextEditor: (callback) ->
@onDidAddPaneItem ({item, pane, index}) ->
callback({textEditor: item, pane, index}) if item instanceof Editor
# Essential: Invoke the given callback with all current and future text
# editors in the workspace.
#
# * `callback` {Function} to be called with current and future text editors.
# * `editor` An {Editor} that is present in {::getTextEditors} at the time
# of subscription or that is added at some later time.
#
# Returns a {Disposable} on which `.dispose()` can be called to unsubscribe.
observeTextEditors: (callback) ->
callback(textEditor) for textEditor in @getTextEditors()
@onDidAddTextEditor ({textEditor}) -> callback(textEditor)
# Essential: Invoke the given callback whenever an item is opened. Unlike
# ::onDidAddPaneItem, observers will be notified for items that are already
# present in the workspace when they are reopened.
#
# * `callback` {Function} to be called whenever an item is opened.
# * `event` {Object} with the following keys:
# * `uri` {String} representing the opened URI. Could be `undefined`.
# * `item` The opened item.
# * `pane` The pane in which the item was opened.
# * `index` The index of the opened item on its pane.
#
# Returns a {Disposable} on which `.dispose()` can be called to unsubscribe.
onDidOpen: (callback) ->
@emitter.on 'did-open', callback
eachEditor: (callback) ->
deprecate("Use Workspace::observeTextEditors instead")
callback(editor) for editor in @getEditors()
@subscribe this, 'editor-created', (editor) -> callback(editor)
# Public: Get all current editors in the workspace.
#
# Returns an {Array} of {Editor}s.
getEditors: ->
deprecate("Use Workspace::getTextEditors instead")
editors = []
for pane in @paneContainer.getPanes()
editors.push(item) for item in pane.getItems() when item instanceof Editor
editors
# Public: Open a given a URI in Atom asynchronously.
on: (eventName) ->
switch eventName
when 'editor-created'
deprecate("Use Workspace::onDidAddTextEditor or Workspace::observeTextEditors instead.")
when 'uri-opened'
deprecate("Use Workspace::onDidAddPaneItem instead.")
else
deprecate("Subscribing via ::on is deprecated. Use documented event subscription methods instead.")
super
###
Section: Opening
###
# Essential: Open a given a URI in Atom asynchronously.
#
# uri - A {String} containing a URI.
# options - An optional options {Object}
# :initialLine - A {Number} indicating which row to move the cursor to
# initially. Defaults to `0`.
# :initialColumn - A {Number} indicating which column to move the cursor to
# initially. Defaults to `0`.
# :split - Either 'left' or 'right'. If 'left', the item will be opened in
# leftmost pane of the current active pane's row. If 'right', the
# item will be opened in the rightmost pane of the current active
# pane's row.
# :activatePane - A {Boolean} indicating whether to call {Pane::activate} on
# the containing pane. Defaults to `true`.
# :searchAllPanes - A {Boolean}. If `true`, the workspace will attempt to
# activate an existing item for the given URI on any pane.
# If `false`, only the active pane will be searched for
# an existing item for the same URI. Defaults to `false`.
# * `uri` A {String} containing a URI.
# * `options` (optional) {Object}
# * `initialLine` A {Number} indicating which row to move the cursor to
# initially. Defaults to `0`.
# * `initialColumn` A {Number} indicating which column to move the cursor to
# initially. Defaults to `0`.
# * `split` Either 'left' or 'right'. If 'left', the item will be opened in
# leftmost pane of the current active pane's row. If 'right', the
# item will be opened in the rightmost pane of the current active pane's row.
# * `activatePane` A {Boolean} indicating whether to call {Pane::activate} on
# containing pane. Defaults to `true`.
# * `searchAllPanes` A {Boolean}. If `true`, the workspace will attempt to
# activate an existing item for the given URI on any pane.
# If `false`, only the active pane will be searched for
# an existing item for the same URI. Defaults to `false`.
#
# Returns a promise that resolves to the {Editor} for the file URI.
open: (uri, options={}) ->
@@ -124,15 +231,15 @@ class Workspace extends Model
pane = @paneContainer.paneForUri(uri) if searchAllPanes
pane ?= switch split
when 'left'
@activePane.findLeftmostSibling()
@getActivePane().findLeftmostSibling()
when 'right'
@activePane.findOrCreateRightmostSibling()
@getActivePane().findOrCreateRightmostSibling()
else
@activePane
@getActivePane()
@openUriInPane(uri, pane, options)
# Public: Open Atom's license in the active pane.
# Open Atom's license in the active pane.
openLicense: ->
@open(join(atom.getLoadSettings().resourcePath, 'LICENSE.md'))
@@ -140,14 +247,14 @@ class Workspace extends Model
# in specs. Calling this in production code will block the UI thread and
# everyone will be mad at you.**
#
# uri - A {String} containing a URI.
# options - An optional options {Object}
# :initialLine - A {Number} indicating which row to move the cursor to
# initially. Defaults to `0`.
# :initialColumn - A {Number} indicating which column to move the cursor to
# initially. Defaults to `0`.
# :activatePane - A {Boolean} indicating whether to call {Pane::activate} on
# the containing pane. Defaults to `true`.
# * `uri` A {String} containing a URI.
# * `options` An optional options {Object}
# * `initialLine` A {Number} indicating which row to move the cursor to
# initially. Defaults to `0`.
# * `initialColumn` A {Number} indicating which column to move the cursor to
# initially. Defaults to `0`.
# * `activatePane` A {Boolean} indicating whether to call {Pane::activate} on
# the containing pane. Defaults to `true`.
openSync: (uri='', options={}) ->
deprecate("Don't use the `changeFocus` option") if options.changeFocus?
@@ -182,12 +289,14 @@ class Workspace extends Model
@itemOpened(item)
pane.activateItem(item)
pane.activate() if changeFocus
index = pane.getActiveItemIndex()
@emit "uri-opened"
@emitter.emit 'did-open', {uri, pane, item, index}
item
.catch (error) ->
console.error(error.stack ? error)
# Public: Asynchronously reopens the last-closed item's URI if it hasn't already been
# Extended: Asynchronously reopens the last-closed item's URI if it hasn't already been
# reopened.
#
# Returns a promise that is resolved when the item is opened
@@ -203,65 +312,68 @@ class Workspace extends Model
if uri = @destroyedItemUris.pop()
@openSync(uri)
# Public: Register an opener for a uri.
# Extended: Register an opener for a uri.
#
# An {Editor} will be used if no openers return a value.
#
# ## Example
# ```coffeescript
# atom.project.registerOpener (uri) ->
# if path.extname(uri) is '.toml'
# return new TomlEditor(uri)
# ## Examples
#
# ```coffee
# atom.project.registerOpener (uri) ->
# if path.extname(uri) is '.toml'
# return new TomlEditor(uri)
# ```
#
# opener - A {Function} to be called when a path is being opened.
# * `opener` A {Function} to be called when a path is being opened.
registerOpener: (opener) ->
@openers.push(opener)
# Public: Unregister an opener registered with {::registerOpener}.
# Extended: Unregister an opener registered with {::registerOpener}.
unregisterOpener: (opener) ->
_.remove(@openers, opener)
getOpeners: ->
@openers
# Public: Get the active {Pane}.
###
Section: Pane Items
###
# Essential: Get all pane items in the workspace.
#
# Returns a {Pane}.
getActivePane: ->
@paneContainer.activePane
# Returns an {Array} of items.
getPaneItems: ->
@paneContainer.getPaneItems()
# Public: Get all {Pane}s.
#
# Returns an {Array} of {Pane}s.
getPanes: ->
@paneContainer.getPanes()
# Public: Save all pane items.
saveAll: ->
@paneContainer.saveAll()
# Public: Make the next pane active.
activateNextPane: ->
@paneContainer.activateNextPane()
# Public: Make the previous pane active.
activatePreviousPane: ->
@paneContainer.activatePreviousPane()
# Public: Get the first pane {Pane} with an item for the given URI.
#
# Returns a {Pane} or `undefined` if no pane exists for the given URI.
paneForUri: (uri) ->
@paneContainer.paneForUri(uri)
# Public: Get the active {Pane}'s active item.
# Essential: Get the active {Pane}'s active item.
#
# Returns an pane item {Object}.
getActivePaneItem: ->
@paneContainer.getActivePane().getActiveItem()
@paneContainer.getActivePaneItem()
# Public: Save the active pane item.
# Essential: Get all text editors in the workspace.
#
# Returns an {Array} of {Editor}s.
getTextEditors: ->
@getPaneItems().filter (item) -> item instanceof Editor
# Essential: Get the active item if it is an {Editor}.
#
# Returns an {Editor} or `undefined` if the current active item is not an
# {Editor}.
getActiveTextEditor: ->
activeItem = @getActiveItem()
activeItem if activeItem instanceof Editor
# Deprecated:
getActiveEditor: ->
@activePane?.getActiveEditor()
# Extended: Save all pane items.
saveAll: ->
@paneContainer.saveAll()
# Save the active pane item.
#
# If the active pane item currently has a URI according to the item's
# `.getUri` method, calls `.save` on the item. Otherwise
@@ -270,7 +382,7 @@ class Workspace extends Model
saveActivePaneItem: ->
@activePane?.saveActiveItem()
# Public: Prompt the user for a path and save the active pane item to it.
# Prompt the user for a path and save the active pane item to it.
#
# Opens a native dialog where the user selects a path on disk, then calls
# `.saveAs` on the item with the selected path. This method does nothing if
@@ -278,34 +390,59 @@ class Workspace extends Model
saveActivePaneItemAs: ->
@activePane?.saveActiveItemAs()
# Public: Destroy (close) the active pane item.
# Destroy (close) the active pane item.
#
# Removes the active pane item and calls the `.destroy` method on it if one is
# defined.
destroyActivePaneItem: ->
@activePane?.destroyActiveItem()
# Public: Destroy (close) the active pane.
###
Section: Panes
###
# Extended: Get all panes in the workspace.
#
# Returns an {Array} of {Pane}s.
getPanes: ->
@paneContainer.getPanes()
# Extended: Get the active {Pane}.
#
# Returns a {Pane}.
getActivePane: ->
@paneContainer.getActivePane()
# Extended: Make the next pane active.
activateNextPane: ->
@paneContainer.activateNextPane()
# Extended: Make the previous pane active.
activatePreviousPane: ->
@paneContainer.activatePreviousPane()
# Extended: Get the first pane {Pane} with an item for the given URI.
#
# * `uri` {String} uri
#
# Returns a {Pane} or `undefined` if no pane exists for the given URI.
paneForUri: (uri) ->
@paneContainer.paneForUri(uri)
# Destroy (close) the active pane.
destroyActivePane: ->
@activePane?.destroy()
# Public: Get the active item if it is an {Editor}.
#
# Returns an {Editor} or `undefined` if the current active item is not an
# {Editor}.
getActiveEditor: ->
@activePane?.getActiveEditor()
# Public: Increase the editor font size by 1px.
# Increase the editor font size by 1px.
increaseFontSize: ->
atom.config.set("editor.fontSize", atom.config.get("editor.fontSize") + 1)
# Public: Decrease the editor font size by 1px.
# Decrease the editor font size by 1px.
decreaseFontSize: ->
fontSize = atom.config.get("editor.fontSize")
atom.config.set("editor.fontSize", fontSize - 1) if fontSize > 1
# Public: Restore to a default editor font size.
# Restore to a default editor font size.
resetFontSize: ->
atom.config.restoreDefault("editor.fontSize")