Comparar commits

...

511 Commits

Autor SHA1 Mensagem Data
Kevin Sawicki 90ff3f585d Always pass specs on Windows CI 2014-09-23 10:03:14 -07:00
Kevin Sawicki 2a7b73898e Upgrade to bracket-matcher@0.58 2014-09-23 09:08:26 -07:00
Kevin Sawicki 7375b32fb3 Upgrade to bracket-matcher@0.57 2014-09-23 08:51:34 -07:00
Ben Ogle d4f7e710f4 Reorder properties by usage 2014-09-22 17:28:20 -07:00
Kevin Sawicki 32143cfbdb Upgrade to symbols-view@0.66 2014-09-22 16:58:25 -07:00
Ben Ogle 2e4fda323e Merge pull request #3605 from atom/bo-fix-cursor-events
Make cursor / selection events consistent
2014-09-22 16:44:42 -07:00
Ben Ogle 021208d933 Update Cursor::onDidChangePosition doc string 2014-09-22 16:12:51 -07:00
Ben Ogle 688b209000 Update doc string in Selection::onDidChangeRange 2014-09-22 16:12:19 -07:00
Ben Ogle 91a443e7cb Update onDidChangeSelectionRange doc string 2014-09-22 16:09:32 -07:00
Ben Ogle c62fb26001 onDidChangeSelectionRange emits object with ranges + selection 2014-09-22 16:08:12 -07:00
Ben Ogle 3134364362 Add cursor to the docs 2014-09-22 15:50:47 -07:00
Ben Ogle e5c03e139a Only pass event to the editor 2014-09-22 15:50:40 -07:00
Ben Ogle 5083c18c84 Add cursor to onDidChangeCursorPosition event object 2014-09-22 15:37:41 -07:00
Kevin Sawicki 4260eaa329 Merge pull request #3585 from deiga/patch-1
Add matching of Atom.app more stable
2014-09-22 15:06:50 -07:00
Kevin Sawicki dc3a3225b3 Remove logging from specs 2014-09-22 15:00:06 -07:00
Kevin Sawicki 95087b8996 Git -> GitRepository 2014-09-22 14:54:01 -07:00
Kevin Sawicki a06fba75b8 Upgrade to bracket-matcher@0.56 2014-09-22 14:50:25 -07:00
Ben Ogle d727e440aa Merge pull request #3601 from atom/bo-rename-git
Rename Git -> GitRepository
2014-09-22 13:43:04 -07:00
Ben Ogle 6e8cfba440 nof 2014-09-22 11:07:53 -07:00
Ben Ogle 7a429b024e Use GitRepository rather than Git 2014-09-22 11:07:41 -07:00
Ben Ogle 84425f238a Rename git -> git-repository 2014-09-22 11:07:19 -07:00
Ben Ogle c62b7cc710 Deprecate requiring Git 2014-09-22 11:01:14 -07:00
Kevin Sawicki 39d3724860 Handle error events in spawned processes
Refs #3600
2014-09-22 10:57:42 -07:00
Kevin Sawicki 9eed8a206a Upgrade to first-mate@2.1.2 2014-09-22 10:47:56 -07:00
Kevin Sawicki ec0bcd90a6 Upload correct verison of .deb file 2014-09-22 10:38:56 -07:00
Kevin Sawicki 08871989e2 Correct process arch value 2014-09-22 10:35:52 -07:00
Kevin Sawicki c94b03f13d Run mkdeb task right before publishing 2014-09-22 10:33:29 -07:00
Kevin Sawicki 481653ff60 🍎 Insert newline with alt-enter and shift-enter
Closes #3588
2014-09-22 10:26:24 -07:00
Nathan Sobo bac99222f3 Force scrollbars to be GPU layers when acceleration is enabled
Fixes #3559

For some reason, Chromium 37 is not compositing scrollbars correctly on
secondary monitors in OS X. They’re invisible when the lines layer
extends beneath the scrollbars unless we apply this style.
2014-09-19 15:10:04 -06:00
Kevin Sawicki d6842dc8a2 Upgrade to language-xml@0.21 2014-09-19 09:56:11 -07:00
Kevin Sawicki 8b651328d2 Upgrade to settings-view@0.145 2014-09-19 09:45:25 -07:00
Kevin Sawicki 17838f832d 📝 Add installing on debian steps 2014-09-19 09:36:30 -07:00
Kevin Sawicki 9e686c11e4 Upgrade to apm 0.96 2014-09-19 09:29:45 -07:00
Timo Sand 8932eba0bf Add matching of Atom.app more stable
I have this file on my Mac `/Users/timosand/Library/Application Support/com.github.atom.ShipIt/update.85PyXs3/Atom.app` and my `mdfind` returns it. It seems to be a common one, so I thought to remove it from the list to be sure that it selects the right Atom.app
2014-09-19 07:48:21 +03:00
Ben Ogle 5cc62b2429 Merge pull request #3583 from atom/bo-final-docs-pass
Final docs pass
2014-09-18 18:45:18 -07:00
Ben Ogle e5096d8190 Data -> Details 2014-09-18 18:40:46 -07:00
Ben Ogle 2af699f35e Rename cursor sections 2014-09-18 17:27:08 -07:00
Kevin Sawicki b1f48338cd Upgrade to apm 0.95 2014-09-18 17:26:46 -07:00
Ben Ogle 7632e5dd40 Reorg decoration 2014-09-18 17:24:24 -07:00
Ben Ogle 9f1aabed0a Reorg Editor a bit based on conversations
Move heavier used sections near the top of the file. Make some of the
single extended methods public.
2014-09-18 17:20:18 -07:00
Ben Ogle 33827d1dc8 Upgrade text-buffer for better docs 2014-09-18 16:59:06 -07:00
Ben Ogle 29f53d4432 PaneView is private 2014-09-18 16:52:56 -07:00
Ben Ogle f407ca3a0c saveAll is private 2014-09-18 16:52:11 -07:00
Ben Ogle 2d3ea244ee Opener stuff is essential 2014-09-18 16:51:59 -07:00
Ben Ogle 97931ff259 Move observePaneItems and onDidChangePaneItem to essential 2014-09-18 16:51:30 -07:00
Ben Ogle d02c3e0d62 WorkspaceView is extended 2014-09-18 16:45:13 -07:00
Ben Ogle e2d9e5bd74 Make focusing other pane views from workspaceView private 2014-09-18 16:44:49 -07:00
Kevin Sawicki 0b03c89010 Upgrade to settings-view@0.144 2014-09-18 16:43:47 -07:00
Ben Ogle 69f54b90dc Clean up atom details section 2014-09-18 16:43:13 -07:00
Ben Ogle 7c483f989f Clean up marker 2014-09-18 16:43:00 -07:00
Kevin Sawicki c89bafb66e Refresh horizontal scrollbar DOM node
Previously the vertical scrollbar's DOM node was used as the
horizontal node causing the horizontal scrollbar to not refresh
properly

Closes #3511
2014-09-18 16:26:40 -07:00
Kevin Sawicki ee093d1709 Merge pull request #3582 from atom/ks-dont-allow-focused-specs-on-ci
Fail focused specs on CI
2014-09-18 16:16:17 -07:00
Ben Ogle 155d4ce733 Merge pull request #3569 from atom/bo-proper-doc-marker
Rename DisplayBufferMarker to Marker
2014-09-18 16:14:35 -07:00
Kevin Sawicki 021278e902 Always auto indent at least one hard tab
Previously when the delta between the suggested and current indent level
was greater than zero but less than one, no text would be inserted since
Editor::buildIndentString returns an empty string for levels less than one
when using hard tabs.

Closes #3575
2014-09-18 15:36:31 -07:00
Kevin Sawicki 597942c4ac Fail focused specs on CI
This ensures focused specs never end up as green builds
2014-09-18 15:18:42 -07:00
Kevin Sawicki 7f3279e789 Unfocus spec 2014-09-18 14:50:36 -07:00
Ben Ogle 325cc95f48 Fix specs 2014-09-18 13:53:13 -07:00
Ben Ogle 068c2c359f displayBufferMarker -> marker 2014-09-18 13:53:13 -07:00
Ben Ogle 39343b0c52 Fix reference to display-buffer-marker 2014-09-18 13:53:13 -07:00
Ben Ogle 6121147fc1 Upgrade text-buffer to have a private marker 2014-09-18 13:53:12 -07:00
Ben Ogle 65b41fa502 Move buffer-display-marker -> marker 2014-09-18 13:53:12 -07:00
Ben Ogle 9af2325f17 Rename DisplayBufferMarker -> Marker
Gnar!! 😎
2014-09-18 13:53:12 -07:00
Ben Ogle fb7b9041ab Shore up the docs around marker creation and invalidation 2014-09-18 13:53:12 -07:00
Ben Ogle bf44cf89db DisplayBufferMarker::matchesAttributes -> ::matchesProperties 2014-09-18 13:53:12 -07:00
Ben Ogle cef8b95ef3 Deprecate s|getAttributes for s|getProperties 2014-09-18 13:53:12 -07:00
Ben Ogle bd19899dd8 Add DisplayBufferMarker::getInvalidationStrategy 2014-09-18 13:53:12 -07:00
Ben Ogle e3ce6f8a20 Organize DisplayBufferMarker into sections. Add docs from Marker 2014-09-18 13:53:12 -07:00
Kevin Sawicki a88299284e Upgrade to language-ruby@0.38 2014-09-18 13:51:34 -07:00
Kevin Sawicki 0bf0829e77 Upgrade to settings-view@0.143 2014-09-18 13:40:16 -07:00
Kevin Sawicki 46adbea0c2 Merge pull request #3567 from atom/ks-deprecate-custom-dom-events
Deprecate custom DOM events
2014-09-18 13:30:59 -07:00
Kevin Sawicki 62a5c1c58d Don't dispose emitter, specs fail 2014-09-18 11:51:45 -07:00
Kevin Sawicki c291c705ec Add missing support to deprecation message 2014-09-18 11:51:45 -07:00
Kevin Sawicki 95253758f3 Dispose emitter after emitting did-destroy 2014-09-18 11:51:45 -07:00
Kevin Sawicki 1a24c79c7f Deprecate beep event 2014-09-18 11:51:45 -07:00
Kevin Sawicki 522a66c876 📝 Wrap ::onDidAddPaneItem in {} 2014-09-18 11:51:45 -07:00
Kevin Sawicki 67610829f4 Add Atom::onDidBeep 2014-09-18 11:51:44 -07:00
Kevin Sawicki fe30cf2135 Deprecate editor:detached 2014-09-18 11:51:44 -07:00
Kevin Sawicki 280a3c30e6 Deprecate editor:attached 2014-09-18 11:51:44 -07:00
Kevin Sawicki 0b82e83806 Move deprecatedViewEvents to deprecated section 2014-09-18 11:51:44 -07:00
Kevin Sawicki 6d2719c783 Deprecate editor:will-be-removed 2014-09-18 11:51:44 -07:00
Kevin Sawicki 31dd109343 Add Editor::onDidDestroy 2014-09-18 11:51:44 -07:00
Kevin Sawicki a5b7764b38 Deprecate pane:attached 2014-09-18 11:51:44 -07:00
Kevin Sawicki ddc88ec3ed Deprecate when pane:active-item-modified-status-changed 2014-09-18 11:51:44 -07:00
Kevin Sawicki 088d4f439f Deprecate pane:active-item-title-changed on PaneView 2014-09-18 11:51:44 -07:00
Kevin Sawicki b1994b28b3 Deprecate pane:active-item-title-changed 2014-09-18 11:51:44 -07:00
Kevin Sawicki cf303a73b7 Deprecate custom events on PaneView 2014-09-18 11:51:44 -07:00
Kevin Sawicki 1b25ea8a8d Deprecate custom events on EditorView 2014-09-18 11:51:44 -07:00
Kevin Sawicki 291b989ff0 Deprecate pane:item-moved 2014-09-18 11:51:43 -07:00
Kevin Sawicki 1850197f55 Deprecate pane:item-removed 2014-09-18 11:51:43 -07:00
Kevin Sawicki c2c0962e3b Deprecate pane:item-added 2014-09-18 11:51:43 -07:00
Kevin Sawicki 099953c58b Deprecate uri-opened 2014-09-18 11:51:43 -07:00
Kevin Sawicki 33fdb0b518 Deprecate pane:became-inactive 2014-09-18 11:51:43 -07:00
Kevin Sawicki 5148deded1 Deprecate pane:became-active 2014-09-18 11:51:43 -07:00
Kevin Sawicki fdddccf094 💄 2014-09-18 11:51:43 -07:00
Kevin Sawicki 4521eeaeb1 Deprecate pane:active-item-changed 2014-09-18 11:51:43 -07:00
Kevin Sawicki 7344ba644e Deprecate pane-container:active-pane-item-changed 2014-09-18 11:51:43 -07:00
Kevin Sawicki ce887fe877 Deprecate selection:changed 2014-09-18 11:51:43 -07:00
Kevin Sawicki ee701f3b8b Deprecate cursor:moved 2014-09-18 11:51:43 -07:00
Kevin Sawicki c5f593cf08 deprecatedViewEvents -> setupViewEventDeprecations 2014-09-18 11:51:43 -07:00
Kevin Sawicki 4b4dc7224e Deprecate pane:removed event 2014-09-18 11:51:42 -07:00
Kevin Sawicki 31dd9bed6a Map over cmdArgs when quoting 2014-09-18 11:37:37 -07:00
Kevin Sawicki 44860ba572 Filter null/undefined arguments on Windows
These won't be able to be properly quoted
2014-09-18 11:36:41 -07:00
Kevin Sawicki c37e4649b5 Only call replace on string arguments
Prevents errors being thrown when trying to call replace on non-string
arguments.
2014-09-18 11:31:29 -07:00
Kevin Sawicki 3fb22f123a Don't throw errors when folding comments
Previously trying to fold single line comments at the start/end
of files would throw errors since the +1 and -1 used in the
index ranges would cause the loop to advance past the last row
or before the first row.
2014-09-18 11:06:25 -07:00
Kevin Sawicki 616dae2f22 Upgrade to tree-view@0.126 2014-09-18 10:33:08 -07:00
Kevin Sawicki e300677da0 Upgrade to less-cache@0.15 2014-09-18 10:03:33 -07:00
Kevin Sawicki ca9d05f6fa Remove notification stylesheet
These were currently undocumented in the styleguide, had hard-coded colors,
weren't being styled by the default light/dark UI themes, and were unused.

They were also causing conflicts with the notification token scope that
the Objective-C grammar uses.
2014-09-18 09:26:46 -07:00
Kevin Sawicki ba49f5d0b8 Upgrade to symbols-view@0.65 2014-09-18 09:22:56 -07:00
Kevin Sawicki 5d22f96f7b Upgrade to language-coffee-script@0.34 2014-09-18 08:52:19 -07:00
Kevin Sawicki afd6f6144c Upgrade to symbols-view@0.64 2014-09-17 18:16:09 -07:00
Kevin Sawicki 14b3bd5b39 Upgrade to language-coffee-script@0.33 2014-09-17 17:03:33 -07:00
Ben Ogle 7bf60a09dd Make ScrollView Extended 2014-09-17 17:02:41 -07:00
Ben Ogle 8448b265d5 Merge pull request #3549 from atom/bo-visibility-split
Add sections and split methods into essential / extended API
2014-09-17 16:51:50 -07:00
Ben Ogle a85a5e8495 Add public back for the deserializers 2014-09-17 16:20:08 -07:00
Ben Ogle 736342b527 Fix the title duplication 2014-09-17 15:59:22 -07:00
Ben Ogle fad83fff1c Change name of section in cursor 2014-09-17 15:57:24 -07:00
Ben Ogle 6f2b1a4b21 Reorganize Selection into sections 2014-09-17 15:57:13 -07:00
Ben Ogle 37ddf096a7 Reorganize ThemeManager into sections 2014-09-17 15:39:16 -07:00
Kevin Sawicki 27584cf069 Upgrade to grammar-selector@0.34 2014-09-17 15:20:31 -07:00
Kevin Sawicki 12181bcb02 Upgrade to language-coffee-script@0.32 2014-09-17 14:44:26 -07:00
Ben Ogle 0963077a32 Reorganize Project class into sections 2014-09-17 14:26:15 -07:00
Kevin Sawicki a476bb220a Upgrade to language-coffee-script@0.31 2014-09-17 14:26:12 -07:00
Ben Ogle cfffae936c Deprecate pathForRepositoryUrl for eventual removal 2014-09-17 14:23:46 -07:00
Nathan Sobo aa8bfd8e5f Remove stray console.log 2014-09-17 15:03:04 -06:00
Nathan Sobo d36c738b07 Merge pull request #3469 from atom/ns-command-registry
Add command registry
2014-09-17 14:55:19 -06:00
Kevin Sawicki bfdb5bd150 Upgrade to tabs@0.52 2014-09-17 13:52:21 -07:00
Kevin Sawicki 8b34f85f34 Upgrade to grammar-selector@0.33 2014-09-17 13:45:55 -07:00
Kevin Sawicki ad17b2d1c3 Upgrade to apm 0.94 2014-09-17 11:29:24 -07:00
Kevin Sawicki e4d50f4b38 Merge pull request #3565 from atom/ks-support-variation-sequences
Support variation sequences
2014-09-17 10:58:43 -07:00
Kevin Sawicki 146e8c2a0b 💄 Remove extra newline 2014-09-17 10:40:12 -07:00
Kevin Sawicki f1fd13b0b2 Return as soon as first paired character is found
Previously the character count of the entire string was taken even
though it was only checking for the presence of a paired character.

Now hasPairedCharacter returns as early as possible and the now
unused getCharacterCount has been removed.
2014-09-17 10:35:33 -07:00
Kevin Sawicki e343b0e0fc Don't treat consecutive variation selectors as a sequence 2014-09-17 10:17:27 -07:00
Kevin Sawicki c1aa5c9e48 📝 Mention variation sequence in comment 2014-09-17 10:17:27 -07:00
Kevin Sawicki 3acddf3e71 📝 Drop text 2014-09-17 10:17:26 -07:00
Kevin Sawicki df68ae26a2 Add specs for variation sequences 2014-09-17 10:17:26 -07:00
Kevin Sawicki fb7061f500 📝 Mention variation sequence in specs 2014-09-17 10:17:26 -07:00
Kevin Sawicki 878da262d2 Add support for Unicode variation sequences
These are character pairs that should be treated as tokens with a
buffer delta of 2 and a screen delta of 1.
2014-09-17 10:17:26 -07:00
Kevin Sawicki b6faffe2db Merge pull request #3555 from atom/ks-include-leading-trailing-classes-for-hard-tabs
Add leading/trailing whitespace classes to hard tab tokens
2014-09-17 10:15:34 -07:00
Kevin Sawicki 36f60c517e Assert other whitespace class is not present 2014-09-17 09:50:55 -07:00
Kevin Sawicki 348f865cab Add spec for all whitespace lines 2014-09-17 09:47:49 -07:00
Kevin Sawicki 18f54e6780 💄 Put leading spec first 2014-09-17 09:42:31 -07:00
Kevin Sawicki b281737838 Add leading/trailing classes to hard tab tokens
Previously the leading-whitespace and trailing-whitespace classes
were never added to tokens that were hard tabs.
2014-09-17 09:42:31 -07:00
Kevin Sawicki 72b92fc3e5 Only add command on platforms where it can be run
Closes #3561
2014-09-17 08:54:16 -07:00
Kevin Sawicki 03fcda8807 Upgrade to grammar-selector@0.32 2014-09-16 18:49:31 -07:00
Kevin Sawicki b6b7ce31a8 Upgrade to language-javascript@0.40 2014-09-16 18:10:32 -07:00
Ben Ogle 13cc97e44f Reorganize PackageManager into sections 2014-09-16 17:05:23 -07:00
Kevin Sawicki 3794cb606f Upgrade to grammar-selector@0.31 2014-09-16 16:56:36 -07:00
Kevin Sawicki 2dbaa52417 Upgrade to grammar-selector@0.30 2014-09-16 16:53:25 -07:00
Ben Ogle 6467f3c425 Reorganize cursor into sections 2014-09-16 16:50:17 -07:00
Kevin Sawicki ad288478d5 Upgrade to language-sql@0.11 2014-09-16 16:46:04 -07:00
Kevin Sawicki dd063c09d0 Upgrade to pathwatcher@2.1.3 2014-09-16 16:41:37 -07:00
Ben Ogle 5252b5314b WorkspaceView Public -> Essential 2014-09-16 16:30:46 -07:00
Ben Ogle 4c93045384 Reorganize WorkspaceView into sections 2014-09-16 16:30:13 -07:00
Ben Ogle fb1ac72b6e installShellCommands is not public 2014-09-16 16:23:30 -07:00
Kevin Sawicki 51aaffb2e5 Upgrade to status-bar@0.45 2014-09-16 16:22:07 -07:00
Ben Ogle 7ff5938454 Convert visibility in SelectListView 2014-09-16 16:18:47 -07:00
Ben Ogle 053d483b2b Rearrange SelectListView with sections 2014-09-16 16:06:37 -07:00
Ben Ogle b444fbd22c Git module is extended 2014-09-16 14:44:49 -07:00
Ben Ogle f1a5e8e1a8 Reorganize Git into sections 2014-09-16 14:41:23 -07:00
Kevin Sawicki 0098ac67ef Upgrade to markdown-preview@0.103 2014-09-16 14:23:38 -07:00
Ben Ogle cc64a2c3b4 Move things into the construction and destruction section 2014-09-16 14:10:49 -07:00
Ben Ogle b9a63d5030 Add bit about editorView being sparse 2014-09-16 14:07:04 -07:00
Kevin Sawicki c747ab411c Upgrade to tabs@0.51 2014-09-16 14:04:01 -07:00
Ben Ogle f80334d617 Task has better examples 2014-09-16 14:03:33 -07:00
Ben Ogle 679c52ffd1 Task is extended 2014-09-16 14:03:17 -07:00
Ben Ogle 1ee1eb3580 Syntax is extended 2014-09-16 13:43:56 -07:00
Ben Ogle 050ec6ca64 MenuManager is extended 2014-09-16 13:42:55 -07:00
Ben Ogle 69ba6e3e7e DeserializerManager is extended 2014-09-16 13:42:26 -07:00
Ben Ogle 6379f87b8a ContextMenuManager is Extended 2014-09-16 13:40:37 -07:00
Ben Ogle f3f4e8f7a3 Config is Essential 2014-09-16 13:39:43 -07:00
Ben Ogle dbca4f1b8c Clipboard is extended 2014-09-16 13:36:48 -07:00
Ben Ogle 1933488914 Buffered process classes are extended 2014-09-16 13:35:19 -07:00
Ben Ogle 6e7dae032d All dev tool methods are extended 2014-09-16 13:34:11 -07:00
Ben Ogle 88d0d291d4 Convert visibility in the messaging the user section 2014-09-16 13:31:53 -07:00
Ben Ogle 488b1819ae Convert visibility in the managing the window section 2014-09-16 13:31:18 -07:00
Ben Ogle b1df925d02 Convert visibility in metadata section 2014-09-16 13:30:47 -07:00
Ben Ogle dbf8094fdb Reorder the sections so public methods are closer to the top 2014-09-16 13:26:58 -07:00
Ben Ogle cf927e6405 Create Messaging the user + Deserializing sections 2014-09-16 13:23:09 -07:00
Ben Ogle 6a16a9b83f move Atom::open to the window management section 2014-09-16 13:22:21 -07:00
Ben Ogle ebb6ebca2a Move windowloadTime into metadata section 2014-09-16 13:21:35 -07:00
Ben Ogle 816bb9b38d Deserializers are private 2014-09-16 13:21:19 -07:00
Ben Ogle e260064df2 Add getLoadSettings to atom metadata section 2014-09-16 11:52:59 -07:00
Ben Ogle a3e4ccbb83 Create atom metadata section 2014-09-16 11:52:11 -07:00
Ben Ogle e84eba058a Move deprecated methods to the bottom of the file 2014-09-16 11:44:00 -07:00
Ben Ogle c25a04fd53 Move fullscreen stuff into the managing window section 2014-09-16 11:42:07 -07:00
Ben Ogle 9e68e47432 💄 2014-09-16 11:37:30 -07:00
Ben Ogle 53806d7d63 Managing the dev tool section 2014-09-16 11:37:21 -07:00
Ben Ogle c0dd53104a Make a managing the atom window section
de-public the get/setWindowDimensions in favor of 
the (get|set)(Size|Position)
2014-09-16 11:37:11 -07:00
Ben Ogle 39d7e12ebb Fix deprecation method calls 2014-09-16 11:35:14 -07:00
Ben Ogle 779619a4f2 Construction and destruction section 2014-09-16 10:58:36 -07:00
Ben Ogle b3ec8ed03f Make Atom::initialize private 2014-09-16 10:58:27 -07:00
Ben Ogle f84666943c Properties section 2014-09-16 10:58:08 -07:00
Ben Ogle 9eb51dfd0a Make Atom.loadOrCreate Private 2014-09-16 10:56:48 -07:00
Ben Ogle ac516102ca Atom is Essential 2014-09-16 10:56:26 -07:00
Ben Ogle 5b8e30580d Reorg Event Subscription section 2014-09-16 10:52:33 -07:00
Ben Ogle 44fd6cc335 Workspace is Essential 2014-09-16 10:51:34 -07:00
Ben Ogle e01d96862f Update docs in decoration 2014-09-16 10:51:34 -07:00
Ben Ogle d349ec55f9 Use new methods 2014-09-16 10:51:34 -07:00
Ben Ogle bbe69347ee Clean up the syntax scopes section 2014-09-16 10:51:34 -07:00
Ben Ogle 6270f2ff55 Add missing argument to docs 2014-09-16 10:51:33 -07:00
Ben Ogle 1ef2aa63d6 Clean up visibilities where I made an error 2014-09-16 10:51:33 -07:00
Ben Ogle ff188723cd Create a saving section 2014-09-16 10:51:33 -07:00
Ben Ogle b661cdd229 💄 2014-09-16 10:51:33 -07:00
Ben Ogle 499888a386 Reorg marker section 2014-09-16 10:51:33 -07:00
Ben Ogle 86bbf4276b Reorg the Decorations section 2014-09-16 10:51:33 -07:00
Ben Ogle 48d02cf934 Reorganize the Folds section 2014-09-16 10:51:33 -07:00
Ben Ogle 9dacdaf2ef Reorganize the Syntatic Queries section 2014-09-16 10:51:33 -07:00
Ben Ogle af184fe2ff Convert visibility on the grammars section 2014-09-16 10:51:33 -07:00
Ben Ogle d827d4ad34 Change visibility on the Editor Coordinates section 2014-09-16 10:51:33 -07:00
Ben Ogle 4238052dc3 Move text mutation transactions into the mutating text section 2014-09-16 10:51:33 -07:00
Ben Ogle 5790221c15 Reorg undo section 2014-09-16 10:51:32 -07:00
Ben Ogle 5f807df1b0 Reorganize the indentation section 2014-09-16 10:51:32 -07:00
Ben Ogle 30ced48d23 Reorganize Soft Wrap Behavior section 2014-09-16 10:51:32 -07:00
Ben Ogle d17c6e409f Reorganize Tab Behavior section 2014-09-16 10:51:32 -07:00
Ben Ogle 81165e0e41 Add docs for the Editor::scan methods 2014-09-16 10:51:32 -07:00
Ben Ogle 49f5817b87 Convert visibility of the removing text section 2014-09-16 10:51:32 -07:00
Ben Ogle 6b71ea1875 Convert visibility in the Inserting Text section 2014-09-16 10:51:32 -07:00
Ben Ogle 6287f90a39 Convert visibility in the Mutating text section 2014-09-16 10:51:32 -07:00
Ben Ogle 783c1dd449 Convert visibility in the mutating text section 2014-09-16 10:51:32 -07:00
Ben Ogle 719ab078cc Convert file details section to essential extended 2014-09-16 10:51:32 -07:00
Ben Ogle 2491090c91 Move Essential methods above the extended versions 2014-09-16 10:51:32 -07:00
Ben Ogle f12b70e3b7 Editor::onDidChangeScreenLines -> onDidChange 2014-09-16 10:51:32 -07:00
Ben Ogle 4a20f13162 Upgrade scandal to handle negate syntax
!*.coffee
2014-09-16 10:25:25 -07:00
Kevin Sawicki 73253d37bc Prepare 0.130 2014-09-16 10:19:32 -07:00
Kevin Sawicki 16c9c41978 Upgrade to tree-view@0.125 2014-09-16 10:02:45 -07:00
Kevin Sawicki c7ca3e66fd Prepare 0.129 2014-09-16 09:27:02 -07:00
Nathan Sobo eb97154c94 Merge remote-tracking branch 'origin/master' into ns-command-registry 2014-09-16 10:27:00 -06:00
Nathan Sobo 1f95d8069a Document CommandRegistry 2014-09-16 10:08:17 -06:00
Kevin Sawicki dc88f080a3 Upgrade to tree-view@0.124 2014-09-16 09:00:30 -07:00
Nathan Sobo a069f34ad6 Fix CommandRegistry::findCommands spec
Don’t assert against commands registered on the window with jQuery
2014-09-16 09:23:52 -06:00
Nathan Sobo 33ad0a9b93 Delegate ::onDidChangeActivePane and ::observeActivePane 2014-09-16 09:19:07 -06:00
Kevin Sawicki 5c77b06d2a Add Editor:onDidSave 2014-09-15 18:25:29 -07:00
Kevin Sawicki 82a906cce5 Add Workspace::onDidChangeActivePaneItem
Closes #3546
2014-09-15 16:39:53 -07:00
Kevin Sawicki 94e285611c getActiveItem -> getActivePaneItem 2014-09-15 16:31:01 -07:00
Nathan Sobo ebe116d724 Update parent view is-focused and mini classes on editor mount
Fixes #3526
2014-09-15 16:03:36 -06:00
Nathan Sobo 647f6c5b24 Upgrade keybinding resolver to fix deprecation warnings in specs 2014-09-15 15:44:17 -06:00
Nathan Sobo 01a3e0cfba Merge pull request #3545 from atom/ns-revert-soft-wrapped
Rename soft-wrapped back to soft-wrap
2014-09-15 14:49:10 -06:00
Nathan Sobo 3faf566a48 Rename editor:toggle-soft-wrapped back to editor:toggle-soft-wrap 2014-09-15 14:34:35 -06:00
Nathan Sobo a0edb92e16 Rename editor.softWrapped config option back to editor.softWrap 2014-09-15 14:34:35 -06:00
Kevin Sawicki 69480385e6 Upgrade to tree-view@0.123 2014-09-15 13:02:21 -07:00
Kevin Sawicki 804f290cd3 Memoize comment scope selector 2014-09-15 13:01:37 -07:00
Ben Ogle 274a36e263 Upgrade UI themes to fix tabs 2014-09-15 11:18:51 -07:00
Nathan Sobo 4a14580429 Merge pull request #3338 from atom/ns-change-ctrl-a-binding
Change ctrl-a binding to editor:move-to-first-character-of-line on Mac
2014-09-15 12:15:59 -06:00
Kevin Sawicki 17a6256483 Upgrade to find-and-replace@0.138 2014-09-15 11:10:35 -07:00
Kevin Sawicki 7d61330b9f Upgrade to tree-view@0.122 2014-09-15 11:07:49 -07:00
Kevin Sawicki 5e52357674 Upgrade to markdown-preview@0.102 2014-09-15 11:05:39 -07:00
Kevin Sawicki 6ee82d4937 Upgrade to tree-view@0.121 2014-09-15 10:56:01 -07:00
Kevin Sawicki 863362ffed 📝 Outdent ordered list 2014-09-15 08:51:10 -07:00
Kevin Sawicki cea7d89129 📝 🐧 Tweak Linux instructions 2014-09-15 08:50:16 -07:00
Kevin Sawicki 5e65339332 Merge pull request #3535 from Bengt/patch-1
Elaborate getting a current working copy.
2014-09-15 08:44:06 -07:00
Kevin Sawicki 8c2bcf3943 Catch and log deactivate errors
Closes #3538
2014-09-15 08:34:54 -07:00
Kevin Sawicki 10762d6440 Upgrade to language-gfm@0.50 2014-09-15 08:21:19 -07:00
Kevin Sawicki f872583c81 Upgrade to tree-view@0.120 2014-09-14 09:37:26 -07:00
Bengt Lüers ca8153b56b Elaborate getting a current working copy.
The `git checkout` step from #3098 got removed by some merge, so here it is again.
2014-09-14 15:15:52 +02:00
Kevin Sawicki 54c1dd5225 Upgrade to language-php@0.16 2014-09-12 15:10:04 -07:00
Kevin Sawicki d858c6c357 Merge pull request #3528 from atom/ks-add-debian-asset
Add Debian asset to releases
2014-09-12 13:45:47 -07:00
Kevin Sawicki 6d1d6de8ff Restore only uploading from master 2014-09-12 13:28:10 -07:00
Kevin Sawicki 97e7d24f43 Add missing task helpers require 2014-09-12 13:22:15 -07:00
Kevin Sawicki 1bfda1fc61 Copy .deb file to proper upload path 2014-09-12 13:22:15 -07:00
Kevin Sawicki b1a6772105 Don't include version in .deb asset name 2014-09-12 13:22:15 -07:00
Kevin Sawicki bf76a3f1e7 Only publish on Linux for now 2014-09-12 13:22:15 -07:00
Kevin Sawicki 8dcd454401 Remove token logging 2014-09-12 13:22:15 -07:00
Kevin Sawicki 3a2c155afc Log token 2014-09-12 13:22:15 -07:00
Kevin Sawicki e00ff30cd7 Extensions should be an array 2014-09-12 13:22:14 -07:00
Kevin Sawicki 38eda4ca14 Remove duplidate tasks in CI tasks array 2014-09-12 13:22:14 -07:00
Kevin Sawicki dc0bdef36c Don't run specs on Linux CI for now 2014-09-12 13:22:14 -07:00
Kevin Sawicki 9717d973a7 Upload .deb asset during publish 2014-09-12 13:22:14 -07:00
Kevin Sawicki 24206d45a7 Run mkdeb task on Linux CI 2014-09-12 13:22:14 -07:00
Kevin Sawicki a1e177c7dc Set ATOM_ACCESS_TOKEN 2014-09-12 13:22:14 -07:00
Kevin Sawicki 735d1a912e Log debug output 2014-09-12 13:22:14 -07:00
Kevin Sawicki e060d0b562 Add initial Linux CI build script 2014-09-12 13:22:14 -07:00
Kevin Sawicki 68e11fed11 Add .node-version file with 0.10.21 2014-09-12 13:22:14 -07:00
Kevin Sawicki c72ce45820 Log installed node version 2014-09-12 13:22:14 -07:00
Kevin Sawicki 04cc11fa81 Don't read env var files on Linux 2014-09-12 13:22:14 -07:00
Kevin Sawicki f14ad99558 Remove linux check 2014-09-12 13:22:14 -07:00
Kevin Sawicki a060eff478 Use skinny arrows 2014-09-12 11:23:15 -07:00
Ben Ogle 1c57a8b0cd Update event-kit with better organization in docs 2014-09-12 11:19:37 -07:00
Ben Ogle 7c1cab7789 Don’t recurse into dependencies of dependencies.
We always want the top level module!
2014-09-12 10:49:53 -07:00
Kevin Sawicki 591d9068d8 Upgrade to tree-view@0.119 2014-09-12 10:43:15 -07:00
Kevin Sawicki c24bf5bd0c Upgrade to find-and-replace@0.137 2014-09-12 10:34:59 -07:00
Kevin Sawicki 050a79e5b9 Upgrade to find-and-replace@0.136 2014-09-12 10:29:01 -07:00
Kevin Sawicki ee8b01e46a Upgrade to find-and-replace@0.135 2014-09-12 10:10:04 -07:00
Kevin Sawicki ceb48b7f4f Upgrade to tree-view@0.118 2014-09-12 09:51:01 -07:00
Kevin Sawicki 61e01c3984 Upgrade to language-ruby@0.37 2014-09-12 09:11:42 -07:00
Cheng Zhao 901ba72557 Show the open dialog as child window on Windows and Linux.
On Mac the open dialog is still showed as independent dialog, this matches
most native apps' behavior.

Fixes #3401.
2014-09-12 21:43:01 +08:00
Kevin Sawicki 8cffb8006a Upgrade to language-gfm@0.49 2014-09-11 21:41:15 -07:00
Ben Ogle 0643aa66c9 Upgrade atom-keymap for new docs organization 2014-09-11 18:23:39 -07:00
Ben Ogle d0033b2d40 Upgrade tello for bugfix 2014-09-11 18:23:39 -07:00
Kevin Sawicki 8847b35931 Upgrade to tree-view@0.117 2014-09-11 18:11:16 -07:00
Kevin Sawicki 9a534f0b6d Upgrade to tree-view@0.116 2014-09-11 17:35:07 -07:00
Kevin Sawicki 137b926f54 Upgrade to archive-view@0.37 2014-09-11 17:15:49 -07:00
Ben Ogle 24d1a45fd9 Upgrade to pathwather with better doc organization 2014-09-11 16:29:52 -07:00
Kevin Sawicki ea6f124724 Merge pull request #3519 from atom/ks-remeasure-after-themes-load
Wait for themes to load before measuring
2014-09-11 16:22:07 -07:00
Kevin Sawicki c161e93b96 💄 Add ? 2014-09-11 16:08:04 -07:00
Kevin Sawicki e6252546c4 Set initialLoadComplete to true in specs 2014-09-11 15:49:44 -07:00
Kevin Sawicki 4a1f048d52 Refresh scrollbars when no stylesheet is specified 2014-09-11 15:44:30 -07:00
Kevin Sawicki dc5eb95a39 Wait for initial stylesheet load to complete
Instead of measuring on each stylesheet load at startup,
wait for the initial load of all the stylesheets to complete
and then do the necessary measurments.
2014-09-11 15:32:02 -07:00
Kevin Sawicki 844fd29dad Remove unused param 2014-09-11 15:32:02 -07:00
Kevin Sawicki 7b1a38bf8b Upgrade to wrap-guide@0.22 2014-09-11 15:31:47 -07:00
Ben Ogle 54ef5acdc6 Upgrade first-mate with new docs 2014-09-11 14:59:24 -07:00
Ben Ogle c8ccf1e0d7 Merge pull request #3518 from atom/bo-font-settings-in-model
Deprecate font-size, font-family, line-height, invisibles, indent guide methods on EditorView
2014-09-11 14:21:34 -07:00
Kevin Sawicki aee496346b Prepare 0.128 2014-09-11 14:10:44 -07:00
Ben Ogle 6a2c161bf2 Deprecate setShowInvisibles 2014-09-11 14:10:33 -07:00
Ben Ogle 5ef31e00a2 Deprecate EditorView::setShowIndentGuide 2014-09-11 14:10:17 -07:00
Ben Ogle f8ba40bcfe Deprecate font-size, font-family, line-height methods on EditorView. 2014-09-11 14:00:34 -07:00
Ben Ogle 834176f7b7 Merge pull request #3514 from atom/bo-remove-method-deprecations
Remove event deprecations from core
2014-09-11 13:45:26 -07:00
Ben Ogle 3f3284a8db Move the deprecations 2014-09-11 13:33:50 -07:00
Kevin Sawicki ff308d366c Upgrade to language-ruby@0.36 2014-09-11 13:27:47 -07:00
Nathan Sobo 98a51005c3 Upgrade command-palette to use atom.commands global 2014-09-11 14:25:53 -06:00
Nathan Sobo fb6a184b0e Include commands registered via jQuery in CommandRegistry::findCommands 2014-09-11 14:18:57 -06:00
Nathan Sobo 8b7b946429 Set root node to workspace view when it’s constructed
Makes it easier to deal with specs
2014-09-11 14:18:57 -06:00
Nathan Sobo e4264035d8 fixup! Clear atom.commands after each spec 2014-09-11 14:18:00 -06:00
Nathan Sobo 8f9cf3c790 Set the atom.commands root node to document.body in beforeEach 2014-09-11 14:17:45 -06:00
Nathan Sobo 99cf8fabc0 Clear atom.commands after each spec 2014-09-11 14:13:48 -06:00
Nathan Sobo 3e0e19d51b Add CommandRegistry::findCommands 2014-09-11 13:48:35 -06:00
Nathan Sobo 155fb675ec 💄 group dispatch specs 2014-09-11 13:48:35 -06:00
Nathan Sobo ab8ac369df Move a few workspace commands to the command registry 2014-09-11 13:48:35 -06:00
Nathan Sobo a348ecf034 Allow CommandRegistry::rootNode to be reassigned 2014-09-11 13:48:35 -06:00
Nathan Sobo dac127c30b Assign atom.commands to a CommandRegistry instance 2014-09-11 13:48:35 -06:00
Nathan Sobo 7580d64d2e Allow CommandRegistry::rootNode to be assigned after construction 2014-09-11 13:48:35 -06:00
Nathan Sobo 43d3082d4e Allow multiple commands to be registered by passing an object 2014-09-11 13:48:35 -06:00
Nathan Sobo aee33fc126 Pass selector first to CommandRegistry::add 2014-09-11 13:48:35 -06:00
Nathan Sobo 4de0865d28 Allow listeners to be removed via a Disposable returned from ::add 2014-09-11 13:48:34 -06:00
Nathan Sobo fe27ebec1b Handle .stopImmediatePropagation() being called on command events 2014-09-11 13:48:34 -06:00
Nathan Sobo fbaf956e1f Handle .stopPropagation() being called on command events 2014-09-11 13:48:34 -06:00
Nathan Sobo 5eb22520f1 Order multiple matching listeners by selector specificity 2014-09-11 13:48:34 -06:00
Nathan Sobo a075aa2b07 Perform synthetic bubbling through event target ancestors 2014-09-11 13:48:34 -06:00
Nathan Sobo decc983420 Start on CommandRegistry 2014-09-11 13:48:34 -06:00
Ben Ogle 04c0824822 Fix / clean up specs 2014-09-11 11:28:21 -07:00
Ben Ogle f38fb2a924 nof 2014-09-11 11:11:15 -07:00
Nathan Sobo 04caea9bb0 Upgrade autosave to suppress autosave when opening menus inside editor 2014-09-11 11:56:36 -06:00
Ben Ogle f39114a95c Subscribe to items via event methods.
Add deprecation warnings when they don’t return a disposable
2014-09-11 10:48:03 -07:00
Nathan Sobo 435e081402 Upgrade autosave to autosave all items on window blur 2014-09-11 11:20:19 -06:00
Nathan Sobo 36aa3834d3 Only call ::checkForVisibilityChange on editor attachment, not ::pollDOM
I’m pretty sure ::pollDOM is subsumed by ::checkForVisibilityChange
because there’s no reason the editor would be considered visible prior
to being attached.
2014-09-11 10:38:36 -06:00
Nathan Sobo 50a751b8e6 Merge pull request #3517 from smashwilson/ensure-measurements
Force visibility-change checking in EditorView's afterAttach method
2014-09-11 10:35:23 -06:00
Ash Wilson 40570c0b99 Force visibility-change checking in EditorView.
When an `EditorView` becomes attached, if hardware acceleration is enabled,
the call to `pollDOM` is a no-op because there's already a refresh pending.
This can cause problems, because then the initial measurements don't happen
and (for example) the lineHeight is left as null - it'll be set on the next
rendering, but not before subscribers to `workspaceView.eachEditorView` are
notified.
2014-09-11 11:14:41 -04:00
Ben Ogle 025c6111b3 Move global editor stylesheet updating into the ThemeManager 2014-09-10 18:01:45 -07:00
Ben Ogle 667315aff5 Add ThemeManager::onDidUpdateStylesheet 2014-09-10 18:01:27 -07:00
Ben Ogle c1f8065caf Use the new split*() methods on Pane model in WorkspaceView specs 2014-09-10 17:41:38 -07:00
Ben Ogle 70e1d14f96 Add KeymapManager::onDidLoadBundledKeymaps 2014-09-10 17:28:47 -07:00
Ben Ogle 7625e5352d Use event methods in EditorComponent 2014-09-10 17:28:26 -07:00
Ben Ogle 6e3c945fa2 Use event methods for theme subscriptions 2014-09-10 17:26:08 -07:00
Ben Ogle f8b17b6b3c Add Returns line to all the event subscription methods 2014-09-10 17:07:21 -07:00
Nathan Sobo d55f5cba78 Upgrade first-mate for event subscription methods 2014-09-10 17:24:55 -06:00
Nathan Sobo f0a19e3f67 Upgrade atom-keymap for event subscription methods 2014-09-10 16:41:05 -06:00
Ben Ogle 465c13e292 Update packages that use atomdoc to force update of atomdoc 2014-09-10 15:36:48 -07:00
Ben Ogle be1d4ee5dc Use explicit versions of donna and tello in build package.json 2014-09-10 14:37:40 -07:00
Nathan Sobo 238cf60882 Upgrade pathwatcher for explicit event subscription methods 2014-09-10 14:58:21 -06:00
Ben Ogle 60a3cebfab Fix section name in git class 2014-09-10 12:13:04 -07:00
Ben Ogle 8f8165e289 Fix doc strings in Atom class 2014-09-10 12:12:36 -07:00
Ben Ogle d3b3fdefc9 Merge pull request #3507 from atom/bo-rename-events
Rename the rest of the internal events to the onDid* pattern
2014-09-10 12:11:26 -07:00
Ben Ogle 49937b2956 Revert "Add Project::onDidChangePath()"
This reverts commit ed4acb02d8.

Conflicts:
	src/project.coffee
2014-09-10 11:56:38 -07:00
Ben Ogle 40b32930cf Revert "Add Project::onDidCreateBuffer"
This reverts commit 4070e5fb25.
2014-09-10 11:55:41 -07:00
Ben Ogle 61fa1c4230 Revert "Add Project::observeBuffers"
This reverts commit b6fe72ef9e.

Conflicts:
	src/project.coffee
2014-09-10 11:55:26 -07:00
Ben Ogle 6a0a842de4 Update section comments 2014-09-10 11:52:57 -07:00
Kevin Sawicki c141448e9f Wrap HTML elements in $ so matchers still work 2014-09-10 11:19:05 -07:00
Kevin Sawicki 61166bf365 Don't track focus for spec windows 2014-09-10 11:14:08 -07:00
Kevin Sawicki 9c24e5a23d Prepare 0.127 2014-09-10 11:02:57 -07:00
Kevin Sawicki 883f7e1f5a Use cross-platform path in specs 2014-09-10 10:22:48 -07:00
Kevin Sawicki d9b1b7b399 Don't dump symbols on Windows CI for now
Currently errors and isn't uploaded yet anyway as a release asset
2014-09-10 10:08:26 -07:00
Kevin Sawicki d1bdda5b3e Upgrade to language-html@0.26 2014-09-10 09:40:55 -07:00
Nathan Sobo a3f3b7e032 Upgrade text-buffer to fix null exception 2014-09-10 09:45:06 -06:00
Kevin Sawicki 3228de7ead Merge pull request #3508 from envygeeks/patch-2
Proc requires super user permissions on Linux.
2014-09-09 18:45:50 -07:00
Jordon Bedwell 5a64b09924 Proc requires super user permissions on Linux. 2014-09-09 20:36:40 -05:00
Kevin Sawicki b0c17aa98f 📝 Correct misspellings 2014-09-09 18:32:37 -07:00
Kevin Sawicki 9f5f4f2c10 Merge pull request #3499 from envygeeks/patch-1
Add alternatives alternative to symlinks.
2014-09-09 18:31:22 -07:00
Jordon Bedwell 335339ef61 Change language and make the command one line. 2014-09-09 20:20:39 -05:00
Kevin Sawicki 291bf7fe08 Upgrade to pathwatcher 2.0.12 2014-09-09 16:31:00 -07:00
Kevin Sawicki 40eaf69ab0 Upgrade to metrics@0.34 2014-09-09 16:25:44 -07:00
Kevin Sawicki 55ac855de1 Upgrade to pathwatcher 2.0.11 2014-09-09 16:12:20 -07:00
Ben Ogle 2e219f288d Add sections for docs clarity 2014-09-09 15:55:47 -07:00
Ben Ogle 09fbd46869 Remove event docs 2014-09-09 15:43:35 -07:00
Ben Ogle 10ceb34426 Fix docs 2014-09-09 15:43:12 -07:00
Ben Ogle 5ba5215f5d Add event subscription methods to ThemeManager 2014-09-09 15:35:00 -07:00
Ben Ogle 3bf348e51f Add ThemeManager::onDidReloadAll 2014-09-09 15:24:55 -07:00
Ben Ogle 0afd8a1392 Add Package::onDidDeactivate 2014-09-09 15:09:18 -07:00
Ben Ogle 55b5debd7f Add PackageManager::onDidLoadAll 2014-09-09 15:04:13 -07:00
Ben Ogle 229277f764 Add PackageManager::onDidActivateAll() 2014-09-09 15:03:45 -07:00
Ben Ogle af1b0b5736 Fix Doc String 2014-09-09 14:45:41 -07:00
Ben Ogle ae4f92cc52 Add onDidChangeStatuses 2014-09-09 14:45:31 -07:00
Kevin Sawicki 66b27ad52a Upgrade to snippets@0.52 2014-09-09 14:30:52 -07:00
Ben Ogle dddd17c11b Fix observeBuffers 2014-09-09 14:29:14 -07:00
Ben Ogle 05f54d427d Add Git::onDidChangeStatus 2014-09-09 14:28:30 -07:00
Ben Ogle ffbb18a0f8 Remove event comments, add method section comment 2014-09-09 14:16:10 -07:00
Ben Ogle b6fe72ef9e Add Project::observeBuffers 2014-09-09 14:13:26 -07:00
Ben Ogle 4070e5fb25 Add Project::onDidCreateBuffer 2014-09-09 14:12:49 -07:00
Ben Ogle ed4acb02d8 Add Project::onDidChangePath() 2014-09-09 13:58:23 -07:00
Ben Ogle ab96e5b5fd 💄 Fix doc string 2014-09-09 13:58:01 -07:00
Ben Ogle f357f694b3 Merge pull request #3456 from atom/ns-editor-event-methods
Add event subscription methods for Editor and associated classes
2014-09-09 13:40:45 -07:00
Ben Ogle 2a02375c4d Move the Decoration events to an events section 2014-09-09 12:31:01 -07:00
Ben Ogle e452b88fec Add sections for events 2014-09-09 12:30:43 -07:00
Ben Ogle 0f83fe54f9 Add and use Editor::observeSelections() and ::observeCursors() 2014-09-09 12:08:43 -07:00
Ben Ogle 3e5666f183 use getPaneView rather than getPane 2014-09-09 12:08:12 -07:00
Nathan Sobo 260f72d2b5 Merge pull request #3495 from atom/atom-shell-v0.16.0
Upgrade to Chrome 37
2014-09-09 12:43:42 -06:00
Nathan Sobo 84deefb6b1 Upgrade atom-shell to incorporate changes in 92.2 and 92.3 2014-09-09 12:31:48 -06:00
Nathan Sobo 5afceb3951 Merge remote-tracking branch 'origin/master' into atom-shell-v0.16.0
Conflicts:
	apm/package.json
2014-09-09 12:05:54 -06:00
Ben Ogle 72be16736c isDestroyed -> destroyed 2014-09-09 10:58:12 -07:00
Ben Ogle 789d9c8eff 📝 Selection event methods 2014-09-09 10:56:44 -07:00
Ben Ogle 858ac5bf79 onDidChangeSelectionScreenRange -> onDidChangeSelectionRange
for consistency
2014-09-09 10:54:57 -07:00
Ben Ogle 9db804b413 Doc events in Cursor 2014-09-09 10:51:46 -07:00
Ben Ogle c7525e8cff 💄 doc strings 2014-09-09 10:51:35 -07:00
Ben Ogle 7198a919bf onDidMoveCursor -> onDidChangeCursorPosition 2014-09-09 10:43:25 -07:00
Ben Ogle aebdfb4cf6 Event docs 2014-09-09 10:39:41 -07:00
Kevin Sawicki 7b1f8cc7da Set project path for window:open-path files
The project path will now be set to the parent directory if it isn't
already set when a file path is specified via the window:open-path
event.

Closes atom/tree-view#217
2014-09-09 09:55:31 -07:00
Nathan Sobo 17aa6f958c Upgrade autocomplete to fix specs 2014-09-09 10:18:19 -06:00
Cheng Zhao 3e10f491b4 Disable subpixel font scaling. 2014-09-09 21:54:32 +08:00
Cheng Zhao 3487ab9b11 Upgrade to atom-shell@0.16.2 2014-09-09 20:44:49 +08:00
Kevin Sawicki f6545d4002 Check if name matches before resolving path
Path resolution hits the filesystem so check for a name
match first.
2014-09-08 17:27:34 -07:00
Kevin Sawicki 408cac4632 🐎 Use DOM APIs to find editor views 2014-09-08 17:10:30 -07:00
Kevin Sawicki bb5a440651 :racehorse Upgrade to atom-keymap@2.0.6 2014-09-08 16:56:10 -07:00
Ben Ogle 5883e27c60 Make Editor::onDidChangeGrammar emit from Editor
Seems like the initial implementation was to handle the event, unfold 
all then, re-emit the grammar-changed event.
2014-09-08 16:32:43 -07:00
Ben Ogle 1d073173d4 Add Editor::onDidChangeSelectedScreenRange 2014-09-08 16:25:35 -07:00
Ben Ogle 601b311496 Add Editor::onDidMoveCursor 2014-09-08 16:20:54 -07:00
Ben Ogle d4835e1d8e Add Editor:onScrollTopChanged and Editor:onScrollLeftChanged 2014-09-08 16:17:06 -07:00
Ben Ogle 6f9f087e11 💄 consistency 2014-09-08 16:05:31 -07:00
Ben Ogle b6a9e1b576 Fix deprecation warning 2014-09-08 16:05:21 -07:00
Ben Ogle efea16848a Add deprecation warnings for all the other converted events 2014-09-08 16:05:07 -07:00
Ben Ogle 8aa1784c4a Add Editor::onDidChangeScreenLines 2014-09-08 16:04:43 -07:00
Nathan Sobo 2d3ae1b44d Upgrade event-kit for api docs 2014-09-08 17:00:46 -06:00
Jordon Bedwell efc730dc2f Add alternatives alternative to symlinks. 2014-09-08 14:39:47 -05:00
Kevin Sawicki 70dd3675e6 Upgrade to minidump 0.8 2014-09-08 12:05:25 -07:00
Kevin Sawicki 30ae93b9d9 Upgrade to apm 0.92.3
Refs #3492
2014-09-08 10:12:31 -07:00
Kevin Sawicki aa5a094cbe Merge pull request #3470 from atom/ks-no-jquery-to-apply-stylesheets
Use DOM APIs to apply stylesheets
2014-09-08 10:09:06 -07:00
Kevin Sawicki ab75f3122f 💄 Use proper Less 2014-09-08 09:45:24 -07:00
Kevin Sawicki 359491fc3f Remove nulled variable 2014-09-08 09:40:06 -07:00
Kevin Sawicki 444eb0e5e5 💄 e -> error 2014-09-08 09:37:39 -07:00
Kevin Sawicki 522d446366 📝 Emit -> Emitted 2014-09-08 09:35:05 -07:00
Kevin Sawicki f8949adf38 💄 Sort requires 2014-09-08 09:34:31 -07:00
Kevin Sawicki 01d62653f2 Remove unused require 2014-09-08 09:33:51 -07:00
Kevin Sawicki 35a48f0cfb Update specs to expect an element 2014-09-08 09:33:51 -07:00
Kevin Sawicki f7103bbed6 Store sheet before it goes away 2014-09-08 09:33:51 -07:00
Kevin Sawicki 7e6b7ada54 Preserve ordering within type class 2014-09-08 09:33:51 -07:00
Kevin Sawicki 5e2f8a3ae3 🐎 Use DOM APIs to apply stylesheets
Previously jQuery was used, but using the DOM APIs directly
takes 1/3 of the time.
2014-09-08 09:33:51 -07:00
Kevin Sawicki 4bda13ec74 Merge pull request #3453 from atom/ks-lower-browser-process-startup-time
Lower browser process startup time
2014-09-08 09:32:48 -07:00
Kevin Sawicki 42f3605465 finish-launching -> ready 2014-09-08 09:22:46 -07:00
Kevin Sawicki e7e4196fa6 Use fs.statSyncNoException 2014-09-08 09:22:45 -07:00
Kevin Sawicki 68801aacdb Don't require shell until it is used 2014-09-08 09:22:45 -07:00
Kevin Sawicki 13956edfb5 Always assign to autoUpdater 2014-09-08 09:22:45 -07:00
Kevin Sawicki 3a7564b59e Start auto updater on the next tick
This prevents it from adding time to first window startup
2014-09-08 09:22:45 -07:00
Kevin Sawicki 4e0928600f 💄 2014-09-08 09:22:45 -07:00
Kevin Sawicki 417134c799 Require dialog when used 2014-09-08 09:22:45 -07:00
Kevin Sawicki b2638c8bad 💄 2014-09-08 09:22:45 -07:00
Kevin Sawicki 27bf096fbc Remove require that is now inlined where used 2014-09-08 09:22:44 -07:00
Kevin Sawicki 4fa6f631a9 Defer ContextMenu require until requested 2014-09-08 09:22:44 -07:00
Kevin Sawicki 6e7968861d Use fs instead of fs-plus
Since only an is file check is performed fs is sufficient
2014-09-08 09:22:44 -07:00
Kevin Sawicki fc59d9c503 Require https on a next tick
This require is heavy in node for some reason so only
require it on Windows since it is only used there and only
after a next tick so that it doesn't affect startup
2014-09-08 09:22:44 -07:00
Kevin Sawicki 163b52efb0 CoffeeScript.compile returns a string 2014-09-08 09:22:44 -07:00
Kevin Sawicki d4ed8a0b73 Defer requiring CoffeeScript
Requiring it up front adds about 30-40ms to startup.
2014-09-08 09:22:44 -07:00
Kevin Sawicki d7106a6b4c Make browser process benchmark executable 2014-09-08 09:22:43 -07:00
Kevin Sawicki 4b867ddc7a Properly delete socket file in benchmark 2014-09-08 09:22:43 -07:00
Kevin Sawicki b5dfaff426 Remove unused requires from main.coffee 2014-09-08 09:22:43 -07:00
Kevin Sawicki 7eba55d009 Add initial browser process startup benchmark 2014-09-08 09:22:43 -07:00
alandarev abbb21bf47 🐧 Add Category 'Development' to linux desktop file
Closes #2827
Closes #3482
Closes #3488
2014-09-08 08:37:50 -07:00
Kevin Sawicki ff4d4f047f Merge pull request #3472 from pinak222/master
🐧 Add MimeType text/plain to .desktop file
2014-09-08 08:34:52 -07:00
Kevin Sawicki 9e21ea39bd Upgrade to language-xml@0.20 2014-09-08 08:33:48 -07:00
Ivan Žužak 11dbee0290 Merge pull request #3468 from atom/iz-update-keymap-instructions
Explain capital letters in keystrokes in default keymap.cson comments
2014-09-08 15:21:46 +02:00
Cheng Zhao de4936efc8 Upgrade to apm@0.93.1 2014-09-08 18:27:24 +08:00
Cheng Zhao 846d81abf5 Upgrade to atom-shell@0.16.1 2014-09-08 18:19:59 +08:00
Cheng Zhao a8e4638612 🍎 Add "Services" menu, fixes #3204 2014-09-08 14:49:25 +08:00
Cheng Zhao 4134f5efe4 Upgrade to apm@0.93.0 2014-09-07 10:26:44 +08:00
Cheng Zhao 1c5acc059e Upgrade to atom-shell@0.16.0 2014-09-07 10:24:35 +08:00
pinak222 c01a24f293 Add MimeType text/plain to .desktop file
This adds Atom in open with menu in KDE (possibly other DE's) for text files therefore providing better integration.
2014-09-06 10:59:01 +05:30
Kevin Sawicki 571ce5bddd Upgrade to tree-view@0.115 2014-09-05 18:33:09 -07:00
Kevin Sawicki 5237e687ee 🐧 Add separator after preference items
Closes #3471
2014-09-05 18:16:12 -07:00
Kevin Sawicki fe74dfdf4e Upgrade to apm 0.92.1 2014-09-05 17:57:46 -07:00
Ben Ogle 250c21f00a Deprecate all events from ::on 2014-09-05 17:26:41 -07:00
Ben Ogle e6dbea09fe Add onDidCreateMarker and onDidUpdateMarkers 2014-09-05 17:26:14 -07:00
Ben Ogle 47ef54a072 Subscribe directly to the decoration destroy for removal 2014-09-05 16:53:35 -07:00
Ben Ogle 86e9778adb Remove the decoration changed event 2014-09-05 16:51:26 -07:00
Ben Ogle aeffef30c6 Directly subscribe to the decorations in EditorComponent 2014-09-05 16:49:30 -07:00
Ben Ogle 7ae25d34e7 Decoration Params -> Properties 2014-09-05 16:20:42 -07:00
Ben Ogle e6e6028683 Deprecate decoration events 2014-09-05 15:14:27 -07:00
Ben Ogle f3e8f11d07 Use DisplayBuffer::onDidChangeSoftWrapped in Editor 2014-09-05 13:42:11 -07:00
Ben Ogle 6e8a626de2 Add ::onDidChangeSoftWrapped to DisplayBuffer and Editor 2014-09-05 13:41:46 -07:00
Ben Ogle 21e4d8a064 Add DisplayBuffer::onDidChange 2014-09-05 13:30:59 -07:00
Ivan Žužak 733e06fa8c Use shift in the example rather than explaining the difference 2014-09-05 22:24:42 +02:00
Ben Ogle db84b7952c fix another linter error 2014-09-05 12:44:56 -07:00
Ben Ogle 557562d8c8 Fix linter error 2014-09-05 12:42:33 -07:00
Ivan Zuzak b1fdb48e9e Link to relevant docs in keymap.cson file 2014-09-05 21:40:54 +02:00
Ben Ogle 0a920b18d7 Update TokenizedBUffer::on deprecations 2014-09-05 12:40:33 -07:00
Ben Ogle 289b22c782 Use event methods in TokenizedBuffer spec 2014-09-05 12:40:14 -07:00
Ivan Zuzak 6d498aad3b Explain capital letters in keystrokes 2014-09-05 21:40:11 +02:00
Ben Ogle 53fbfb8b27 Merge decoration-changed and decoration-updated
Only emit the decorations from the events
2014-09-05 12:35:52 -07:00
Ben Ogle a2adbff3e9 Add TokenizedBuffer::onDidTokenize 2014-09-05 12:33:28 -07:00
Ben Ogle 48a68d87f5 Add TextBuffer::onDidChange 2014-09-05 12:26:54 -07:00
Ben Ogle bcc6adff4f No longer need this as the event method passes it through 2014-09-05 12:26:06 -07:00
Ben Ogle 9435f852dd Use new decoration updated event method 2014-09-05 12:25:14 -07:00
Ben Ogle 569c403d56 Update the events on decorations 2014-09-05 12:08:35 -07:00
Nathan Sobo 6ad9531e5c Add Selection::onDidChangeRange and ::onDidDestroy and deprecate ::on 2014-09-05 11:39:34 -07:00
Nathan Sobo 56687027b6 Add Cursor::onDidChangePosition and ::onDidDestroy and deprecate ::on 2014-09-05 11:39:34 -07:00
Nathan Sobo 6bd8702421 Deprecate DisplayBufferMarker::on 2014-09-05 11:39:34 -07:00
Nathan Sobo c69b5fc0a0 Remove specs for ::onDidMoveCursor, which was removed 2014-09-05 11:39:33 -07:00
Nathan Sobo 1131b33a83 Add DisplayBufferMarker::onDidChange and ::onDidDestroy 2014-09-05 11:39:33 -07:00
Nathan Sobo 651eb78315 Add Editor::onDidAdd/RemoveSelection
Also update EditorComponent to use the new ::onDidAddSelection method.
2014-09-05 11:39:33 -07:00
Nathan Sobo 3e77b9b7c0 Eliminate Editor::onDidMoveCursor
If you want to know if a cursor moved, subscribe to the cursor.
2014-09-05 11:39:33 -07:00
Nathan Sobo e77b4a54dd Add Editor::onDidRemoveCursor 2014-09-05 11:39:33 -07:00
Nathan Sobo 3b6e40fbd8 Add Editor::onDidAddCursor 2014-09-05 11:39:33 -07:00
Nathan Sobo 161edfd15a Remove ‘cursors-moved’ event
It event was not document only being used in EditorComponent. Due to
our batching strategy, it’s fine to respond to individual
::onDidMoveCursor events.
2014-09-05 11:39:33 -07:00
Nathan Sobo 2a81687d38 Add Editor::onDidMoveCursor 2014-09-05 11:39:33 -07:00
Nathan Sobo 05ea381c0a Add Editor::onWill/DidInsertText 2014-09-05 11:39:33 -07:00
Nathan Sobo 63c9da02f6 Add Editor::onDidConflict 2014-09-05 11:39:33 -07:00
Nathan Sobo 5a02303b58 Add Editor::onDidStopChanging which delegates to TextBuffer 2014-09-05 11:39:33 -07:00
Nathan Sobo 1c95a55740 Add ::onDidChangeGrammar to Editor, DisplayBuffer, and TokenizedBuffer 2014-09-05 11:39:33 -07:00
Nathan Sobo 3e260eea56 Add Editor::onDidChangeSoftWrapped 2014-09-05 11:39:33 -07:00
Nathan Sobo 965afc2c37 Rename softWrap to softWrapped
Our new pattern for booleans is to have ::set and ::is, and that means
the property name needs to be in passive voice for ::is to make sense.
This is in preparation for adding a new change observation method.

* ::setSoftWrapped
* ::isSoftWrapped
* ::toggleSoftWrapped
2014-09-05 11:39:33 -07:00
Nathan Sobo d15d1572ef Add Editor::onDidChangeModified 2014-09-05 11:36:40 -07:00
Nathan Sobo 133f3f45ab Add Editor::onDidChangePath 2014-09-05 11:36:40 -07:00
Nathan Sobo b731f7cbdc Add Editor::onDidChangeTitle 2014-09-05 11:36:40 -07:00
Ben Ogle 8f6053c53f Upgrade bracket matcher to use new apis
It was really noisy with deprecations
2014-09-05 11:31:40 -07:00
Kevin Sawicki 0c749537a1 Prepare 0.126 2014-09-05 09:39:06 -07:00
Nathan Sobo 7a0a808af1 Change ctrl-a binding to editor:move-to-first-character-of-line
Considering that the entire Atom core team has ctrl-a bound to move to
the first character and it's also the the default behavior of Sublime,
this seems like a more sensible and useful default option even though
it deviates from text editing norms on OS X.
2014-08-19 12:14:16 -06:00
89 arquivos alterados com 5158 adições e 3205 exclusões
+1
Ver Arquivo
@@ -0,0 +1 @@
v0.10.21
+11
Ver Arquivo
@@ -25,6 +25,17 @@ You can also download a `.zip` file from the [releases page](https://github.com/
The Windows version does not currently automatically update so you will need to
manually upgrade to future releases by re-downloading the `.zip` file.
### Debian Linux (Ubuntu)
Currently only a 64-bit version is available.
1. Download `atom-amd64.deb` from the [Atom releases page](https://github.com/atom/atom/releases/latest).
2. Run `sudo dpkg --install atom-amd64.deb` on the downloaded package.
3. Launch Atom using the installed `atom` command.
The Linux version does not currently automatically update so you will need to
repeat these steps to upgrade to future releases.
## Building
* [Linux](docs/build-instructions/linux.md)
+1 -1
Ver Arquivo
@@ -6,6 +6,6 @@
"url": "https://github.com/atom/atom.git"
},
"dependencies": {
"atom-package-manager": "0.92.0"
"atom-package-manager": "0.96.0"
}
}
+1 -1
Ver Arquivo
@@ -50,7 +50,7 @@ if [ $OS == 'Mac' ]; then
# If ATOM_PATH isn't a executable file, use spotlight to search for Atom
if [ ! -x "$ATOM_PATH/$ATOM_APP_NAME" ]; then
ATOM_PATH=$(mdfind "kMDItemCFBundleIdentifier == 'com.github.atom'" | head -1 | xargs dirname)
ATOM_PATH=$(mdfind "kMDItemCFBundleIdentifier == 'com.github.atom'" | grep -v ShipIt | head -1 | xargs dirname)
fi
# Exit if Atom can't be found
+56
Ver Arquivo
@@ -0,0 +1,56 @@
#!/usr/bin/env coffee
{spawn, exec} = require 'child_process'
fs = require 'fs'
os = require 'os'
path = require 'path'
_ = require 'underscore-plus'
temp = require 'temp'
directoryToOpen = temp.mkdirSync('browser-process-startup-')
socketPath = path.join(os.tmpdir(), 'atom.sock')
numberOfRuns = 10
deleteSocketFile = ->
try
fs.unlinkSync(socketPath) if fs.existsSync(socketPath)
catch error
console.error(error)
launchAtom = (callback) ->
deleteSocketFile()
cmd = 'atom'
args = ['--safe', '--new-window', '--foreground', directoryToOpen]
atomProcess = spawn(cmd, args)
output = ''
startupTimes = []
dataListener = (data) ->
output += data
if match = /App load time: (\d+)/.exec(output)
startupTime = parseInt(match[1])
atomProcess.stderr.removeListener 'data', dataListener
atomProcess.kill()
exec 'pkill -9 Atom', (error) ->
console.error(error) if error?
callback(startupTime)
atomProcess.stderr.on 'data', dataListener
startupTimes = []
collector = (startupTime) ->
startupTimes.push(startupTime)
if startupTimes.length < numberOfRuns
launchAtom(collector)
else
maxTime = _.max(startupTimes)
minTime = _.min(startupTimes)
totalTime = startupTimes.reduce (previousValue=0, currentValue) -> previousValue + currentValue
console.log "Startup Runs: #{startupTimes.length}"
console.log "First run time: #{startupTimes[0]}ms"
console.log "Max time: #{maxTime}ms"
console.log "Min time: #{minTime}ms"
console.log "Average time: #{Math.round(totalTime/startupTimes.length)}ms"
launchAtom(collector)
+8 -1
Ver Arquivo
@@ -225,9 +225,16 @@ module.exports = (grunt) ->
grunt.registerTask('compile', ['coffee', 'prebuild-less', 'cson', 'peg'])
grunt.registerTask('lint', ['coffeelint', 'csslint', 'lesslint'])
grunt.registerTask('test', ['shell:kill-atom', 'run-specs'])
grunt.registerTask('ci', ['output-disk-space', 'download-atom-shell', 'build', 'dump-symbols', 'set-version', 'check-licenses', 'lint', 'test', 'codesign', 'publish-build'])
grunt.registerTask('docs', ['markdown:guides', 'build-docs'])
ciTasks = ['output-disk-space', 'download-atom-shell', 'build']
ciTasks.push('dump-symbols') if process.platform isnt 'win32'
ciTasks.push('set-version', 'check-licenses', 'lint')
ciTasks.push('mkdeb') if process.platform is 'linux'
ciTasks.push('test') if process.platform isnt 'linux'
ciTasks.push('codesign', 'publish-build')
grunt.registerTask('ci', ciTasks)
defaultTasks = ['download-atom-shell', 'build', 'set-version']
defaultTasks.push 'install' unless process.platform is 'linux'
grunt.registerTask('default', defaultTasks)
+3 -3
Ver Arquivo
@@ -7,8 +7,8 @@
},
"dependencies": {
"async": "~0.2.9",
"donna": "~1.0",
"tello": "~0.2",
"donna": "1.0.1",
"tello": "1.0.3",
"formidable": "~1.0.14",
"fs-plus": "2.x",
"github-releases": "~0.2.0",
@@ -27,7 +27,7 @@
"harmony-collections": "~0.3.8",
"json-front-matter": "~0.1.3",
"legal-eagle": "~0.4.0",
"minidump": "~0.7",
"minidump": "~0.8",
"normalize-package-data": "0.2.12",
"npm": "~1.4.5",
"rcedit": "~0.1.2",
+1
Ver Arquivo
@@ -11,6 +11,7 @@ module.exports = (grunt) ->
modulesPath = path.resolve(__dirname, '..', '..', 'node_modules')
classes = {}
fs.traverseTreeSync modulesPath, (modulePath) ->
return false if modulePath.match(/node_modules/g).length > 1 # dont need the dependencies of the dependencies
return true unless path.basename(modulePath) is 'package.json'
return true unless fs.isFileSync(modulePath)
+28 -11
Ver Arquivo
@@ -28,7 +28,7 @@ module.exports = (gruntObject) ->
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')
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()
@@ -45,16 +45,33 @@ module.exports = (gruntObject) ->
uploadAssets(release, buildDir, assets, done)
getAssets = ->
if process.platform is 'darwin'
[
{assetName: 'atom-mac.zip', sourcePath: 'Atom.app'}
{assetName: 'atom-mac-symbols.zip', sourcePath: 'Atom.breakpad.syms'}
{assetName: 'atom-api.json', sourcePath: 'atom-api.json'}
]
else
[
{assetName: 'atom-windows.zip', sourcePath: 'Atom'}
]
switch process.platform
when 'darwin'
[
{assetName: 'atom-mac.zip', sourcePath: 'Atom.app'}
{assetName: 'atom-mac-symbols.zip', sourcePath: 'Atom.breakpad.syms'}
{assetName: 'atom-api.json', sourcePath: 'atom-api.json'}
]
when 'win32'
[
{assetName: 'atom-windows.zip', sourcePath: 'Atom'}
]
when 'linux'
buildDir = grunt.config.get('atom.buildDir')
if process.arch is 'ia32'
arch = 'i386'
else
arch = 'amd64'
{version} = grunt.file.readJSON('package.json')
sourcePath = "#{buildDir}/atom-#{version}-#{arch}.deb"
assetName = "atom-#{arch}.deb"
{cp} = require('./task-helpers')(grunt)
cp sourcePath, path.join(buildDir, assetName)
[
{assetName, sourcePath}
]
logError = (message, error, details) ->
grunt.log.error(message)
+1 -2
Ver Arquivo
@@ -109,7 +109,6 @@ module.exports = (grunt) ->
grunt.log.error("[Error]".red + " #{failures.join(', ')} spec(s) failed") if failures.length > 0
if process.platform is 'win32' and process.env.JANKY_SHA1
# Package specs are still flaky on Windows CI
done(!coreSpecFailed)
done()
else
done(!coreSpecFailed and failedPackages.length == 0)
+2 -1
Ver Arquivo
@@ -53,8 +53,9 @@ module.exports = (grunt) ->
proc = childProcess.spawn(options.cmd, options.args, options.opts)
proc.stdout.on 'data', (data) -> stdout.push(data.toString())
proc.stderr.on 'data', (data) -> stderr.push(data.toString())
proc.on 'error', (processError) -> error ?= processError
proc.on 'close', (exitCode, signal) ->
error = new Error(signal) if exitCode != 0
error ?= new Error(signal) if exitCode != 0
results = {stderr: stderr.join(''), stdout: stdout.join(''), code: exitCode}
grunt.log.error results.stderr if exitCode != 0
callback(error, results, exitCode)
+40 -16
Ver Arquivo
@@ -33,26 +33,41 @@ Ubuntu LTS 12.04 64-bit is the recommended platform.
If you have problems with permissions don't forget to prefix with `sudo`
From the cloned repository directory:
1. Clone the Atom repository:
1. Build:
```sh
git clone https://github.com/atom/atom
cd atom
```
```sh
$ script/build
```
This will create the atom application at `$TMPDIR/atom-build/Atom`.
2. Install the `atom` and `apm` commands to `/usr/local/bin` by executing:
2. Checkout the latest Atom release:
```sh
$ sudo script/grunt install
```
3. *Optionally*, you may generate a `.deb` package at `$TMPDIR/atom-build`:
```sh
git fetch
git checkout $(git describe --tags `git rev-list --tags --max-count=1`)
```
```sh
$ script/grunt mkdeb
```
3. Build Atom:
Use the newly installed atom by restarting any running atom instances.
```sh
script/build
```
This will create the atom application at `$TMPDIR/atom-build/Atom`.
4. Install the `atom` and `apm` commands to `/usr/local/bin` by executing:
```sh
sudo script/grunt install
```
5. *Optionally*, you may generate a `.deb` package at `$TMPDIR/atom-build`:
```sh
script/grunt mkdeb
```
Use the newly installed Atom by fully quitting Atom and then reopening.
## Advanced Options
@@ -88,7 +103,7 @@ this is the reason for this error you can issue
and restart Atom. If Atom now works fine, you can make this setting permanent:
```sh
echo 32768 > /proc/sys/fs/inotify/max_user_watches
echo 32768 | sudo tee -a /proc/sys/fs/inotify/max_user_watches
```
See also https://github.com/atom/atom/issues/2082.
@@ -100,6 +115,15 @@ have Node.js installed, or node isn't identified as Node.js on your machine.
If it's the latter, entering `sudo ln -s /usr/bin/nodejs /usr/bin/node` into
your terminal may fix the issue.
#### You can also use Alternatives
On some variants (mostly Debian based distros) it's preferable for you to use
Alternatives so that changes to the binary paths can be fixed or altered easily:
```sh
sudo update-alternatives --install /usr/bin/node node /usr/bin/nodejs 1 --slave /usr/bin/js js /usr/bin/nodejs
```
### Linux build error reports in atom/atom
* Use [this search](https://github.com/atom/atom/search?q=label%3Abuild-error+label%3Alinux&type=Issues)
to get a list of reports about build errors on Linux.
+1 -1
Ver Arquivo
@@ -11,4 +11,4 @@
# atom.workspaceView.eachEditorView (editorView) ->
# editor = editorView.getEditor()
# if path.extname(editor.getPath()) is '.md'
# editor.setSoftWrap(true)
# editor.setSoftWrapped(true)
+4 -1
Ver Arquivo
@@ -13,6 +13,9 @@
# 'enter': 'editor:newline'
#
# '.workspace':
# 'ctrl-P': 'core:move-up'
# 'ctrl-shift-p': 'core:move-up'
# 'ctrl-p': 'core:move-down'
#
# You can find more information about keymaps in these guides:
# * https://atom.io/docs/latest/customizing-atom#customizing-key-bindings
# * https://atom.io/docs/latest/advanced/keymaps
+6 -1
Ver Arquivo
@@ -1,12 +1,17 @@
{Point, Range} = require 'text-buffer'
{deprecate} = require 'grim'
module.exports =
BufferedNodeProcess: require '../src/buffered-node-process'
BufferedProcess: require '../src/buffered-process'
Git: require '../src/git'
GitRepository: require '../src/git-repository'
Point: Point
Range: Range
Object.defineProperty module.exports, 'Git', get: ->
deprecate "Please require `GitRepository` instead of `Git`: `{GitRepository} = require 'atom'`"
module.exports.GitRepository
# The following classes can't be used from a Task handler and should therefore
# only be exported when not running as a child node process
unless process.env.ATOM_SHELL_INTERNAL_RUN_AS_NODE
+3 -1
Ver Arquivo
@@ -119,7 +119,7 @@
'cmd-shift-right': 'editor:select-to-end-of-line'
'alt-backspace': 'editor:delete-to-beginning-of-word'
'alt-delete': 'editor:delete-to-end-of-word'
'ctrl-a': 'editor:move-to-beginning-of-line'
'ctrl-a': 'editor:move-to-first-character-of-line'
'ctrl-e': 'editor:move-to-end-of-line'
'ctrl-k': 'editor:cut-to-end-of-line'
@@ -143,6 +143,8 @@
# Sublime Parity
'cmd-enter': 'editor:newline-below'
'cmd-shift-enter': 'editor:newline-above'
'alt-enter': 'editor:newline'
'shift-enter': 'editor:newline'
'cmd-]': 'editor:indent-selected-rows'
'cmd-[': 'editor:outdent-selected-rows'
'ctrl-cmd-up': 'editor:move-line-up'
+2
Ver Arquivo
@@ -18,6 +18,8 @@
{ type: 'separator' }
{ label: 'Install Shell Commands', command: 'window:install-shell-commands' }
{ type: 'separator' }
{ label: 'Services', submenu: [] }
{ type: 'separator' }
{ label: 'Hide Atom', command: 'application:hide' }
{ label: 'Hide Others', command: 'application:hide-other-applications' }
{ label: 'Show All', command: 'application:unhide-all-applications' }
+1
Ver Arquivo
@@ -85,6 +85,7 @@
{ 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' }
{ type: 'separator' }
]
}
+37 -37
Ver Arquivo
@@ -1,7 +1,7 @@
{
"name": "atom",
"productName": "Atom",
"version": "0.125.0",
"version": "0.130.0",
"description": "A hackable text editor for the 21st Century.",
"main": "./src/browser/main.js",
"repository": {
@@ -17,18 +17,18 @@
"url": "http://github.com/atom/atom/raw/master/LICENSE.md"
}
],
"atomShellVersion": "0.15.9",
"atomShellVersion": "0.16.2",
"dependencies": {
"async": "0.2.6",
"atom-keymap": "^2.0.5",
"atom-keymap": "^2.1.1",
"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.3.1",
"event-kit": "0.5.0",
"first-mate": "^2.0.5",
"event-kit": "0.7.2",
"first-mate": "^2.1.2",
"fs-plus": "^2.2.6",
"fstream": "0.1.24",
"fuzzaldrin": "^2.1",
@@ -36,109 +36,109 @@
"grim": "0.12.0",
"guid": "0.0.10",
"jasmine-tagged": "^1.1.2",
"less-cache": "0.14.0",
"less-cache": "0.15.0",
"mixto": "^1",
"mkdirp": "0.3.5",
"nslog": "^1.0.1",
"oniguruma": "^3.0.4",
"optimist": "0.4.0",
"pathwatcher": "^2.0.10",
"pathwatcher": "^2.1.3",
"property-accessors": "^1",
"q": "^1.0.1",
"random-words": "0.0.1",
"react-atom-fork": "^0.11.1",
"reactionary-atom-fork": "^1.0.0",
"runas": "1.0.1",
"scandal": "1.0.0",
"scandal": "1.0.2",
"scoped-property-store": "^0.9.0",
"scrollbar-style": "^1.0.2",
"season": "^1.0.2",
"semver": "1.1.4",
"serializable": "^1",
"space-pen": "3.4.6",
"space-pen": "3.4.7",
"temp": "0.7.0",
"text-buffer": "^3.2.0",
"text-buffer": "^3.2.6",
"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.34.0",
"atom-dark-ui": "0.35.0",
"atom-light-syntax": "0.20.0",
"atom-light-ui": "0.29.0",
"atom-light-ui": "0.30.0",
"base16-tomorrow-dark-theme": "0.21.0",
"base16-tomorrow-light-theme": "0.4.0",
"solarized-dark-syntax": "0.22.0",
"solarized-light-syntax": "0.12.0",
"archive-view": "0.36.0",
"autocomplete": "0.31.0",
"archive-view": "0.37.0",
"autocomplete": "0.32.0",
"autoflow": "0.18.0",
"autosave": "0.15.0",
"autosave": "0.17.0",
"background-tips": "0.16.0",
"bookmarks": "0.28.0",
"bracket-matcher": "0.54.0",
"command-palette": "0.24.0",
"bracket-matcher": "0.58.0",
"command-palette": "0.25.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.134.0",
"find-and-replace": "0.138.0",
"fuzzy-finder": "0.58.0",
"git-diff": "0.39.0",
"go-to-line": "0.25.0",
"grammar-selector": "0.29.0",
"grammar-selector": "0.34.0",
"image-view": "0.36.0",
"incompatible-packages": "0.9.0",
"keybinding-resolver": "0.19.0",
"keybinding-resolver": "0.20.0",
"link": "0.25.0",
"markdown-preview": "0.101.0",
"metrics": "0.33.0",
"markdown-preview": "0.103.0",
"metrics": "0.34.0",
"open-on-github": "0.30.0",
"package-generator": "0.31.0",
"release-notes": "0.36.0",
"settings-view": "0.142.0",
"snippets": "0.51.0",
"settings-view": "0.145.0",
"snippets": "0.52.0",
"spell-check": "0.42.0",
"status-bar": "0.44.0",
"status-bar": "0.45.0",
"styleguide": "0.30.0",
"symbols-view": "0.63.0",
"tabs": "0.50.0",
"symbols-view": "0.66.0",
"tabs": "0.52.0",
"timecop": "0.22.0",
"tree-view": "0.114.0",
"tree-view": "0.126.0",
"update-package-dependencies": "0.6.0",
"welcome": "0.18.0",
"whitespace": "0.25.0",
"wrap-guide": "0.21.0",
"wrap-guide": "0.22.0",
"language-c": "0.28.0",
"language-coffee-script": "0.30.0",
"language-coffee-script": "0.34.0",
"language-css": "0.17.0",
"language-gfm": "0.48.0",
"language-gfm": "0.50.0",
"language-git": "0.9.0",
"language-go": "0.17.0",
"language-html": "0.25.0",
"language-html": "0.26.0",
"language-hyperlink": "0.12.0",
"language-java": "0.11.0",
"language-javascript": "0.39.0",
"language-javascript": "0.40.0",
"language-json": "0.8.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-php": "0.16.0",
"language-property-list": "0.7.0",
"language-python": "0.19.0",
"language-ruby": "0.35.0",
"language-ruby": "0.38.0",
"language-ruby-on-rails": "0.18.0",
"language-sass": "0.21.0",
"language-shellscript": "0.8.0",
"language-source": "0.8.0",
"language-sql": "0.10.0",
"language-sql": "0.11.0",
"language-text": "0.6.0",
"language-todo": "0.11.0",
"language-toml": "0.12.0",
"language-xml": "0.19.0",
"language-xml": "0.21.0",
"language-yaml": "0.17.0"
},
"private": true,
+2 -1
Ver Arquivo
@@ -5,4 +5,5 @@ Exec=<%= installDir %>/share/atom/atom %U
Icon=<%= iconName %>
Type=Application
StartupNotify=true
Categories=GNOME;GTK;Utility;TextEditor;
Categories=GNOME;GTK;Utility;TextEditor;Development;
MimeType=text/plain;
+1 -4
Ver Arquivo
@@ -5,9 +5,6 @@ var path = require('path');
process.chdir(path.dirname(__dirname));
if (process.platform == 'linux')
throw new Error('cibuild can not run on linux yet!');
var homeDir = process.platform == 'win32' ? process.env.USERPROFILE : process.env.HOME;
function loadEnvironmentVariables(filePath) {
@@ -27,7 +24,7 @@ function loadEnvironmentVariables(filePath) {
function readEnvironmentVariables() {
if (process.platform === 'win32')
loadEnvironmentVariables(path.resolve('/jenkins/config/atomcredentials'));
else {
else if (process.platform === 'darwin') {
loadEnvironmentVariables('/var/lib/jenkins/config/atomcredentials');
loadEnvironmentVariables('/var/lib/jenkins/config/xcodekeychain');
}
Arquivo executável
+13
Ver Arquivo
@@ -0,0 +1,13 @@
#!/bin/bash
set -e
export ATOM_ACCESS_TOKEN=$BUILD_ATOM_LINUX_ACCESS_TOKEN
if [ -d /usr/local/share/nodenv ]; then
export NODENV_ROOT=/usr/local/share/nodenv
export PATH=/usr/local/share/nodenv/bin:/usr/local/share/nodenv/shims:$PATH
export NODENV_VERSION="v0.10.21"
fi
script/cibuild
+1 -1
Ver Arquivo
@@ -31,7 +31,7 @@ function verifyNode(cb) {
var nodeMajorVersion = +versionArray[0];
var nodeMinorVersion = +versionArray[1];
if (nodeMajorVersion === 0 && nodeMinorVersion < 10) {
error = "node v0.10 is required to build Atom.";
error = "node v0.10 is required to build Atom, node " + nodeVersion + " is installed.";
cb(error);
}
else {
+41 -14
Ver Arquivo
@@ -8,6 +8,23 @@ describe "the `atom` global", ->
beforeEach ->
atom.workspaceView = new WorkspaceView
describe 'window sizing methods', ->
describe '::getPosition and ::setPosition', ->
it 'sets the position of the window, and can retrieve the position just set', ->
atom.setPosition(22, 45)
expect(atom.getPosition()).toEqual x: 22, y: 45
describe '::getSize and ::setSize', ->
originalSize = null
beforeEach ->
originalSize = atom.getSize()
afterEach ->
atom.setSize(originalSize.width, originalSize.height)
it 'sets the size of the window, and can retrieve the size just set', ->
atom.setSize(100, 400)
expect(atom.getSize()).toEqual width: 100, height: 400
describe "package lifecycle methods", ->
describe ".loadPackage(name)", ->
it "continues if the package has an invalid package.json", ->
@@ -241,15 +258,15 @@ describe "the `atom` global", ->
two = atom.themes.stringToId(two)
three = atom.themes.stringToId(three)
expect(atom.themes.stylesheetElementForId(one)).not.toExist()
expect(atom.themes.stylesheetElementForId(two)).not.toExist()
expect(atom.themes.stylesheetElementForId(three)).not.toExist()
expect(atom.themes.stylesheetElementForId(one)).toBeNull()
expect(atom.themes.stylesheetElementForId(two)).toBeNull()
expect(atom.themes.stylesheetElementForId(three)).toBeNull()
atom.packages.activatePackage("package-with-stylesheets-manifest")
expect(atom.themes.stylesheetElementForId(one)).toExist()
expect(atom.themes.stylesheetElementForId(two)).toExist()
expect(atom.themes.stylesheetElementForId(three)).not.toExist()
expect(atom.themes.stylesheetElementForId(one)).not.toBeNull()
expect(atom.themes.stylesheetElementForId(two)).not.toBeNull()
expect(atom.themes.stylesheetElementForId(three)).toBeNull()
expect($('#jasmine-content').css('font-size')).toBe '1px'
describe "when the metadata does not contain a 'stylesheets' manifest", ->
@@ -263,14 +280,14 @@ describe "the `atom` global", ->
two = atom.themes.stringToId(two)
three = atom.themes.stringToId(three)
expect(atom.themes.stylesheetElementForId(one)).not.toExist()
expect(atom.themes.stylesheetElementForId(two)).not.toExist()
expect(atom.themes.stylesheetElementForId(three)).not.toExist()
expect(atom.themes.stylesheetElementForId(one)).toBeNull()
expect(atom.themes.stylesheetElementForId(two)).toBeNull()
expect(atom.themes.stylesheetElementForId(three)).toBeNull()
atom.packages.activatePackage("package-with-stylesheets")
expect(atom.themes.stylesheetElementForId(one)).toExist()
expect(atom.themes.stylesheetElementForId(two)).toExist()
expect(atom.themes.stylesheetElementForId(three)).toExist()
expect(atom.themes.stylesheetElementForId(one)).not.toBeNull()
expect(atom.themes.stylesheetElementForId(two)).not.toBeNull()
expect(atom.themes.stylesheetElementForId(three)).not.toBeNull()
expect($('#jasmine-content').css('font-size')).toBe '3px'
describe "grammar loading", ->
@@ -350,7 +367,7 @@ describe "the `atom` global", ->
atom.packages.deactivatePackage("package-that-throws-on-activate")
expect(badPack.mainModule.serialize).not.toHaveBeenCalled()
it "absorbs exceptions that are thrown by the package module's serialize methods", ->
it "absorbs exceptions that are thrown by the package module's serialize method", ->
spyOn(console, 'error')
waitsForPromise ->
@@ -365,6 +382,16 @@ describe "the `atom` global", ->
expect(atom.packages.packageStates['package-with-serialization']).toEqual someNumber: 1
expect(console.error).toHaveBeenCalled()
it "absorbs exceptions that are thrown by the package module's deactivate method", ->
spyOn(console, 'error')
waitsForPromise ->
atom.packages.activatePackage("package-that-throws-on-deactivate")
runs ->
expect(-> atom.packages.deactivatePackage("package-that-throws-on-deactivate")).not.toThrow()
expect(console.error).toHaveBeenCalled()
it "removes the package's grammars", ->
waitsForPromise ->
atom.packages.activatePackage('package-with-grammars')
@@ -520,7 +547,7 @@ describe "the `atom` global", ->
reloadedHandler = jasmine.createSpy('reloadedHandler')
reloadedHandler.reset()
atom.themes.on('reloaded', reloadedHandler)
atom.themes.onDidReloadAll reloadedHandler
pack = atom.packages.disablePackage(packageName)
+126
Ver Arquivo
@@ -0,0 +1,126 @@
CommandRegistry = require '../src/command-registry'
describe "CommandRegistry", ->
[registry, parent, child, grandchild] = []
beforeEach ->
parent = document.createElement("div")
child = document.createElement("div")
grandchild = document.createElement("div")
parent.classList.add('parent')
child.classList.add('child')
grandchild.classList.add('grandchild')
child.appendChild(grandchild)
parent.appendChild(child)
document.querySelector('#jasmine-content').appendChild(parent)
registry = new CommandRegistry(parent)
describe "command dispatch", ->
it "invokes callbacks with selectors matching the target", ->
called = false
registry.add '.grandchild', 'command', (event) ->
expect(this).toBe grandchild
expect(event.type).toBe 'command'
expect(event.eventPhase).toBe Event.BUBBLING_PHASE
expect(event.target).toBe grandchild
expect(event.currentTarget).toBe grandchild
called = true
grandchild.dispatchEvent(new CustomEvent('command', bubbles: true))
expect(called).toBe true
it "invokes callbacks with selectors matching ancestors of the target", ->
calls = []
registry.add '.child', 'command', (event) ->
expect(this).toBe child
expect(event.target).toBe grandchild
expect(event.currentTarget).toBe child
calls.push('child')
registry.add '.parent', 'command', (event) ->
expect(this).toBe parent
expect(event.target).toBe grandchild
expect(event.currentTarget).toBe parent
calls.push('parent')
grandchild.dispatchEvent(new CustomEvent('command', bubbles: true))
expect(calls).toEqual ['child', 'parent']
it "orders multiple matching listeners for an element by selector specificity", ->
child.classList.add('foo', 'bar')
calls = []
registry.add '.foo.bar', 'command', -> calls.push('.foo.bar')
registry.add '.foo', 'command', -> calls.push('.foo')
registry.add '.bar', 'command', -> calls.push('.bar') # specificity ties favor commands added later, like CSS
grandchild.dispatchEvent(new CustomEvent('command', bubbles: true))
expect(calls).toEqual ['.foo.bar', '.bar', '.foo']
it "stops bubbling through ancestors when .stopPropagation() is called on the event", ->
calls = []
registry.add '.parent', 'command', -> calls.push('parent')
registry.add '.child', 'command', -> calls.push('child-2')
registry.add '.child', 'command', (event) -> calls.push('child-1'); event.stopPropagation()
grandchild.dispatchEvent(new CustomEvent('command', bubbles: true))
expect(calls).toEqual ['child-1', 'child-2']
it "stops invoking callbacks when .stopImmediatePropagation() is called on the event", ->
calls = []
registry.add '.parent', 'command', -> calls.push('parent')
registry.add '.child', 'command', -> calls.push('child-2')
registry.add '.child', 'command', (event) -> calls.push('child-1'); event.stopImmediatePropagation()
grandchild.dispatchEvent(new CustomEvent('command', bubbles: true))
expect(calls).toEqual ['child-1']
it "allows listeners to be removed via a disposable returned by ::add", ->
calls = []
disposable1 = registry.add '.parent', 'command', -> calls.push('parent')
disposable2 = registry.add '.child', 'command', -> calls.push('child')
disposable1.dispose()
grandchild.dispatchEvent(new CustomEvent('command', bubbles: true))
expect(calls).toEqual ['child']
calls = []
disposable2.dispose()
grandchild.dispatchEvent(new CustomEvent('command', bubbles: true))
expect(calls).toEqual []
it "allows multiple commands to be registered under one selector when called with an object", ->
calls = []
disposable = registry.add '.child',
'command-1': -> calls.push('command-1')
'command-2': -> calls.push('command-2')
grandchild.dispatchEvent(new CustomEvent('command-1', bubbles: true))
grandchild.dispatchEvent(new CustomEvent('command-2', bubbles: true))
expect(calls).toEqual ['command-1', 'command-2']
calls = []
disposable.dispose()
grandchild.dispatchEvent(new CustomEvent('command-1', bubbles: true))
grandchild.dispatchEvent(new CustomEvent('command-2', bubbles: true))
expect(calls).toEqual []
describe "::findCommands({target})", ->
it "returns commands that can be invoked on the target or its ancestors", ->
registry.add '.parent', 'namespace:command-1', ->
registry.add '.child', 'namespace:command-2', ->
registry.add '.grandchild', 'namespace:command-3', ->
registry.add '.grandchild.no-match', 'namespace:command-4', ->
expect(registry.findCommands(target: grandchild)[0..2]).toEqual [
{name: 'namespace:command-3', displayName: 'Namespace: Command 3'}
{name: 'namespace:command-2', displayName: 'Namespace: Command 2'}
{name: 'namespace:command-1', displayName: 'Namespace: Command 1'}
]
+34 -35
Ver Arquivo
@@ -9,7 +9,7 @@ describe "DisplayBuffer", ->
buffer = atom.project.bufferForPathSync('sample.js')
displayBuffer = new DisplayBuffer({buffer, tabLength})
changeHandler = jasmine.createSpy 'changeHandler'
displayBuffer.on 'changed', changeHandler
displayBuffer.onDidChange changeHandler
waitsForPromise ->
atom.packages.activatePackage('language-javascript')
@@ -58,7 +58,7 @@ describe "DisplayBuffer", ->
describe "soft wrapping", ->
beforeEach ->
displayBuffer.setSoftWrap(true)
displayBuffer.setSoftWrapped(true)
displayBuffer.setEditorWidthInChars(50)
changeHandler.reset()
@@ -129,7 +129,7 @@ describe "DisplayBuffer", ->
expect(event).toEqual(start: 7, end: 8, screenDelta: -1, bufferDelta: 0)
describe "when the update causes a line to softwrap an additional time", ->
describe "when the update causes a line to soft wrap an additional time", ->
it "rewraps the line and emits a change event", ->
buffer.insert([6, 28], '1234567890')
expect(displayBuffer.tokenizedLineForScreenRow(7).text).toBe ' current < pivot ? '
@@ -162,7 +162,7 @@ describe "DisplayBuffer", ->
describe "when a newline is inserted, deleted, and re-inserted at the end of a wrapped line (regression)", ->
it "correctly renders the original wrapped line", ->
buffer = atom.project.buildBufferSync(null, '')
displayBuffer = new DisplayBuffer({buffer, tabLength, editorWidthInChars: 30, softWrap: true})
displayBuffer = new DisplayBuffer({buffer, tabLength, editorWidthInChars: 30, softWrapped: true})
buffer.insert([0, 0], "the quick brown fox jumps over the lazy dog.")
buffer.insert([0, Infinity], '\n')
@@ -220,10 +220,10 @@ describe "DisplayBuffer", ->
displayBuffer.setWidth(50)
displayBuffer.manageScrollPosition = true
displayBuffer.setSoftWrap(false)
displayBuffer.setSoftWrapped(false)
displayBuffer.setScrollLeft(Infinity)
expect(displayBuffer.getScrollLeft()).toBeGreaterThan 0
displayBuffer.setSoftWrap(true)
displayBuffer.setSoftWrapped(true)
expect(displayBuffer.getScrollLeft()).toBe 0
displayBuffer.setScrollLeft(10)
expect(displayBuffer.getScrollLeft()).toBe 0
@@ -234,7 +234,7 @@ describe "DisplayBuffer", ->
buffer.release()
buffer = atom.project.bufferForPathSync('two-hundred.txt')
displayBuffer = new DisplayBuffer({buffer, tabLength})
displayBuffer.on 'changed', changeHandler
displayBuffer.onDidChange changeHandler
describe "when folds are created and destroyed", ->
describe "when a fold spans multiple lines", ->
@@ -568,7 +568,7 @@ describe "DisplayBuffer", ->
describe "::clipScreenPosition(screenPosition, wrapBeyondNewlines: false, wrapAtSoftNewlines: false, skipAtomicTokens: false)", ->
beforeEach ->
displayBuffer.setSoftWrap(true)
displayBuffer.setSoftWrapped(true)
displayBuffer.setEditorWidthInChars(50)
it "allows valid positions", ->
@@ -643,7 +643,7 @@ describe "DisplayBuffer", ->
it "correctly translates positions on soft wrapped lines containing tabs", ->
buffer.setText('\t\taa bb cc dd ee ff gg')
displayBuffer.setSoftWrap(true)
displayBuffer.setSoftWrapped(true)
displayBuffer.setEditorWidthInChars(10)
expect(displayBuffer.screenPositionForBufferPosition([0, 10], wrapAtSoftNewlines: true)).toEqual [1, 0]
expect(displayBuffer.bufferPositionForScreenPosition([1, 0])).toEqual [0, 10]
@@ -686,7 +686,7 @@ describe "DisplayBuffer", ->
expect(marker2.getScreenRange()).toEqual [[5, 4], [5, 10]]
it "emits a 'marker-created' event on the DisplayBuffer whenever a marker is created", ->
displayBuffer.on 'marker-created', markerCreatedHandler = jasmine.createSpy("markerCreatedHandler")
displayBuffer.onDidCreateMarker markerCreatedHandler = jasmine.createSpy("markerCreatedHandler")
marker1 = displayBuffer.markScreenRange([[5, 4], [5, 10]])
expect(markerCreatedHandler).toHaveBeenCalledWith(marker1)
@@ -722,7 +722,7 @@ describe "DisplayBuffer", ->
beforeEach ->
marker = displayBuffer.markScreenRange([[5, 4], [5, 10]])
marker.on 'changed', markerChangedHandler = jasmine.createSpy("markerChangedHandler")
marker.onDidChange markerChangedHandler = jasmine.createSpy("markerChangedHandler")
it "triggers the 'changed' event whenever the markers head's screen position changes in the buffer or on screen", ->
marker.setHeadScreenPosition([8, 20])
@@ -859,8 +859,8 @@ describe "DisplayBuffer", ->
it "updates markers before emitting buffer change events, but does not notify their observers until the change event", ->
marker2 = displayBuffer.markBufferRange([[8, 1], [8, 1]])
marker2.on 'changed', marker2ChangedHandler = jasmine.createSpy("marker2ChangedHandler")
displayBuffer.on 'changed', changeHandler = jasmine.createSpy("changeHandler").andCallFake -> onDisplayBufferChange()
marker2.onDidChange marker2ChangedHandler = jasmine.createSpy("marker2ChangedHandler")
displayBuffer.onDidChange changeHandler = jasmine.createSpy("changeHandler").andCallFake -> onDisplayBufferChange()
# New change ----
@@ -886,7 +886,7 @@ describe "DisplayBuffer", ->
marker2ChangedHandler.reset()
marker3 = displayBuffer.markBufferRange([[8, 1], [8, 2]])
marker3.on 'changed', marker3ChangedHandler = jasmine.createSpy("marker3ChangedHandler")
marker3.onDidChange marker3ChangedHandler = jasmine.createSpy("marker3ChangedHandler")
onDisplayBufferChange = ->
# calls change handler first
@@ -932,7 +932,7 @@ describe "DisplayBuffer", ->
expect(marker3ChangedHandler).toHaveBeenCalled()
it "updates the position of markers before emitting change events that aren't caused by a buffer change", ->
displayBuffer.on 'changed', changeHandler = jasmine.createSpy("changeHandler").andCallFake ->
displayBuffer.onDidChange changeHandler = jasmine.createSpy("changeHandler").andCallFake ->
# calls change handler first
expect(markerChangedHandler).not.toHaveBeenCalled()
# but still updates the markers
@@ -998,20 +998,20 @@ describe "DisplayBuffer", ->
expect(marker.isValid()).toBeFalsy()
expect(displayBuffer.getMarker(marker.id)).toBeUndefined()
it "emits 'destroyed' events when markers are destroyed", ->
it "notifies ::onDidDestroy observers when markers are destroyed", ->
destroyedHandler = jasmine.createSpy("destroyedHandler")
marker = displayBuffer.markScreenRange([[5, 4], [5, 10]])
marker.on 'destroyed', destroyedHandler
marker.onDidDestroy destroyedHandler
marker.destroy()
expect(destroyedHandler).toHaveBeenCalled()
destroyedHandler.reset()
marker2 = displayBuffer.markScreenRange([[5, 4], [5, 10]])
marker2.on 'destroyed', destroyedHandler
marker2.onDidDestroy destroyedHandler
buffer.getMarker(marker2.id).destroy()
expect(destroyedHandler).toHaveBeenCalled()
describe "DisplayBufferMarker::copy(attributes)", ->
describe "Marker::copy(attributes)", ->
it "creates a copy of the marker with the given attributes merged in", ->
initialMarkerCount = displayBuffer.getMarkerCount()
marker1 = displayBuffer.markScreenRange([[5, 4], [5, 10]], a: 1, b: 2)
@@ -1020,10 +1020,10 @@ describe "DisplayBuffer", ->
marker2 = marker1.copy(b: 3)
expect(marker2.getBufferRange()).toEqual marker1.getBufferRange()
expect(displayBuffer.getMarkerCount()).toBe initialMarkerCount + 2
expect(marker1.getAttributes()).toEqual a: 1, b: 2
expect(marker2.getAttributes()).toEqual a: 1, b: 3
expect(marker1.getProperties()).toEqual a: 1, b: 2
expect(marker2.getProperties()).toEqual a: 1, b: 3
describe "DisplayBufferMarker::getPixelRange()", ->
describe "Marker::getPixelRange()", ->
it "returns the start and end positions of the marker based on the line height and character widths assigned to the DisplayBuffer", ->
marker = displayBuffer.markScreenRange([[5, 10], [6, 4]])
@@ -1041,9 +1041,8 @@ describe "DisplayBuffer", ->
describe 'when a marker is created', ->
it 'the second display buffer will not emit a marker-created event when the marker has been deleted in the first marker-created event', ->
displayBuffer2 = new DisplayBuffer({buffer, tabLength})
displayBuffer.on 'marker-created', markerCreated1 = jasmine.createSpy().andCallFake (marker) ->
marker.destroy()
displayBuffer2.on 'marker-created', markerCreated2 = jasmine.createSpy()
displayBuffer.onDidCreateMarker markerCreated1 = jasmine.createSpy().andCallFake (marker) -> marker.destroy()
displayBuffer2.onDidCreateMarker markerCreated2 = jasmine.createSpy()
displayBuffer.markBufferRange([[0, 0], [1, 5]], {})
@@ -1051,15 +1050,15 @@ describe "DisplayBuffer", ->
expect(markerCreated2).not.toHaveBeenCalled()
describe "decorations", ->
[marker, decoration, decorationParams] = []
[marker, decoration, decorationProperties] = []
beforeEach ->
marker = displayBuffer.markBufferRange([[2, 13], [3, 15]])
decorationParams = {type: 'gutter', class: 'one'}
decoration = displayBuffer.decorateMarker(marker, decorationParams)
decorationProperties = {type: 'gutter', class: 'one'}
decoration = displayBuffer.decorateMarker(marker, decorationProperties)
it "can add decorations associated with markers and remove them", ->
expect(decoration).toBeDefined()
expect(decoration.getParams()).toBe decorationParams
expect(decoration.getProperties()).toBe decorationProperties
expect(displayBuffer.decorationForId(decoration.id)).toBe decoration
expect(displayBuffer.decorationsForScreenRowRange(2, 3)[marker.id][0]).toBe decoration
@@ -1074,12 +1073,12 @@ describe "DisplayBuffer", ->
describe "when a decoration is updated via Decoration::update()", ->
it "emits an 'updated' event containing the new and old params", ->
decoration.on 'updated', updatedSpy = jasmine.createSpy()
decoration.update type: 'gutter', class: 'two'
decoration.onDidChangeProperties updatedSpy = jasmine.createSpy()
decoration.setProperties type: 'gutter', class: 'two'
{oldParams, newParams} = updatedSpy.mostRecentCall.args[0]
expect(oldParams).toEqual decorationParams
expect(newParams).toEqual type: 'gutter', class: 'two', id: decoration.id
{oldProperties, newProperties} = updatedSpy.mostRecentCall.args[0]
expect(oldProperties).toEqual decorationProperties
expect(newProperties).toEqual type: 'gutter', class: 'two', id: decoration.id
describe "::setScrollTop", ->
beforeEach ->
@@ -1172,7 +1171,7 @@ describe "DisplayBuffer", ->
it "recomputes the scroll width when the scoped character widths change in a batch", ->
operatorWidth = 20
displayBuffer.on 'character-widths-changed', changedSpy = jasmine.createSpy()
displayBuffer.onDidChangeCharacterWidths changedSpy = jasmine.createSpy()
displayBuffer.batchCharacterMeasurement ->
displayBuffer.setScopedCharWidth(['source.js', 'keyword.operator.js'], '<', operatorWidth)
+51 -7
Ver Arquivo
@@ -197,6 +197,50 @@ describe "EditorComponent", ->
nextAnimationFrame()
expect(linesNode.style.backgroundColor).toBe 'rgb(255, 0, 0)'
it "applies .leading-whitespace for lines with leading spaces and/or tabs", ->
editor.setText(' a')
nextAnimationFrame()
leafNodes = getLeafNodes(component.lineNodeForScreenRow(0))
expect(leafNodes[0].classList.contains('leading-whitespace')).toBe true
expect(leafNodes[0].classList.contains('trailing-whitespace')).toBe false
editor.setText('\ta')
nextAnimationFrame()
leafNodes = getLeafNodes(component.lineNodeForScreenRow(0))
expect(leafNodes[0].classList.contains('leading-whitespace')).toBe true
expect(leafNodes[0].classList.contains('trailing-whitespace')).toBe false
it "applies .trailing-whitespace for lines with trailing spaces and/or tabs", ->
editor.setText(' ')
nextAnimationFrame()
leafNodes = getLeafNodes(component.lineNodeForScreenRow(0))
expect(leafNodes[0].classList.contains('trailing-whitespace')).toBe true
expect(leafNodes[0].classList.contains('leading-whitespace')).toBe false
editor.setText('\t')
nextAnimationFrame()
leafNodes = getLeafNodes(component.lineNodeForScreenRow(0))
expect(leafNodes[0].classList.contains('trailing-whitespace')).toBe true
expect(leafNodes[0].classList.contains('leading-whitespace')).toBe false
editor.setText('a ')
nextAnimationFrame()
leafNodes = getLeafNodes(component.lineNodeForScreenRow(0))
expect(leafNodes[0].classList.contains('trailing-whitespace')).toBe true
expect(leafNodes[0].classList.contains('leading-whitespace')).toBe false
editor.setText('a\t')
nextAnimationFrame()
leafNodes = getLeafNodes(component.lineNodeForScreenRow(0))
expect(leafNodes[0].classList.contains('trailing-whitespace')).toBe true
expect(leafNodes[0].classList.contains('leading-whitespace')).toBe false
describe "when showInvisibles is enabled", ->
invisibles = null
@@ -278,7 +322,7 @@ describe "EditorComponent", ->
describe "when soft wrapping is enabled", ->
beforeEach ->
editor.setText "a line that wraps \n"
editor.setSoftWrap(true)
editor.setSoftWrapped(true)
nextAnimationFrame()
componentNode.style.width = 16 * charWidth + editor.getVerticalScrollbarWidth() + 'px'
component.measureHeightAndWidth()
@@ -457,7 +501,7 @@ describe "EditorComponent", ->
expect(component.lineNumberNodeForScreenRow(6).offsetTop).toBe 6 * lineHeightInPixels
it "renders • characters for soft-wrapped lines", ->
editor.setSoftWrap(true)
editor.setSoftWrapped(true)
wrapperNode.style.height = 4.5 * lineHeightInPixels + 'px'
wrapperNode.style.width = 30 * charWidth + 'px'
component.measureHeightAndWidth()
@@ -893,7 +937,7 @@ describe "EditorComponent", ->
it "only applies decorations to screen rows that are spanned by their marker when lines are soft-wrapped", ->
editor.setText("a line that wraps, ok")
editor.setSoftWrap(true)
editor.setSoftWrapped(true)
componentNode.style.width = 16 * charWidth + 'px'
component.measureHeightAndWidth()
nextAnimationFrame()
@@ -1134,7 +1178,7 @@ describe "EditorComponent", ->
it "renders the decoration's new params", ->
expect(componentNode.querySelector('.test-highlight')).toBeTruthy()
decoration.update(type: 'highlight', class: 'new-test-highlight')
decoration.setProperties(type: 'highlight', class: 'new-test-highlight')
nextAnimationFrame()
expect(componentNode.querySelector('.test-highlight')).toBeFalsy()
@@ -2066,7 +2110,7 @@ describe "EditorComponent", ->
describe "soft wrapping", ->
beforeEach ->
editor.setSoftWrap(true)
editor.setSoftWrapped(true)
nextAnimationFrame()
it "updates the wrap location when the editor is resized", ->
@@ -2192,10 +2236,10 @@ describe "EditorComponent", ->
describe "legacy editor compatibility", ->
it "triggers the screen-lines-changed event before the editor:display-update event", ->
editor.setSoftWrap(true)
editor.setSoftWrapped(true)
callingOrder = []
editor.on 'screen-lines-changed', -> callingOrder.push 'screen-lines-changed'
editor.onDidChange -> callingOrder.push 'screen-lines-changed'
wrapperView.on 'editor:display-updated', -> callingOrder.push 'editor:display-updated'
editor.insertText("HELLO! HELLO!\n HELLO! HELLO! HELLO! HELLO! HELLO! HELLO! HELLO! HELLO! HELLO! HELLO! HELLO! HELLO! HELLO! HELLO! HELLO! HELLO! HELLO! HELLO! ")
nextAnimationFrame()
+121 -68
Ver Arquivo
@@ -110,7 +110,7 @@ describe "Editor", ->
runs ->
expect(editor1.getTabLength()).toBe 4
expect(editor1.getSoftWrap()).toBe true
expect(editor1.isSoftWrapped()).toBe true
expect(editor1.getSoftTabs()).toBe false
atom.config.set('editor.tabLength', 100)
@@ -122,7 +122,7 @@ describe "Editor", ->
runs ->
expect(editor2.getTabLength()).toBe 100
expect(editor2.getSoftWrap()).toBe false
expect(editor2.isSoftWrapped()).toBe false
expect(editor2.getSoftTabs()).toBe true
describe "title", ->
@@ -138,13 +138,24 @@ describe "Editor", ->
buffer.setPath(undefined)
expect(editor.getLongTitle()).toBe 'untitled'
it "emits 'title-changed' events when the underlying buffer path", ->
titleChangedHandler = jasmine.createSpy("titleChangedHandler")
editor.on 'title-changed', titleChangedHandler
it "notifies ::onDidChangeTitle observers when the underlying buffer path changes", ->
observed = []
editor.onDidChangeTitle (title) -> observed.push(title)
buffer.setPath('/foo/bar/baz.txt')
buffer.setPath(undefined)
expect(titleChangedHandler.callCount).toBe 2
expect(observed).toEqual ['baz.txt', 'untitled']
describe "path", ->
it "notifies ::onDidChangePath observers when the underlying buffer path changes", ->
observed = []
editor.onDidChangePath (filePath) -> observed.push(filePath)
buffer.setPath(__filename)
buffer.setPath(undefined)
expect(observed).toEqual [__filename, undefined]
describe "cursor", ->
describe ".getLastCursor()", ->
@@ -163,20 +174,19 @@ describe "Editor", ->
editor.moveDown()
expect(editor.getCursorBufferPosition()).toEqual [1, 1]
it "emits a single 'cursors-moved' event for all moved cursors", ->
editor.on 'cursors-moved', cursorsMovedHandler = jasmine.createSpy("cursorsMovedHandler")
it "emits an event with the old position, new position, and the cursor that moved", ->
editor.onDidChangeCursorPosition positionChangedHandler = jasmine.createSpy()
editor.moveDown()
expect(cursorsMovedHandler.callCount).toBe 1
editor.setCursorBufferPosition([2, 4])
cursorsMovedHandler.reset()
editor.addCursorAtScreenPosition([3, 0])
editor.moveDown()
expect(cursorsMovedHandler.callCount).toBe 1
expect(positionChangedHandler).toHaveBeenCalled()
eventObject = positionChangedHandler.mostRecentCall.args[0]
cursorsMovedHandler.reset()
editor.getLastCursor().moveDown()
expect(cursorsMovedHandler.callCount).toBe 1
expect(eventObject.oldBufferPosition).toEqual [0, 0]
expect(eventObject.oldScreenPosition).toEqual [0, 0]
expect(eventObject.newBufferPosition).toEqual [2, 4]
expect(eventObject.newScreenPosition).toEqual [2, 4]
expect(eventObject.cursor).toBe editor.getLastCursor()
describe ".setCursorScreenPosition(screenPosition)", ->
it "clears a goal column established by vertical movement", ->
@@ -203,7 +213,7 @@ describe "Editor", ->
describe "when soft-wrap is enabled and code is folded", ->
beforeEach ->
editor.setSoftWrap(true)
editor.setSoftWrapped(true)
editor.setEditorWidthInChars(50)
editor.createFold(2, 3)
@@ -484,7 +494,7 @@ describe "Editor", ->
describe ".moveToBeginningOfScreenLine()", ->
describe "when soft wrap is on", ->
it "moves cursor to the beginning of the screen line", ->
editor.setSoftWrap(true)
editor.setSoftWrapped(true)
editor.setEditorWidthInChars(10)
editor.setCursorScreenPosition([1, 2])
editor.moveToBeginningOfScreenLine()
@@ -504,7 +514,7 @@ describe "Editor", ->
describe ".moveToEndOfScreenLine()", ->
describe "when soft wrap is on", ->
it "moves cursor to the beginning of the screen line", ->
editor.setSoftWrap(true)
editor.setSoftWrapped(true)
editor.setEditorWidthInChars(10)
editor.setCursorScreenPosition([1, 2])
editor.moveToEndOfScreenLine()
@@ -523,7 +533,7 @@ describe "Editor", ->
describe ".moveToBeginningOfLine()", ->
it "moves cursor to the beginning of the buffer line", ->
editor.setSoftWrap(true)
editor.setSoftWrapped(true)
editor.setEditorWidthInChars(10)
editor.setCursorScreenPosition([1, 2])
editor.moveToBeginningOfLine()
@@ -532,7 +542,7 @@ describe "Editor", ->
describe ".moveToEndOfLine()", ->
it "moves cursor to the end of the buffer line", ->
editor.setSoftWrap(true)
editor.setSoftWrapped(true)
editor.setEditorWidthInChars(10)
editor.setCursorScreenPosition([0, 2])
editor.moveToEndOfLine()
@@ -542,7 +552,7 @@ describe "Editor", ->
describe ".moveToFirstCharacterOfLine()", ->
describe "when soft wrap is on", ->
it "moves to the first character of the current screen line or the beginning of the screen line if it's already on the first character", ->
editor.setSoftWrap(true)
editor.setSoftWrapped(true)
editor.setEditorWidthInChars(10)
editor.setCursorScreenPosition [2,5]
editor.addCursorAtScreenPosition [8,7]
@@ -782,37 +792,6 @@ describe "Editor", ->
editor.setCursorBufferPosition([3, 1])
expect(editor.getCurrentParagraphBufferRange()).toBeUndefined()
describe "cursor-moved events", ->
cursorMovedHandler = null
beforeEach ->
editor.foldBufferRow(4)
editor.setSelectedBufferRange([[8, 1], [9, 0]])
cursorMovedHandler = jasmine.createSpy("cursorMovedHandler")
editor.on 'cursor-moved', cursorMovedHandler
describe "when the position of the cursor changes", ->
it "emits a cursor-moved event", ->
buffer.insert([9, 0], '...')
expect(cursorMovedHandler).toHaveBeenCalledWith(
oldBufferPosition: [9, 0]
oldScreenPosition: [6, 0]
newBufferPosition: [9, 3]
newScreenPosition: [6, 3]
textChanged: true
)
describe "when the position of the associated selection's tail changes, but not the cursor's position", ->
it "does not emit a cursor-moved event", ->
buffer.insert([8, 0], '...')
expect(cursorMovedHandler).not.toHaveBeenCalled()
describe "::getCursorBufferPositions()", ->
it "returns the cursor positions in the order they were added", ->
cursor1 = editor.addCursorAtBufferPosition([8, 5])
cursor2 = editor.addCursorAtBufferPosition([4, 5])
expect(editor.getCursorBufferPositions()).toEqual [[0, 0], [8, 5], [4, 5]]
describe "::getCursorScreenPositions()", ->
it "returns the cursor positions in the order they were added", ->
editor.foldBufferRow(4)
@@ -922,6 +901,22 @@ describe "Editor", ->
beforeEach ->
selection = editor.getLastSelection()
describe "when the selection range changes", ->
it "emits an event with the old range, new range, and the selection that moved", ->
editor.setSelectedBufferRange([[3, 0], [4, 5]])
editor.onDidChangeSelectionRange rangeChangedHandler = jasmine.createSpy()
editor.selectToBufferPosition([6, 2])
expect(rangeChangedHandler).toHaveBeenCalled()
eventObject = rangeChangedHandler.mostRecentCall.args[0]
expect(eventObject.oldBufferRange).toEqual [[3, 0], [4, 5]]
expect(eventObject.oldScreenRange).toEqual [[3, 0], [4, 5]]
expect(eventObject.newBufferRange).toEqual [[3, 0], [6, 2]]
expect(eventObject.newScreenRange).toEqual [[3, 0], [6, 2]]
expect(eventObject.selection).toBe selection
describe ".selectUp/Down/Left/Right()", ->
it "expands each selection to its cursor's new location", ->
editor.setSelectedBufferRanges([[[0,9], [0,13]], [[3,16], [3,21]]])
@@ -1651,7 +1646,7 @@ describe "Editor", ->
beforeEach ->
editor.setSelectedBufferRange([[1, 0], [1, 2]])
it "will-insert-text and did-insert-text events are emitted when inserting text", ->
it "replaces the selection with the given text", ->
range = editor.insertText('xxx')
expect(range).toEqual [ [[1, 0], [1, 3]] ]
expect(buffer.lineForRow(1)).toBe 'xxxvar sort = function(items) {'
@@ -1733,19 +1728,19 @@ describe "Editor", ->
editor.insertText('holy cow')
expect(editor.tokenizedLineForScreenRow(2).fold).toBeUndefined()
describe "when will-insert-text and did-insert-text events are used", ->
describe "when there are ::onWillInsertText and ::onDidInsertText observers", ->
beforeEach ->
editor.setSelectedBufferRange([[1, 0], [1, 2]])
it "will-insert-text and did-insert-text events are emitted when inserting text", ->
it "notifies the observers when inserting text", ->
willInsertSpy = jasmine.createSpy().andCallFake ->
expect(buffer.lineForRow(1)).toBe ' var sort = function(items) {'
didInsertSpy = jasmine.createSpy().andCallFake ->
expect(buffer.lineForRow(1)).toBe 'xxxvar sort = function(items) {'
editor.on('will-insert-text', willInsertSpy)
editor.on('did-insert-text', didInsertSpy)
editor.onWillInsertText(willInsertSpy)
editor.onDidInsertText(didInsertSpy)
expect(editor.insertText('xxx')).toBeTruthy()
expect(buffer.lineForRow(1)).toBe 'xxxvar sort = function(items) {'
@@ -1760,14 +1755,14 @@ describe "Editor", ->
options = didInsertSpy.mostRecentCall.args[0]
expect(options.text).toBe 'xxx'
it "text insertion is prevented when cancel is called from a will-insert-text handler", ->
it "cancels text insertion when an ::onWillInsertText observer calls cancel on an event", ->
willInsertSpy = jasmine.createSpy().andCallFake ({cancel}) ->
cancel()
didInsertSpy = jasmine.createSpy()
editor.on('will-insert-text', willInsertSpy)
editor.on('did-insert-text', didInsertSpy)
editor.onWillInsertText(willInsertSpy)
editor.onDidInsertText(didInsertSpy)
expect(editor.insertText('xxx')).toBe false
expect(buffer.lineForRow(1)).toBe ' var sort = function(items) {'
@@ -1924,7 +1919,7 @@ describe "Editor", ->
beforeEach ->
selection = editor.getLastSelection()
changeScreenRangeHandler = jasmine.createSpy('changeScreenRangeHandler')
selection.on 'screen-range-changed', changeScreenRangeHandler
selection.onDidChangeRange changeScreenRangeHandler
describe "when the cursor is on the middle of the line", ->
it "removes the character before the cursor", ->
@@ -2365,6 +2360,16 @@ describe "Editor", ->
expect(buffer.lineForRow(5)).toMatch /^\t\t\t$/
expect(editor.getCursorBufferPosition()).toEqual [5, 3]
describe "when the difference between the suggested level of indentation and the current level of indentation is greater than 0 but less than 1", ->
it "inserts one tab", ->
editor.setSoftTabs(false)
buffer.setText(" \ntest")
editor.setCursorBufferPosition [1, 0]
editor.indent(autoIndent: true)
expect(buffer.lineForRow(1)).toBe '\ttest'
expect(editor.getCursorBufferPosition()).toEqual [1, 1]
describe "when the line's indent level is greater than the suggested level of indentation", ->
describe "when 'softTabs' is true (the default)", ->
it "moves the cursor to the end of the leading whitespace and inserts 'tabLength' spaces into the buffer", ->
@@ -2422,7 +2427,7 @@ describe "Editor", ->
describe ".cutToEndOfLine()", ->
describe "when soft wrap is on", ->
it "cuts up to the end of the line", ->
editor.setSoftWrap(true)
editor.setSoftWrapped(true)
editor.setEditorWidthInChars(10)
editor.setCursorScreenPosition([2, 2])
editor.cutToEndOfLine()
@@ -2924,7 +2929,7 @@ describe "Editor", ->
describe "when soft wrap is enabled", ->
it "deletes the entire line that the cursor is on", ->
editor.setSoftWrap(true)
editor.setSoftWrapped(true)
editor.setEditorWidthInChars(10)
editor.setCursorBufferPosition([6])
@@ -3264,6 +3269,13 @@ describe "Editor", ->
editor.destroy()
expect(buffer.getMarkerCount()).toBe 0
it "notifies ::onDidDestroy observers when the editor is destroyed", ->
destroyObserverCalled = false
editor.onDidDestroy -> destroyObserverCalled = true
editor.destroy()
expect(destroyObserverCalled).toBe true
describe ".joinLines()", ->
describe "when no text is selected", ->
describe "when the line below isn't empty", ->
@@ -3378,7 +3390,7 @@ describe "Editor", ->
editor2.destroy()
expect(editor.shouldPromptToSave()).toBeTruthy()
describe "when the edit session contains surrogate pair characters", ->
describe "when the editor contains surrogate pair characters", ->
it "correctly backspaces over them", ->
editor.setText('\uD835\uDF97\uD835\uDF97\uD835\uDF97')
editor.moveToBottom()
@@ -3419,10 +3431,51 @@ describe "Editor", ->
editor.moveLeft()
expect(editor.getCursorBufferPosition()).toEqual [0, 0]
describe "when the editor contains variation sequence character pairs", ->
it "correctly backspaces over them", ->
editor.setText('\u2714\uFE0E\u2714\uFE0E\u2714\uFE0E')
editor.moveToBottom()
editor.backspace()
expect(editor.getText()).toBe '\u2714\uFE0E\u2714\uFE0E'
editor.backspace()
expect(editor.getText()).toBe '\u2714\uFE0E'
editor.backspace()
expect(editor.getText()).toBe ''
it "correctly deletes over them", ->
editor.setText('\u2714\uFE0E\u2714\uFE0E\u2714\uFE0E')
editor.moveToTop()
editor.delete()
expect(editor.getText()).toBe '\u2714\uFE0E\u2714\uFE0E'
editor.delete()
expect(editor.getText()).toBe '\u2714\uFE0E'
editor.delete()
expect(editor.getText()).toBe ''
it "correctly moves over them", ->
editor.setText('\u2714\uFE0E\u2714\uFE0E\u2714\uFE0E\n')
editor.moveToTop()
editor.moveRight()
expect(editor.getCursorBufferPosition()).toEqual [0, 2]
editor.moveRight()
expect(editor.getCursorBufferPosition()).toEqual [0, 4]
editor.moveRight()
expect(editor.getCursorBufferPosition()).toEqual [0, 6]
editor.moveRight()
expect(editor.getCursorBufferPosition()).toEqual [1, 0]
editor.moveLeft()
expect(editor.getCursorBufferPosition()).toEqual [0, 6]
editor.moveLeft()
expect(editor.getCursorBufferPosition()).toEqual [0, 4]
editor.moveLeft()
expect(editor.getCursorBufferPosition()).toEqual [0, 2]
editor.moveLeft()
expect(editor.getCursorBufferPosition()).toEqual [0, 0]
describe ".setIndentationForBufferRow", ->
describe "when the editor uses soft tabs but the row has hard tabs", ->
it "only replaces whitespace characters", ->
editor.setSoftWrap(true)
editor.setSoftWrapped(true)
editor.setText("\t1\n\t2")
editor.setCursorBufferPosition([0, 0])
editor.setIndentationForBufferRow(0, 2)
@@ -3430,7 +3483,7 @@ describe "Editor", ->
describe "when the indentation level is a non-integer", ->
it "does not throw an exception", ->
editor.setSoftWrap(true)
editor.setSoftWrapped(true)
editor.setText("\t1\n\t2")
editor.setCursorBufferPosition([0, 0])
editor.setIndentationForBufferRow(0, 2.1)
@@ -0,0 +1,4 @@
module.exports =
activate: ->
deactivate: -> throw new Error('Top that')
serialize: ->
+30 -30
Ver Arquivo
@@ -1,5 +1,5 @@
temp = require 'temp'
Git = require '../src/git'
GitRepository = require '../src/git-repository'
fs = require 'fs-plus'
path = require 'path'
Task = require '../src/task'
@@ -10,7 +10,7 @@ copyRepository = ->
fs.renameSync(path.join(workingDirPath, 'git.git'), path.join(workingDirPath, '.git'))
workingDirPath
describe "Git", ->
describe "GitRepository", ->
repo = null
beforeEach ->
@@ -22,28 +22,28 @@ describe "Git", ->
describe "@open(path)", ->
it "returns null when no repository is found", ->
expect(Git.open(path.join(temp.dir, 'nogit.txt'))).toBeNull()
expect(GitRepository.open(path.join(temp.dir, 'nogit.txt'))).toBeNull()
describe "new Git(path)", ->
describe "new GitRepository(path)", ->
it "throws an exception when no repository is found", ->
expect(-> new Git(path.join(temp.dir, 'nogit.txt'))).toThrow()
expect(-> new GitRepository(path.join(temp.dir, 'nogit.txt'))).toThrow()
describe ".getPath()", ->
it "returns the repository path for a .git directory path", ->
repo = new Git(path.join(__dirname, 'fixtures', 'git', 'master.git', 'HEAD'))
repo = new GitRepository(path.join(__dirname, 'fixtures', 'git', 'master.git', 'HEAD'))
expect(repo.getPath()).toBe path.join(__dirname, 'fixtures', 'git', 'master.git')
it "returns the repository path for a repository path", ->
repo = new Git(path.join(__dirname, 'fixtures', 'git', 'master.git'))
repo = new GitRepository(path.join(__dirname, 'fixtures', 'git', 'master.git'))
expect(repo.getPath()).toBe path.join(__dirname, 'fixtures', 'git', 'master.git')
describe ".isPathIgnored(path)", ->
it "returns true for an ignored path", ->
repo = new Git(path.join(__dirname, 'fixtures', 'git', 'ignore.git'))
repo = new GitRepository(path.join(__dirname, 'fixtures', 'git', 'ignore.git'))
expect(repo.isPathIgnored('a.txt')).toBeTruthy()
it "returns false for a non-ignored path", ->
repo = new Git(path.join(__dirname, 'fixtures', 'git', 'ignore.git'))
repo = new GitRepository(path.join(__dirname, 'fixtures', 'git', 'ignore.git'))
expect(repo.isPathIgnored('b.txt')).toBeFalsy()
describe ".isPathModified(path)", ->
@@ -51,7 +51,7 @@ describe "Git", ->
beforeEach ->
workingDirPath = copyRepository()
repo = new Git(workingDirPath)
repo = new GitRepository(workingDirPath)
filePath = path.join(workingDirPath, 'a.txt')
newPath = path.join(workingDirPath, 'new-path.txt')
@@ -75,7 +75,7 @@ describe "Git", ->
beforeEach ->
workingDirPath = copyRepository()
repo = new Git(workingDirPath)
repo = new GitRepository(workingDirPath)
filePath = path.join(workingDirPath, 'a.txt')
newPath = path.join(workingDirPath, 'new-path.txt')
fs.writeFileSync(newPath, "i'm new here")
@@ -92,7 +92,7 @@ describe "Git", ->
beforeEach ->
workingDirPath = copyRepository()
repo = new Git(workingDirPath)
repo = new GitRepository(workingDirPath)
filePath = path.join(workingDirPath, 'a.txt')
it "no longer reports a path as modified after checkout", ->
@@ -111,10 +111,10 @@ describe "Git", ->
fs.writeFileSync(filePath, 'ch ch changes')
repo.getPathStatus(filePath)
statusHandler = jasmine.createSpy('statusHandler')
repo.on 'status-changed', statusHandler
repo.onDidChangeStatus statusHandler
repo.checkoutHead(filePath)
expect(statusHandler.callCount).toBe 1
expect(statusHandler.argsForCall[0][0..1]).toEqual [filePath, 0]
expect(statusHandler.argsForCall[0][0]).toEqual {path: filePath, pathStatus: 0}
repo.checkoutHead(filePath)
expect(statusHandler.callCount).toBe 1
@@ -124,7 +124,7 @@ describe "Git", ->
beforeEach ->
workingDirPath = copyRepository()
repo = new Git(workingDirPath)
repo = new GitRepository(workingDirPath)
filePath = path.join(workingDirPath, 'a.txt')
fs.writeFileSync(filePath, 'ch ch changes')
@@ -153,7 +153,7 @@ describe "Git", ->
describe ".destroy()", ->
it "throws an exception when any method is called after it is called", ->
repo = new Git(require.resolve('./fixtures/git/master.git/HEAD'))
repo = new GitRepository(require.resolve('./fixtures/git/master.git/HEAD'))
repo.destroy()
expect(-> repo.getShortHead()).toThrow()
@@ -162,16 +162,16 @@ describe "Git", ->
beforeEach ->
workingDirectory = copyRepository()
repo = new Git(workingDirectory)
repo = new GitRepository(workingDirectory)
filePath = path.join(workingDirectory, 'file.txt')
it "trigger a status-changed event when the new status differs from the last cached one", ->
statusHandler = jasmine.createSpy("statusHandler")
repo.on 'status-changed', statusHandler
repo.onDidChangeStatus statusHandler
fs.writeFileSync(filePath, '')
status = repo.getPathStatus(filePath)
expect(statusHandler.callCount).toBe 1
expect(statusHandler.argsForCall[0][0..1]).toEqual [filePath, status]
expect(statusHandler.argsForCall[0][0]).toEqual {path: filePath, pathStatus: status}
fs.writeFileSync(filePath, 'abc')
status = repo.getPathStatus(filePath)
@@ -182,7 +182,7 @@ describe "Git", ->
beforeEach ->
workingDirectory = copyRepository()
repo = new Git(workingDirectory)
repo = new GitRepository(workingDirectory)
directoryPath = path.join(workingDirectory, 'dir')
filePath = path.join(directoryPath, 'b.txt')
@@ -197,7 +197,7 @@ describe "Git", ->
beforeEach ->
workingDirectory = copyRepository()
repo = new Git(workingDirectory)
repo = new GitRepository(workingDirectory)
modifiedPath = path.join(workingDirectory, 'file.txt')
newPath = path.join(workingDirectory, 'untracked.txt')
cleanPath = path.join(workingDirectory, 'other.txt')
@@ -208,7 +208,7 @@ describe "Git", ->
it "returns status information for all new and modified files", ->
fs.writeFileSync(modifiedPath, 'making this path modified')
statusHandler = jasmine.createSpy('statusHandler')
repo.on 'statuses-changed', statusHandler
repo.onDidChangeStatuses statusHandler
repo.refreshStatus()
waitsFor ->
@@ -232,19 +232,19 @@ describe "Git", ->
editor.insertNewline()
statusHandler = jasmine.createSpy('statusHandler')
atom.project.getRepo().on 'status-changed', statusHandler
atom.project.getRepo().onDidChangeStatus statusHandler
editor.save()
expect(statusHandler.callCount).toBe 1
expect(statusHandler).toHaveBeenCalledWith editor.getPath(), 256
expect(statusHandler).toHaveBeenCalledWith {path: editor.getPath(), pathStatus: 256}
it "emits a status-changed event when a buffer is reloaded", ->
fs.writeFileSync(editor.getPath(), 'changed')
statusHandler = jasmine.createSpy('statusHandler')
atom.project.getRepo().on 'status-changed', statusHandler
atom.project.getRepo().onDidChangeStatus statusHandler
editor.getBuffer().reload()
expect(statusHandler.callCount).toBe 1
expect(statusHandler).toHaveBeenCalledWith editor.getPath(), 256
expect(statusHandler).toHaveBeenCalledWith {path: editor.getPath(), pathStatus: 256}
editor.getBuffer().reload()
expect(statusHandler.callCount).toBe 1
@@ -252,10 +252,10 @@ describe "Git", ->
fs.writeFileSync(editor.getPath(), 'changed')
statusHandler = jasmine.createSpy('statusHandler')
atom.project.getRepo().on 'status-changed', statusHandler
atom.project.getRepo().onDidChangeStatus statusHandler
editor.getBuffer().emitter.emit 'did-change-path'
expect(statusHandler.callCount).toBe 1
expect(statusHandler).toHaveBeenCalledWith editor.getPath(), 256
expect(statusHandler).toHaveBeenCalledWith {path: editor.getPath(), pathStatus: 256}
editor.getBuffer().emitter.emit 'did-change-path'
expect(statusHandler.callCount).toBe 1
@@ -283,7 +283,7 @@ describe "Git", ->
buffer.append('changes')
statusHandler = jasmine.createSpy('statusHandler')
project2.getRepo().on 'status-changed', statusHandler
project2.getRepo().onDidChangeStatus statusHandler
buffer.save()
expect(statusHandler.callCount).toBe 1
expect(statusHandler).toHaveBeenCalledWith buffer.getPath(), 256
expect(statusHandler).toHaveBeenCalledWith {path: buffer.getPath(), pathStatus: 256}
+9
Ver Arquivo
@@ -7,6 +7,8 @@ module.exports.runSpecSuite = (specSuite, logFile, logErrors=true) ->
{TerminalReporter} = require 'jasmine-tagged'
disableFocusMethods() if process.env.JANKY_SHA1
TimeReporter = require './time-reporter'
timeReporter = new TimeReporter()
@@ -38,3 +40,10 @@ module.exports.runSpecSuite = (specSuite, logFile, logErrors=true) ->
$('body').append $$ -> @div id: 'jasmine-content'
jasmineEnv.execute()
disableFocusMethods = ->
['fdescribe', 'ffdescribe', 'fffdescribe', 'fit', 'ffit', 'fffit'].forEach (methodName) ->
focusMethod = window[methodName]
window[methodName] = (description) ->
error = new Error('Focused spec is running on CI')
focusMethod description, -> throw error
+22
Ver Arquivo
@@ -70,6 +70,28 @@ describe "LanguageMode", ->
expect(languageMode.rowRangeForCodeFoldAtBufferRow(2)).toBeNull()
expect(languageMode.rowRangeForCodeFoldAtBufferRow(4)).toEqual [4, 7]
describe ".rowRangeForCommentAtBufferRow(bufferRow)", ->
it "returns the start/end rows of the foldable comment starting at the given row", ->
buffer.setText("//this is a multi line comment\n//another line")
expect(languageMode.rowRangeForCommentAtBufferRow(0)).toEqual [0, 1]
expect(languageMode.rowRangeForCommentAtBufferRow(1)).toEqual [0, 1]
buffer.setText("//this is a multi line comment\n//another line\n//and one more")
expect(languageMode.rowRangeForCommentAtBufferRow(0)).toEqual [0, 2]
expect(languageMode.rowRangeForCommentAtBufferRow(1)).toEqual [0, 2]
buffer.setText("//this is a multi line comment\n\n//with an empty line")
expect(languageMode.rowRangeForCommentAtBufferRow(0)).toBeUndefined()
expect(languageMode.rowRangeForCommentAtBufferRow(1)).toBeUndefined()
expect(languageMode.rowRangeForCommentAtBufferRow(2)).toBeUndefined()
buffer.setText("//this is a single line comment\n")
expect(languageMode.rowRangeForCommentAtBufferRow(0)).toBeUndefined()
expect(languageMode.rowRangeForCommentAtBufferRow(1)).toBeUndefined()
buffer.setText("//this is a single line comment")
expect(languageMode.rowRangeForCommentAtBufferRow(0)).toBeUndefined()
describe "suggestedIndentForBufferRow", ->
it "returns the suggested indentation based on auto-indent/outdent rules", ->
expect(languageMode.suggestedIndentForBufferRow(0)).toBe 0
+1 -1
Ver Arquivo
@@ -102,6 +102,6 @@ describe "Package", ->
theme.activate()
it "deactivated event fires on .deactivate()", ->
theme.on 'deactivated', spy = jasmine.createSpy()
theme.onDidDeactivate spy = jasmine.createSpy()
theme.deactivate()
expect(spy).toHaveBeenCalled()
+43 -12
Ver Arquivo
@@ -1,6 +1,7 @@
PaneContainerView = require '../src/pane-container-view'
PaneView = require '../src/pane-view'
fs = require 'fs-plus'
{Emitter} = require 'event-kit'
{$, View} = require 'atom'
path = require 'path'
temp = require 'temp'
@@ -12,9 +13,14 @@ describe "PaneView", ->
@deserialize: ({id, text}) -> new TestView({id, text})
@content: ({id, text}) -> @div class: 'test-view', id: id, tabindex: -1, text
initialize: ({@id, @text}) ->
@emitter = new Emitter
serialize: -> { deserializer: 'TestView', @id, @text }
getUri: -> @id
isEqual: (other) -> other? and @id == other.id and @text == other.text
changeTitle: ->
@emitter.emit 'did-change-title', 'title'
onDidChangeTitle: (callback) ->
@emitter.on 'did-change-title', callback
beforeEach ->
atom.deserializers.add(TestView)
@@ -145,22 +151,47 @@ describe "PaneView", ->
expect(view1.data('preservative')).toBe 1234
describe "when the title of the active item changes", ->
it "emits pane:active-item-title-changed", ->
activeItemTitleChangedHandler = jasmine.createSpy("activeItemTitleChangedHandler")
pane.on 'pane:active-item-title-changed', activeItemTitleChangedHandler
describe 'when there is no onDidChangeTitle method', ->
beforeEach ->
view1.onDidChangeTitle = null
view2.onDidChangeTitle = null
expect(pane.getActiveItem()).toBe view1
pane.activateItem(view2)
pane.activateItem(view1)
view2.trigger 'title-changed'
expect(activeItemTitleChangedHandler).not.toHaveBeenCalled()
it "emits pane:active-item-title-changed", ->
activeItemTitleChangedHandler = jasmine.createSpy("activeItemTitleChangedHandler")
pane.on 'pane:active-item-title-changed', activeItemTitleChangedHandler
view1.trigger 'title-changed'
expect(activeItemTitleChangedHandler).toHaveBeenCalled()
activeItemTitleChangedHandler.reset()
expect(pane.getActiveItem()).toBe view1
pane.activateItem(view2)
view2.trigger 'title-changed'
expect(activeItemTitleChangedHandler).toHaveBeenCalled()
view2.trigger 'title-changed'
expect(activeItemTitleChangedHandler).not.toHaveBeenCalled()
view1.trigger 'title-changed'
expect(activeItemTitleChangedHandler).toHaveBeenCalled()
activeItemTitleChangedHandler.reset()
pane.activateItem(view2)
view2.trigger 'title-changed'
expect(activeItemTitleChangedHandler).toHaveBeenCalled()
describe 'when there is a onDidChangeTitle method', ->
it "emits pane:active-item-title-changed", ->
activeItemTitleChangedHandler = jasmine.createSpy("activeItemTitleChangedHandler")
pane.on 'pane:active-item-title-changed', activeItemTitleChangedHandler
expect(pane.getActiveItem()).toBe view1
view2.changeTitle()
expect(activeItemTitleChangedHandler).not.toHaveBeenCalled()
view1.changeTitle()
expect(activeItemTitleChangedHandler).toHaveBeenCalled()
activeItemTitleChangedHandler.reset()
pane.activateItem(view2)
view2.changeTitle()
expect(activeItemTitleChangedHandler).toHaveBeenCalled()
describe "when an unmodifed buffer's path is deleted", ->
it "removes the pane item", ->
+4 -4
Ver Arquivo
@@ -50,9 +50,9 @@ describe "Editor", ->
randomlyMutateEditor = ->
if Math.random() < .2
softWrap = not editor.getSoftWrap()
steps.push(['setSoftWrap', softWrap])
editor.setSoftWrap(softWrap)
softWrapped = not editor.isSoftWrapped()
steps.push(['setSoftWrapped', softWrapped])
editor.setSoftWrapped(softWrapped)
else
range = getRandomRange()
text = getRandomText()
@@ -79,7 +79,7 @@ describe "Editor", ->
text
getReferenceScreenLines = ->
if editor.getSoftWrap()
if editor.isSoftWrapped()
screenLines = []
bufferRows = []
for bufferRow in [0..tokenizedBuffer.getLastRow()]
+2 -2
Ver Arquivo
@@ -57,10 +57,10 @@ describe "Selection", ->
expect(selection.isReversed()).toBeFalsy()
describe "when only the selection's tail is moved (regression)", ->
it "emits the 'screen-range-changed' event", ->
it "notifies ::onDidChangeRange observers", ->
selection.setBufferRange([[2, 0], [2, 10]], reversed: true)
changeScreenRangeHandler = jasmine.createSpy('changeScreenRangeHandler')
selection.on 'screen-range-changed', changeScreenRangeHandler
selection.onDidChangeRange changeScreenRangeHandler
buffer.insert([2, 5], 'abc')
expect(changeScreenRangeHandler).toHaveBeenCalled()
+5 -1
Ver Arquivo
@@ -21,6 +21,7 @@ clipboard = require 'clipboard'
atom.themes.loadBaseStylesheets()
atom.themes.requireStylesheet '../static/jasmine'
atom.themes.initialLoadComplete = true
fixturePackagesPath = path.resolve(__dirname, './fixtures/packages')
atom.packages.packageDirPaths.unshift(fixturePackagesPath)
@@ -63,6 +64,7 @@ beforeEach ->
atom.project = new Project(path: projectPath)
atom.workspace = new Workspace()
atom.keymaps.keyBindings = _.clone(keyBindingsToRestore)
atom.commands.setRootNode(document.body)
window.resetTimeouts()
atom.packages.packageStates = {}
@@ -119,6 +121,8 @@ beforeEach ->
addCustomMatchers(this)
afterEach ->
atom.commands.clear()
atom.packages.deactivatePackages()
atom.menu.template = []
@@ -137,7 +141,7 @@ afterEach ->
jasmine.unspy(atom, 'saveSync')
ensureNoPathSubscriptions()
atom.syntax.off()
atom.syntax.clearObservers()
waits(0) # yield to ui thread to make screen update more frequently
ensureNoPathSubscriptions = ->
+28 -26
Ver Arquivo
@@ -1,30 +1,32 @@
textUtils = require '../src/text-utils'
describe 'text utilities', ->
describe '.getCharacterCount(string)', ->
it 'returns the number of full characters in the string', ->
expect(textUtils.getCharacterCount('abc')).toBe 3
expect(textUtils.getCharacterCount('a\uD835\uDF97b\uD835\uDF97c')).toBe 5
expect(textUtils.getCharacterCount('\uD835\uDF97')).toBe 1
expect(textUtils.getCharacterCount('\uD835')).toBe 1
expect(textUtils.getCharacterCount('\uDF97')).toBe 1
describe '.hasPairedCharacter(string)', ->
it 'returns true when the string contains a surrogate pair or variation sequence', ->
expect(textUtils.hasPairedCharacter('abc')).toBe false
expect(textUtils.hasPairedCharacter('a\uD835\uDF97b\uD835\uDF97c')).toBe true
expect(textUtils.hasPairedCharacter('\uD835\uDF97')).toBe true
expect(textUtils.hasPairedCharacter('\u2714\uFE0E')).toBe true
expect(textUtils.hasPairedCharacter('\uD835')).toBe false
expect(textUtils.hasPairedCharacter('\uDF97')).toBe false
expect(textUtils.hasPairedCharacter('\uFE0E')).toBe false
expect(textUtils.hasPairedCharacter('\uFE0E\uFE0E')).toBe false
describe '.hasSurrogatePair(string)', ->
it 'returns true when the string contains a surrogate pair', ->
expect(textUtils.hasSurrogatePair('abc')).toBe false
expect(textUtils.hasSurrogatePair('a\uD835\uDF97b\uD835\uDF97c')).toBe true
expect(textUtils.hasSurrogatePair('\uD835\uDF97')).toBe true
expect(textUtils.hasSurrogatePair('\uD835')).toBe false
expect(textUtils.hasSurrogatePair('\uDF97')).toBe false
describe '.isSurrogatePair(string, index)', ->
it 'returns true when the index is the start of a high/low surrogate pair', ->
expect(textUtils.isSurrogatePair('a\uD835\uDF97b\uD835\uDF97c', 0)).toBe false
expect(textUtils.isSurrogatePair('a\uD835\uDF97b\uD835\uDF97c', 1)).toBe true
expect(textUtils.isSurrogatePair('a\uD835\uDF97b\uD835\uDF97c', 2)).toBe false
expect(textUtils.isSurrogatePair('a\uD835\uDF97b\uD835\uDF97c', 3)).toBe false
expect(textUtils.isSurrogatePair('a\uD835\uDF97b\uD835\uDF97c', 4)).toBe true
expect(textUtils.isSurrogatePair('a\uD835\uDF97b\uD835\uDF97c', 5)).toBe false
expect(textUtils.isSurrogatePair('a\uD835\uDF97b\uD835\uDF97c', 6)).toBe false
expect(textUtils.isSurrogatePair('\uD835')).toBe false
expect(textUtils.isSurrogatePair('\uDF97')).toBe false
describe '.isPairedCharacter(string, index)', ->
it 'returns true when the index is the start of a high/low surrogate pair or variation sequence', ->
expect(textUtils.isPairedCharacter('a\uD835\uDF97b\uD835\uDF97c', 0)).toBe false
expect(textUtils.isPairedCharacter('a\uD835\uDF97b\uD835\uDF97c', 1)).toBe true
expect(textUtils.isPairedCharacter('a\uD835\uDF97b\uD835\uDF97c', 2)).toBe false
expect(textUtils.isPairedCharacter('a\uD835\uDF97b\uD835\uDF97c', 3)).toBe false
expect(textUtils.isPairedCharacter('a\uD835\uDF97b\uD835\uDF97c', 4)).toBe true
expect(textUtils.isPairedCharacter('a\uD835\uDF97b\uD835\uDF97c', 5)).toBe false
expect(textUtils.isPairedCharacter('a\uD835\uDF97b\uD835\uDF97c', 6)).toBe false
expect(textUtils.isPairedCharacter('a\u2714\uFE0E', 0)).toBe false
expect(textUtils.isPairedCharacter('a\u2714\uFE0E', 1)).toBe true
expect(textUtils.isPairedCharacter('a\u2714\uFE0E', 2)).toBe false
expect(textUtils.isPairedCharacter('a\u2714\uFE0E', 3)).toBe false
expect(textUtils.isPairedCharacter('\uD835')).toBe false
expect(textUtils.isPairedCharacter('\uDF97')).toBe false
expect(textUtils.isPairedCharacter('\uFE0E')).toBe false
expect(textUtils.isPairedCharacter('\uFE0E')).toBe false
expect(textUtils.isPairedCharacter('\uFE0E\uFE0E')).toBe false
+14 -12
Ver Arquivo
@@ -69,7 +69,7 @@ describe "ThemeManager", ->
describe "when the core.themes config value changes", ->
it "add/removes stylesheets to reflect the new config value", ->
themeManager.on 'reloaded', reloadHandler = jasmine.createSpy()
themeManager.onDidReloadAll reloadHandler = jasmine.createSpy()
spyOn(themeManager, 'getUserStylesheetPath').andCallFake -> null
waitsForPromise ->
@@ -131,8 +131,8 @@ describe "ThemeManager", ->
describe "requireStylesheet(path)", ->
it "synchronously loads css at the given path and installs a style tag for it in the head", ->
themeManager.on 'stylesheets-changed', stylesheetsChangedHandler = jasmine.createSpy("stylesheetsChangedHandler")
themeManager.on 'stylesheet-added', stylesheetAddedHandler = jasmine.createSpy("stylesheetAddedHandler")
themeManager.onDidChangeStylesheets stylesheetsChangedHandler = jasmine.createSpy("stylesheetsChangedHandler")
themeManager.onDidAddStylesheet stylesheetAddedHandler = jasmine.createSpy("stylesheetAddedHandler")
cssPath = atom.project.resolve('css.css')
lengthBefore = $('head style').length
@@ -193,8 +193,8 @@ describe "ThemeManager", ->
themeManager.requireStylesheet(cssPath)
expect($(document.body).css('font-weight')).toBe("bold")
themeManager.on 'stylesheet-removed', stylesheetRemovedHandler = jasmine.createSpy("stylesheetRemovedHandler")
themeManager.on 'stylesheets-changed', stylesheetsChangedHandler = jasmine.createSpy("stylesheetsChangedHandler")
themeManager.onDidRemoveStylesheet stylesheetRemovedHandler = jasmine.createSpy("stylesheetRemovedHandler")
themeManager.onDidChangeStylesheets stylesheetsChangedHandler = jasmine.createSpy("stylesheetsChangedHandler")
themeManager.removeStylesheet(cssPath)
@@ -217,7 +217,7 @@ describe "ThemeManager", ->
themeManager.activateThemes()
it "loads the correct values from the theme's ui-variables file", ->
themeManager.on 'reloaded', reloadHandler = jasmine.createSpy()
themeManager.onDidReloadAll reloadHandler = jasmine.createSpy()
atom.config.set('core.themes', ['theme-with-ui-variables'])
waitsFor ->
@@ -234,7 +234,7 @@ describe "ThemeManager", ->
describe "when there is a theme with incomplete variables", ->
it "loads the correct values from the fallback ui-variables", ->
themeManager.on 'reloaded', reloadHandler = jasmine.createSpy()
themeManager.onDidReloadAll reloadHandler = jasmine.createSpy()
atom.config.set('core.themes', ['theme-with-incomplete-ui-variables'])
waitsFor ->
@@ -251,7 +251,7 @@ describe "ThemeManager", ->
it 'adds theme-* classes to the workspace for each active theme', ->
expect(atom.workspaceView).toHaveClass 'theme-atom-dark-ui'
themeManager.on 'reloaded', reloadHandler = jasmine.createSpy()
themeManager.onDidReloadAll reloadHandler = jasmine.createSpy()
atom.config.set('core.themes', ['theme-with-ui-variables'])
waitsFor ->
@@ -273,9 +273,9 @@ describe "ThemeManager", ->
themeManager.activateThemes()
runs ->
themeManager.on 'stylesheets-changed', stylesheetsChangedHandler = jasmine.createSpy("stylesheetsChangedHandler")
themeManager.on 'stylesheet-removed', stylesheetRemovedHandler = jasmine.createSpy("stylesheetRemovedHandler")
themeManager.on 'stylesheet-added', stylesheetAddedHandler = jasmine.createSpy("stylesheetAddedHandler")
themeManager.onDidChangeStylesheets stylesheetsChangedHandler = jasmine.createSpy("stylesheetsChangedHandler")
themeManager.onDidRemoveStylesheet stylesheetRemovedHandler = jasmine.createSpy("stylesheetRemovedHandler")
themeManager.onDidAddStylesheet stylesheetAddedHandler = jasmine.createSpy("stylesheetAddedHandler")
spyOn(themeManager, 'loadUserStylesheet').andCallThrough()
expect($(document.body).css('border-style')).toBe 'dotted'
@@ -316,7 +316,9 @@ describe "ThemeManager", ->
themeManager.activateThemes()
runs ->
themeManager.once 'reloaded', -> reloaded = true
disposable = themeManager.onDidReloadAll ->
disposable.dispose()
reloaded = true
spyOn(console, 'warn')
expect(-> atom.config.set('core.themes', ['atom-light-ui', 'theme-really-does-not-exist'])).not.toThrow()
+6 -6
Ver Arquivo
@@ -41,7 +41,7 @@ describe "TokenizedBuffer", ->
buffer = atom.project.bufferForPathSync('sample.js')
tokenizedBuffer = new TokenizedBuffer({buffer})
startTokenizing(tokenizedBuffer)
tokenizedBuffer.on "changed", changeHandler = jasmine.createSpy('changeHandler')
tokenizedBuffer.onDidChange changeHandler = jasmine.createSpy('changeHandler')
afterEach ->
tokenizedBuffer.destroy()
@@ -468,7 +468,7 @@ describe "TokenizedBuffer", ->
runs ->
tokenizedBuffer = editor.displayBuffer.tokenizedBuffer
tokenizedBuffer.on 'tokenized', tokenizedHandler
tokenizedBuffer.onDidTokenize tokenizedHandler
fullyTokenize(tokenizedBuffer)
expect(tokenizedHandler.callCount).toBe(1)
@@ -483,7 +483,7 @@ describe "TokenizedBuffer", ->
tokenizedBuffer = editor.displayBuffer.tokenizedBuffer
fullyTokenize(tokenizedBuffer)
tokenizedBuffer.on 'tokenized', tokenizedHandler
tokenizedBuffer.onDidTokenize tokenizedHandler
editor.getBuffer().insert([0, 0], "'")
fullyTokenize(tokenizedBuffer)
expect(tokenizedHandler).not.toHaveBeenCalled()
@@ -499,7 +499,7 @@ describe "TokenizedBuffer", ->
runs ->
tokenizedBuffer = editor.displayBuffer.tokenizedBuffer
tokenizedBuffer.on 'tokenized', tokenizedHandler
tokenizedBuffer.onDidTokenize tokenizedHandler
fullyTokenize(tokenizedBuffer)
tokenizedHandler.reset()
@@ -753,7 +753,7 @@ describe "TokenizedBuffer", ->
expect(tokenizedBuffer.tokenizedLineForRow(10).indentLevel).toBe 3
expect(tokenizedBuffer.tokenizedLineForRow(11).indentLevel).toBe 2
tokenizedBuffer.on "changed", changeHandler = jasmine.createSpy('changeHandler')
tokenizedBuffer.onDidChange changeHandler = jasmine.createSpy('changeHandler')
buffer.setTextInRange([[7, 0], [8, 65]], ' one\n two\n three\n four')
@@ -771,7 +771,7 @@ describe "TokenizedBuffer", ->
buffer.insert([7, 0], '\n\n')
buffer.insert([5, 0], '\n\n')
tokenizedBuffer.on "changed", changeHandler = jasmine.createSpy('changeHandler')
tokenizedBuffer.onDidChange changeHandler = jasmine.createSpy('changeHandler')
buffer.setTextInRange([[7, 0], [8, 65]], ' ok')
+32
Ver Arquivo
@@ -256,3 +256,35 @@ describe "Window", ->
elements.trigger "core:focus-previous"
expect(elements.find("[tabindex=1]:focus")).toExist()
describe "the window:open-path event", ->
beforeEach ->
spyOn(atom.workspace, 'open')
describe "when the project does not have a path", ->
beforeEach ->
atom.project.setPath()
describe "when the opened path exists", ->
it "sets the project path to the opened path", ->
$(window).trigger('window:open-path', [{pathToOpen: __filename}])
expect(atom.project.getPath()).toBe __dirname
describe "when the opened path does not exist but its parent directory does", ->
it "sets the project path to the opened path's parent directory", ->
$(window).trigger('window:open-path', [{pathToOpen: path.join(__dirname, 'this-path-does-not-exist.txt')}])
expect(atom.project.getPath()).toBe __dirname
describe "when the opened path is a file", ->
it "opens it in the workspace", ->
$(window).trigger('window:open-path', [{pathToOpen: __filename}])
expect(atom.workspace.open.mostRecentCall.args[0]).toBe __filename
describe "when the opened path is a directory", ->
it "does not open it in the workspace", ->
$(window).trigger('window:open-path', [{pathToOpen: __dirname}])
expect(atom.workspace.open.callCount).toBe 0
+11 -8
Ver Arquivo
@@ -42,7 +42,7 @@ describe "WorkspaceView", ->
runs ->
editorView1 = atom.workspaceView.getActiveView()
buffer = editorView1.getEditor().getBuffer()
editorView1.splitRight()
editorView1.getPaneView().getModel().splitRight(copyActiveItem: true)
expect(atom.workspaceView.getActivePaneView()).toBe atom.workspaceView.getPaneViews()[1]
simulateReload()
@@ -196,7 +196,8 @@ describe "WorkspaceView", ->
atom.workspaceView.attachToDom()
rightEditorView = atom.workspaceView.getActiveView()
rightEditorView.getEditor().setText("\t \n")
leftEditorView = rightEditorView.splitLeft()
rightEditorView.getPaneView().getModel().splitLeft(copyActiveItem: true)
leftEditorView = atom.workspaceView.getActiveView()
expect(rightEditorView.find(".line:first").text()).toBe " "
expect(leftEditorView.find(".line:first").text()).toBe " "
@@ -207,14 +208,16 @@ describe "WorkspaceView", ->
expect(rightEditorView.find(".line:first").text()).toBe withInvisiblesShowing
expect(leftEditorView.find(".line:first").text()).toBe withInvisiblesShowing
lowerLeftEditorView = leftEditorView.splitDown()
leftEditorView.getPaneView().getModel().splitDown(copyActiveItem: true)
lowerLeftEditorView = atom.workspaceView.getActiveView()
expect(lowerLeftEditorView.find(".line:first").text()).toBe withInvisiblesShowing
atom.workspaceView.trigger "window:toggle-invisibles"
expect(rightEditorView.find(".line:first").text()).toBe " "
expect(leftEditorView.find(".line:first").text()).toBe " "
lowerRightEditorView = rightEditorView.splitDown()
rightEditorView.getPaneView().getModel().splitDown(copyActiveItem: true)
lowerRightEditorView = atom.workspaceView.getActiveView()
expect(lowerRightEditorView.find(".line:first").text()).toBe " "
describe ".eachEditorView(callback)", ->
@@ -241,7 +244,7 @@ describe "WorkspaceView", ->
atom.workspaceView.eachEditorView(callback)
count = 0
callbackEditor = null
atom.workspaceView.getActiveView().splitRight()
atom.workspaceView.getActiveView().getPaneView().getModel().splitRight(copyActiveItem: true)
expect(count).toBe 1
expect(callbackEditor).toBe atom.workspaceView.getActiveView()
@@ -259,10 +262,10 @@ describe "WorkspaceView", ->
subscription = atom.workspaceView.eachEditorView(callback)
expect(count).toBe 1
atom.workspaceView.getActiveView().splitRight()
atom.workspaceView.getActiveView().getPaneView().getModel().splitRight(copyActiveItem: true)
expect(count).toBe 2
subscription.off()
atom.workspaceView.getActiveView().splitRight()
atom.workspaceView.getActiveView().getPaneView().getModel().splitRight(copyActiveItem: true)
expect(count).toBe 2
describe "core:close", ->
@@ -271,7 +274,7 @@ describe "WorkspaceView", ->
paneView1 = atom.workspaceView.getActivePaneView()
editorView = atom.workspaceView.getActiveView()
editorView.splitRight()
editorView.getPaneView().getModel().splitRight(copyActiveItem: true)
paneView2 = atom.workspaceView.getActivePaneView()
expect(paneView1).not.toBe paneView2
+274 -210
Ver Arquivo
@@ -7,21 +7,22 @@ screen = require 'screen'
shell = require 'shell'
_ = require 'underscore-plus'
{deprecated} = require 'grim'
{deprecate} = require 'grim'
{Emitter} = require 'event-kit'
{Model} = require 'theorist'
fs = require 'fs-plus'
{$} = require './space-pen-extensions'
WindowEventHandler = require './window-event-handler'
# Public: Atom global for dealing with packages, themes, menus, and the window.
# Essential: Atom global for dealing with packages, themes, menus, and the window.
#
# An instance of this class is always available as the `atom` global.
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.
# Load or create the Atom environment in the given mode.
#
# * `mode` A {String} mode that is either 'editor' or 'spec' depending on the
# kind of environment you want to build.
@@ -98,26 +99,27 @@ class Atom extends Model
workspaceViewParentSelector: 'body'
lastUncaughtError: null
# Public: A {Clipboard} instance
clipboard: null
###
Section: Properties
###
# Public: A {CommandRegistry} instance
commands: null
# Public: A {Config} instance
config: null
# Public: A {Clipboard} instance
clipboard: 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 {KeymapManager} instance
keymaps: null
# Public: A {Project} instance
project: null
@@ -125,22 +127,33 @@ class Atom extends Model
# Public: A {Syntax} instance
syntax: null
# Public: A {PackageManager} instance
packages: null
# Public: A {ThemeManager} instance
themes: null
# Public: A {DeserializerManager} instance
deserializers: null
# Public: A {Workspace} instance
workspace: null
# Public: A {WorkspaceView} instance
workspaceView: null
###
Section: Construction and Destruction
###
# Call .loadOrCreate instead
constructor: (@state) ->
@emitter = new Emitter
{@mode} = @state
DeserializerManager = require './deserializer-manager'
@deserializers = new DeserializerManager()
# Public: Sets up the basic services that should be available in all modes
# 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.
@@ -158,6 +171,7 @@ class Atom extends Model
Config = require './config'
KeymapManager = require './keymap-extensions'
CommandRegistry = require './command-registry'
PackageManager = require './package-manager'
Clipboard = require './clipboard'
Syntax = require './syntax'
@@ -179,6 +193,7 @@ class Atom extends Model
@config = new Config({configDirPath, resourcePath})
@keymaps = new KeymapManager({configDirPath, resourcePath})
@keymap = @keymaps # Deprecated
@commands = new CommandRegistry
@packages = new PackageManager({devMode, configDirPath, resourcePath, safeMode})
@themes = new ThemeManager({packageManager: @packages, configDirPath, resourcePath, safeMode})
@contextMenu = new ContextMenuManager({resourcePath, devMode})
@@ -187,7 +202,7 @@ class Atom extends Model
@syntax = @deserializers.deserialize(@state.syntax) ? new Syntax()
@subscribe @packages, 'activated', => @watchThemes()
@subscribe @packages.onDidActivateAll => @watchThemes()
Project = require './project'
TextBuffer = require 'text-buffer'
@@ -198,22 +213,172 @@ class Atom extends Model
@windowEventHandler = new WindowEventHandler
# Deprecated: Callers should be converted to use atom.deserializers
registerRepresentationClass: ->
deprecated("Callers should be converted to use atom.deserializers")
###
Section: Event Subscription
###
# Deprecated: Callers should be converted to use atom.deserializers
registerRepresentationClasses: ->
deprecated("Callers should be converted to use atom.deserializers")
# Extended: Invoke the given callback whenever {::beep} is called.
#
# * `callback` {Function} to be called whenever {::beep} is called.
#
# Returns a {Disposable} on which `.dispose()` can be called to unsubscribe.
onDidBeep: (callback) ->
@emitter.on 'did-beep', callback
setBodyPlatformClass: ->
document.body.classList.add("platform-#{process.platform}")
###
Section: Atom Details
###
# Public: Get the current window
# Public: Is the current window in development mode?
inDevMode: ->
@getLoadSettings().devMode
# Public: Is the current window running specs?
inSpecMode: ->
@getLoadSettings().isSpec
# Public: Get the version of the Atom application.
#
# Returns the version text {String}.
getVersion: ->
@appVersion ?= @getLoadSettings().appVersion
# Public: Determine whether the current version is an official release.
isReleasedVersion: ->
not /\w{7}/.test(@getVersion()) # Check if the release is a 7-character SHA prefix
# Public: Get the directory path to Atom's configuration area.
#
# Returns the absolute path to `~/.atom`.
getConfigDirPath: ->
@constructor.getConfigDirPath()
# Public: Get the time taken to completely load the current window.
#
# 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
# if the window hasn't finished loading yet.
getWindowLoadTime: ->
@loadTime
# Public: Get the load settings for the current window.
#
# Returns an {Object} containing all the load setting key/value pairs.
getLoadSettings: ->
@constructor.getLoadSettings()
###
Section: Managing The Atom Window
###
# Essential: Open a new Atom window using the given options.
#
# 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.
open: (options) ->
ipc.send('open', options)
# Essential: Close the current window.
close: ->
@getCurrentWindow().close()
# Essential: Get the size of current window.
#
# Returns an {Object} in the format `{width: 1000, height: 700}`
getSize: ->
[width, height] = @getCurrentWindow().getSize()
{width, height}
# Essential: Set the size of current window.
#
# * `width` The {Number} of pixels.
# * `height` The {Number} of pixels.
setSize: (width, height) ->
@getCurrentWindow().setSize(width, height)
# Essential: Get the position of current window.
#
# Returns an {Object} in the format `{x: 10, y: 20}`
getPosition: ->
[x, y] = @getCurrentWindow().getPosition()
{x, y}
# Essential: Set the position of current window.
#
# * `x` The {Number} of pixels.
# * `y` The {Number} of pixels.
setPosition: (x, y) ->
ipc.send('call-window-method', 'setPosition', x, y)
# Extended: Get the current window
getCurrentWindow: ->
@constructor.getCurrentWindow()
# Public: Get the dimensions of this window.
# Extended: Move current window to the center of the screen.
center: ->
ipc.send('call-window-method', 'center')
# Extended: Focus the current window.
focus: ->
ipc.send('call-window-method', 'focus')
$(window).focus()
# Extended: Show the current window.
show: ->
ipc.send('call-window-method', 'show')
# Extended: Hide the current window.
hide: ->
ipc.send('call-window-method', 'hide')
# Extended: Reload the current window.
reload: ->
ipc.send('call-window-method', 'restart')
# Extended: Returns a {Boolean} true when the current window is maximized.
isMaximixed: ->
@getCurrentWindow().isMaximized()
maximize: ->
ipc.send('call-window-method', 'maximize')
# Extended: Is the current window in full screen mode?
isFullScreen: ->
@getCurrentWindow().isFullScreen()
# Extended: Set the full screen state of the current window.
setFullScreen: (fullScreen=false) ->
ipc.send('call-window-method', 'setFullScreen', fullScreen)
if fullScreen then document.body.classList.add("fullscreen") else document.body.classList.remove("fullscreen")
# Extended: Toggle the full screen state of the current window.
toggleFullScreen: ->
@setFullScreen(!@isFullScreen())
# Schedule the window to be shown and focused on the next tick.
#
# This is done in a next tick to prevent a white flicker from occurring
# if called synchronously.
displayWindow: ({maximize}={}) ->
setImmediate =>
@show()
@focus()
@setFullScreen(true) if @workspace.fullScreen
@maximize() if maximize
# Get the dimensions of this window.
#
# Returns an {Object} with the following keys:
# * `x` The window's x-position {Number}.
@@ -227,7 +392,7 @@ class Atom extends Model
maximized = browserWindow.isMaximized()
{x, y, width, height, maximized}
# Public: Set the dimensions of the window.
# Set the dimensions of the window.
#
# The window will be centered if either the x or y coordinate is not set
# in the dimensions parameter. If x or y are omitted the window will be
@@ -284,41 +449,6 @@ class Atom extends Model
dimensions = @getWindowDimensions()
@state.windowDimensions = dimensions if @isValidDimensions(dimensions)
# Public: Get the load settings for the current window.
#
# Returns an {Object} containing all the load setting key/value pairs.
getLoadSettings: ->
@constructor.getLoadSettings()
deserializeProject: ->
Project = require './project'
startTime = Date.now()
@project ?= @deserializers.deserialize(@state.project) ? new Project(path: @getLoadSettings().initialPath)
@deserializeTimings.project = Date.now() - startTime
deserializeWorkspaceView: ->
Workspace = require './workspace'
WorkspaceView = require './workspace-view'
startTime = Date.now()
@workspace = Workspace.deserialize(@state.workspace) ? new Workspace
@workspaceView = new WorkspaceView(@workspace)
@deserializeTimings.workspace = Date.now() - startTime
@keymaps.defaultTarget = @workspaceView[0]
$(@workspaceViewParentSelector).append(@workspaceView)
deserializePackageStates: ->
@packages.packageStates = @state.packageStates ? {}
delete @state.packageStates
deserializeEditorWindow: ->
@deserializeTimings = {}
@deserializePackageStates()
@deserializeProject()
@deserializeWorkspaceView()
# Call this method when establishing a real application window.
startEditorWindow: ->
{resourcePath, safeMode} = @getLoadSettings()
@@ -369,59 +499,34 @@ class Atom extends Model
@windowEventHandler?.unsubscribe()
loadThemes: ->
@themes.load()
###
Section: Messaging the User
###
watchThemes: ->
@themes.on 'reloaded', =>
# Only reload stylesheets from non-theme packages
for pack in @packages.getActivePackages() when pack.getType() isnt 'theme'
pack.reloadStylesheets?()
null
# Essential: Visually and audibly trigger a beep.
beep: ->
shell.beep() if @config.get('core.audioBeep')
@workspaceView.trigger 'beep'
@emitter.emit 'did-beep'
# Notify the browser project of the window's current project path
watchProjectPath: ->
onProjectPathChanged = =>
ipc.send('window-command', 'project-path-changed', @project.getPath())
@subscribe @project, 'path-changed', onProjectPathChanged
onProjectPathChanged()
# Public: Open a new Atom window using the given options.
#
# 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.
open: (options) ->
ipc.send('open', options)
# Public: Open a confirm dialog.
# Essential: A flexible way to open a dialog akin to an alert dialog.
#
# ## Examples
#
# ```coffee
# atom.confirm
# message: 'How you feeling?'
# detailedMessage: 'Be honest.'
# buttons:
# Good: -> window.alert('good to hear')
# Bad: -> window.alert('bummer')
# atom.confirm
# message: 'How you feeling?'
# detailedMessage: 'Be honest.'
# buttons:
# Good: -> window.alert('good to hear')
# 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.
# * `detailedMessage` (optional) The {String} detailed message to display.
# * `buttons` (optional) 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}={}) ->
@@ -444,77 +549,71 @@ class Atom extends Model
callback = buttons[buttonLabels[chosen]]
callback?()
showSaveDialog: (callback) ->
callback(showSaveDialogSync())
###
Section: Managing the Dev Tools
###
showSaveDialogSync: (defaultPath) ->
defaultPath ?= @project?.getPath()
currentWindow = @getCurrentWindow()
dialog = remote.require('dialog')
dialog.showSaveDialog currentWindow, {title: 'Save File', defaultPath}
# Public: Open the dev tools for the current window.
# Extended: Open the dev tools for the current window.
openDevTools: ->
ipc.send('call-window-method', 'openDevTools')
# Public: Toggle the visibility of the dev tools for the current window.
# Extended: Toggle the visibility of the dev tools for the current window.
toggleDevTools: ->
ipc.send('call-window-method', 'toggleDevTools')
# Public: Execute code in dev tools.
# Extended: Execute code in dev tools.
executeJavaScriptInDevTools: (code) ->
ipc.send('call-window-method', 'executeJavaScriptInDevTools', code)
# Public: Reload the current window.
reload: ->
ipc.send('call-window-method', 'restart')
###
Section: Private
###
# Public: Focus the current window.
focus: ->
ipc.send('call-window-method', 'focus')
$(window).focus()
deserializeProject: ->
Project = require './project'
# Public: Show the current window.
show: ->
ipc.send('call-window-method', 'show')
startTime = Date.now()
@project ?= @deserializers.deserialize(@state.project) ? new Project(path: @getLoadSettings().initialPath)
@deserializeTimings.project = Date.now() - startTime
# Public: Hide the current window.
hide: ->
ipc.send('call-window-method', 'hide')
deserializeWorkspaceView: ->
Workspace = require './workspace'
WorkspaceView = require './workspace-view'
# Public: Set the size of current window.
#
# * `width` The {Number} of pixels.
# * `height` The {Number} of pixels.
setSize: (width, height) ->
@getCurrentWindow().setSize(width, height)
startTime = Date.now()
@workspace = Workspace.deserialize(@state.workspace) ? new Workspace
@workspaceView = new WorkspaceView(@workspace)
@deserializeTimings.workspace = Date.now() - startTime
# Public: Set the position of current window.
#
# * `x` The {Number} of pixels.
# * `y` The {Number} of pixels.
setPosition: (x, y) ->
ipc.send('call-window-method', 'setPosition', x, y)
@keymaps.defaultTarget = @workspaceView[0]
$(@workspaceViewParentSelector).append(@workspaceView)
# Public: Move current window to the center of the screen.
center: ->
ipc.send('call-window-method', 'center')
deserializePackageStates: ->
@packages.packageStates = @state.packageStates ? {}
delete @state.packageStates
deserializeEditorWindow: ->
@deserializeTimings = {}
@deserializePackageStates()
@deserializeProject()
@deserializeWorkspaceView()
# Schedule the window to be shown and focused on the next tick.
#
# This is done in a next tick to prevent a white flicker from occurring
# if called synchronously.
displayWindow: ({maximize}={}) ->
setImmediate =>
@show()
@focus()
@setFullScreen(true) if @workspace.fullScreen
@maximize() if maximize
loadThemes: ->
@themes.load()
# Public: Close the current window.
close: ->
@getCurrentWindow().close()
watchThemes: ->
@themes.onDidReloadAll =>
# Only reload stylesheets from non-theme packages
for pack in @packages.getActivePackages() when pack.getType() isnt 'theme'
pack.reloadStylesheets?()
null
# Notify the browser project of the window's current project path
watchProjectPath: ->
onProjectPathChanged = =>
ipc.send('window-command', 'project-path-changed', @project.getPath())
@subscribe @project, 'path-changed', onProjectPathChanged
onProjectPathChanged()
exit: (status) ->
app = remote.require('app')
@@ -527,45 +626,14 @@ class Atom extends Model
setRepresentedFilename: (filename) ->
ipc.send('call-window-method', 'setRepresentedFilename', filename)
# Public: Is the current window in development mode?
inDevMode: ->
@getLoadSettings().devMode
showSaveDialog: (callback) ->
callback(showSaveDialogSync())
# Public: Is the current window running specs?
inSpecMode: ->
@getLoadSettings().isSpec
# Public: Toggle the full screen state of the current window.
toggleFullScreen: ->
@setFullScreen(!@isFullScreen())
# Public: Set the full screen state of the current window.
setFullScreen: (fullScreen=false) ->
ipc.send('call-window-method', 'setFullScreen', fullScreen)
if fullScreen then document.body.classList.add("fullscreen") else document.body.classList.remove("fullscreen")
# Public: Is the current window in full screen mode?
isFullScreen: ->
@getCurrentWindow().isFullScreen()
maximize: ->
ipc.send('call-window-method', 'maximize')
# Public: Get the version of the Atom application.
#
# Returns the version text {String}.
getVersion: ->
@appVersion ?= @getLoadSettings().appVersion
# Public: Determine whether the current version is an official release.
isReleasedVersion: ->
not /\w{7}/.test(@getVersion()) # Check if the release is a 7-character SHA prefix
# Public: Get the directory path to Atom's configuration area.
#
# Returns the absolute path to `~/.atom`.
getConfigDirPath: ->
@constructor.getConfigDirPath()
showSaveDialogSync: (defaultPath) ->
defaultPath ?= @project?.getPath()
currentWindow = @getCurrentWindow()
dialog = remote.require('dialog')
dialog.showSaveDialog currentWindow, {title: 'Save File', defaultPath}
saveSync: ->
stateString = JSON.stringify(@state)
@@ -574,27 +642,12 @@ class Atom extends Model
else
@getCurrentWindow().loadSettings.windowState = stateString
# Public: Get the time taken to completely load the current window.
#
# 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
# if the window hasn't finished loading yet.
getWindowLoadTime: ->
@loadTime
crashMainProcess: ->
remote.process.crash()
crashRenderProcess: ->
process.crash()
# Public: Visually and audibly trigger a beep.
beep: ->
shell.beep() if @config.get('core.audioBeep')
@workspaceView.trigger 'beep'
getUserInitScriptPath: ->
initScriptPath = fs.resolve(@getConfigDirPath(), 'init', ['js', 'coffee'])
initScriptPath ? path.join(@getConfigDirPath(), 'init.coffee')
@@ -606,7 +659,7 @@ class Atom extends Model
catch error
console.error "Failed to load `#{userInitScriptPath}`", error.stack, error
# Public: Require the module with the given globals.
# Require the module with the given globals.
#
# The globals will be set on the `window` object and removed after the
# require completes.
@@ -626,3 +679,14 @@ class Atom extends Model
delete window[key]
else
window[key] = value
# Deprecated: Callers should be converted to use atom.deserializers
registerRepresentationClass: ->
deprecate("Callers should be converted to use atom.deserializers")
# Deprecated: Callers should be converted to use atom.deserializers
registerRepresentationClasses: ->
deprecate("Callers should be converted to use atom.deserializers")
setBodyPlatformClass: ->
document.body.classList.add("platform-#{process.platform}")
+19 -10
Ver Arquivo
@@ -5,13 +5,11 @@ AutoUpdateManager = require './auto-update-manager'
BrowserWindow = require 'browser-window'
Menu = require 'menu'
app = require 'app'
dialog = require 'dialog'
fs = require 'fs'
ipc = require 'ipc'
path = require 'path'
os = require 'os'
net = require 'net'
shell = require 'shell'
url = require 'url'
{EventEmitter} = require 'events'
_ = require 'underscore-plus'
@@ -103,11 +101,12 @@ class AtomApplication
window.once 'window:loaded', =>
@autoUpdateManager.emitUpdateAvailableEvent(window)
focusHandler = => @lastFocusedWindow = window
window.browserWindow.on 'focus', focusHandler
window.browserWindow.once 'closed', =>
@lastFocusedWindow = null if window is @lastFocusedWindow
window.browserWindow.removeListener 'focus', focusHandler
unless window.isSpec
focusHandler = => @lastFocusedWindow = window
window.browserWindow.on 'focus', focusHandler
window.browserWindow.once 'closed', =>
@lastFocusedWindow = null if window is @lastFocusedWindow
window.browserWindow.removeListener 'focus', focusHandler
# Creates server to listen for additional atom application launches.
#
@@ -155,8 +154,8 @@ class AtomApplication
atomWindow ?= @focusedWindow()
atomWindow?.browserWindow.inspectElement(x, y)
@on 'application:open-documentation', -> shell.openExternal('https://atom.io/docs/latest/?app')
@on 'application:open-terms-of-use', -> shell.openExternal('https://atom.io/terms')
@on 'application:open-documentation', -> require('shell').openExternal('https://atom.io/docs/latest/?app')
@on 'application:open-terms-of-use', -> require('shell').openExternal('https://atom.io/terms')
@on 'application:install-update', -> @autoUpdateManager.install()
@on 'application:check-for-update', => @autoUpdateManager.check()
@@ -484,5 +483,15 @@ class AtomApplication
when 'folder' then ['openDirectory']
when 'all' then ['openFile', 'openDirectory']
else throw new Error("#{type} is an invalid type for promptForPath")
dialog.showOpenDialog title: 'Open', properties: properties.concat(['multiSelections', 'createDirectory']), (pathsToOpen) =>
# Show the open dialog as child window on Windows and Linux, and as
# independent dialog on OS X. This matches most native apps.
parentWindow =
if process.platform is 'darwin'
null
else
BrowserWindow.getFocusedWindow()
dialog = require 'dialog'
dialog.showOpenDialog parentWindow, title: 'Open', properties: properties.concat(['multiSelections', 'createDirectory']), (pathsToOpen) =>
@openPaths({pathsToOpen, devMode, safeMode, window})
+2 -2
Ver Arquivo
@@ -1,5 +1,5 @@
app = require 'app'
fs = require 'fs-plus'
fs = require 'fs'
path = require 'path'
protocol = require 'protocol'
@@ -24,5 +24,5 @@ class AtomProtocolHandler
relativePath = path.normalize(request.url.substr(7))
for loadPath in @loadPaths
filePath = path.join(loadPath, relativePath)
break if fs.isFileSync(filePath)
break if fs.statSyncNoException(filePath).isFile?()
return new protocol.RequestFileJob(filePath)
+16 -5
Ver Arquivo
@@ -1,7 +1,5 @@
BrowserWindow = require 'browser-window'
ContextMenu = require './context-menu'
app = require 'app'
dialog = require 'dialog'
path = require 'path'
fs = require 'fs'
url = require 'url'
@@ -25,7 +23,12 @@ class AtomWindow
# Normalize to make sure drive letter case is consistent on Windows
@resourcePath = path.normalize(@resourcePath) if @resourcePath
@browserWindow = new BrowserWindow show: false, title: 'Atom', icon: @constructor.iconPath
@browserWindow = new BrowserWindow
show: false
title: 'Atom'
icon: @constructor.iconPath
'web-preferences':
'subpixel-font-scaling': false
global.atomApplication.addWindow(this)
@handleEvents()
@@ -73,6 +76,13 @@ class AtomWindow
getInitialPath: ->
@browserWindow.loadSettings.initialPath
setupContextMenu: ->
ContextMenu = null
@browserWindow.on 'context-menu', (menuTemplate) =>
ContextMenu ?= require './context-menu'
new ContextMenu(menuTemplate, this)
containsPath: (pathToCheck) ->
initialPath = @getInitialPath()
if not initialPath
@@ -95,6 +105,7 @@ class AtomWindow
@browserWindow.on 'unresponsive', =>
return if @isSpec
dialog = require 'dialog'
chosen = dialog.showMessageBox @browserWindow,
type: 'warning'
buttons: ['Close', 'Keep Waiting']
@@ -105,6 +116,7 @@ class AtomWindow
@browserWindow.webContents.on 'crashed', =>
global.atomApplication.exit(100) if @exitWhenDone
dialog = require 'dialog'
chosen = dialog.showMessageBox @browserWindow,
type: 'warning'
buttons: ['Close Window', 'Reload', 'Keep It Open']
@@ -114,8 +126,7 @@ class AtomWindow
when 0 then @browserWindow.destroy()
when 1 then @browserWindow.restart()
@browserWindow.on 'context-menu', (menuTemplate) =>
new ContextMenu(menuTemplate, this)
@setupContextMenu()
if @isSpec
# Workaround for https://github.com/atom/atom-shell/issues/380
+23 -16
Ver Arquivo
@@ -1,44 +1,47 @@
https = require 'https'
autoUpdater = require 'auto-updater'
dialog = require 'dialog'
autoUpdater = null
_ = require 'underscore-plus'
{EventEmitter} = require 'events'
IDLE_STATE='idle'
CHECKING_STATE='checking'
DOWNLOADING_STATE='downloading'
UPDATE_AVAILABLE_STATE='update-available'
NO_UPDATE_AVAILABLE_STATE='no-update-available'
ERROR_STATE='error'
IdleState = 'idle'
CheckingState = 'checking'
DownladingState = 'downloading'
UpdateAvailableState = 'update-available'
NoUpdateAvailableState = 'no-update-available'
ErrorState = 'error'
module.exports =
class AutoUpdateManager
_.extend @prototype, EventEmitter.prototype
constructor: (@version) ->
@state = IDLE_STATE
@state = IdleState
@feedUrl = "https://atom.io/api/updates?version=#{@version}"
process.nextTick => @setupAutoUpdater()
setupAutoUpdater: ->
autoUpdater = require 'auto-updater'
if process.platform is 'win32'
autoUpdater.checkForUpdates = => @checkForUpdatesShim()
autoUpdater.setFeedUrl @feedUrl
autoUpdater.on 'checking-for-update', =>
@setState(CHECKING_STATE)
@setState(CheckingState)
autoUpdater.on 'update-not-available', =>
@setState(NO_UPDATE_AVAILABLE_STATE)
@setState(NoUpdateAvailableState)
autoUpdater.on 'update-available', =>
@setState(DOWNLOADING_STATE)
@setState(DownladingState)
autoUpdater.on 'error', (event, message) =>
@setState(ERROR_STATE)
@setState(ErrorState)
console.error "Error Downloading Update: #{message}"
autoUpdater.on 'update-downloaded', (event, @releaseNotes, @releaseVersion) =>
@setState(UPDATE_AVAILABLE_STATE)
@setState(UpdateAvailableState)
@emitUpdateAvailableEvent(@getWindows()...)
# Only released versions should check for updates.
@@ -48,6 +51,8 @@ class AutoUpdateManager
# Windows doesn't have an auto-updater, so use this method to shim the events.
checkForUpdatesShim: ->
autoUpdater.emit 'checking-for-update'
https = require 'https'
request = https.get @feedUrl, (response) ->
if response.statusCode == 200
body = ""
@@ -67,7 +72,7 @@ class AutoUpdateManager
atomWindow.sendCommand('window:update-available', [@releaseVersion, @releaseNotes])
setState: (state) ->
return unless @state != state
return if @state is state
@state = state
@emit 'state-changed', @state
@@ -86,10 +91,12 @@ class AutoUpdateManager
onUpdateNotAvailable: =>
autoUpdater.removeListener 'error', @onUpdateError
dialog = require 'dialog'
dialog.showMessageBox type: 'info', buttons: ['OK'], message: 'No update available.', detail: "Version #{@version} is the latest version."
onUpdateError: (event, message) =>
autoUpdater.removeListener 'update-not-available', @onUpdateNotAvailable
dialog = require 'dialog'
dialog.showMessageBox type: 'warning', buttons: ['OK'], message: 'There was an error checking for updates.', detail: message
getWindows: ->
+12 -7
Ver Arquivo
@@ -3,11 +3,9 @@ global.shellStartTime = Date.now()
crashReporter = require 'crash-reporter'
app = require 'app'
fs = require 'fs'
module = require 'module'
path = require 'path'
optimist = require 'optimist'
nslog = require 'nslog'
dialog = require 'dialog'
console.log = nslog
@@ -33,14 +31,14 @@ start = ->
app.on 'will-finish-launching', ->
setupCrashReporter()
app.on 'finish-launching', ->
app.on 'ready', ->
app.removeListener 'open-file', addPathToOpen
app.removeListener 'open-url', addUrlToOpen
args.pathsToOpen = args.pathsToOpen.map (pathToOpen) ->
path.resolve(args.executedFrom ? process.cwd(), pathToOpen.toString())
require('coffee-script').register()
setupCoffeeScript()
if args.devMode
require(path.join(args.resourcePath, 'src', 'coffee-cache')).register()
AtomApplication = require path.join(args.resourcePath, 'src', 'browser', 'atom-application')
@@ -57,6 +55,15 @@ global.devResourcePath = path.normalize(global.devResourcePath) if global.devRes
setupCrashReporter = ->
crashReporter.start(productName: 'Atom', companyName: 'GitHub')
setupCoffeeScript = ->
CoffeeScript = null
require.extensions['.coffee'] = (module, filePath) ->
CoffeeScript ?= require('coffee-script')
coffee = fs.readFileSync(filePath, 'utf8')
js = CoffeeScript.compile(coffee, filename: filePath)
module._compile(js, filePath)
parseCommandLine = ->
version = app.getVersion()
options = optimist(process.argv[1..])
@@ -109,9 +116,7 @@ parseCommandLine = ->
else if devMode
resourcePath = global.devResourcePath
try
fs.statSync resourcePath
catch
unless fs.statSyncNoException(resourcePath)
resourcePath = path.dirname(path.dirname(__dirname))
{resourcePath, pathsToOpen, executedFrom, test, version, pidToKillWhenClosed, devMode, safeMode, newWindow, specDirectory, logFile}
+1 -1
Ver Arquivo
@@ -1,7 +1,7 @@
BufferedProcess = require './buffered-process'
path = require 'path'
# Public: Like {BufferedProcess}, but accepts a Node script as the command
# Extended: Like {BufferedProcess}, but accepts a Node script as the command
# to run.
#
# This is necessary on Windows since it doesn't support shebang `#!` lines.
+4 -3
Ver Arquivo
@@ -1,7 +1,7 @@
_ = require 'underscore-plus'
ChildProcess = require 'child_process'
# Public: A wrapper which provides standard error/output line buffering for
# Extended: A wrapper which provides standard error/output line buffering for
# Node's ChildProcess.
#
# ## Examples
@@ -44,13 +44,14 @@ class BufferedProcess
if process.platform is "win32"
# Quote all arguments and escapes inner quotes
if args?
cmdArgs = args.map (arg) ->
cmdArgs = args.filter (arg) -> arg?
cmdArgs = cmdArgs.map (arg) ->
if command in ['explorer.exe', 'explorer'] and /^\/[a-zA-Z]+,.*$/.test(arg)
# Don't wrap /root,C:\folder style arguments to explorer calls in
# quotes since they will not be interpreted correctly if they are
arg
else
"\"#{arg.replace(/"/g, '\\"')}\""
"\"#{arg.toString().replace(/"/g, '\\"')}\""
else
cmdArgs = []
if /\s/.test(command)
+1 -1
Ver Arquivo
@@ -1,7 +1,7 @@
clipboard = require 'clipboard'
crypto = require 'crypto'
# Public: Represents the clipboard used for copying and pasting in Atom.
# Extended: Represents the clipboard used for copying and pasting in Atom.
#
# An instance of this class is always available as the `atom.clipboard` global.
#
+176
Ver Arquivo
@@ -0,0 +1,176 @@
{Disposable, CompositeDisposable} = require 'event-kit'
{specificity} = require 'clear-cut'
_ = require 'underscore-plus'
{$} = require './space-pen-extensions'
SequenceCount = 0
SpecificityCache = {}
module.exports =
# Experimental: Associates listener functions with commands in a
# context-sensitive way using CSS selectors. You can access a global instance of
# this class via `atom.commands`, and commands registered there will be
# presented in the command palette.
#
# The global command registry facilitates a style of event handling known as
# *event delegation* that was popularized by jQuery. Atom commands are expressed
# as custom DOM events that can be invoked on the currently focused element via
# a key binding or manually via the command palette. Rather than binding
# listeners for command events directly to DOM nodes, you instead register
# command event listeners globally on `atom.commands` and constrain them to
# specific kinds of elements with CSS selectors.
#
# As the event bubbles upward through the DOM, all registered event listeners
# with matching selectors are invoked in order of specificity. In the event of a
# specificity tie, the most recently registered listener is invoked first. This
# mirrors the "cascade" semantics of CSS. Event listeners are invoked in the
# context of the current DOM node, meaning `this` always points at
# `event.currentTarget`. As is normally the case with DOM events,
# `stopPropagation` and `stopImmediatePropagation` can be used to terminate the
# bubbling process and prevent invocation of additional listeners.
#
# ## Example
#
# Here is a command that inserts the current date in an editor:
#
# ```coffee
# atom.commands.add '.editor',
# 'user:insert-date': (event) ->
# editor = $(this).view().getModel()
# # soon the above above line will be:
# # editor = @getModel()
# editor.insertText(new Date().toLocaleString())
# ```
class CommandRegistry
constructor: (@rootNode) ->
@listenersByCommandName = {}
setRootNode: (newRootNode) ->
oldRootNode = @rootNode
@rootNode = newRootNode
for commandName of @listenersByCommandName
oldRootNode?.removeEventListener(commandName, @dispatchCommand, true)
newRootNode?.addEventListener(commandName, @dispatchCommand, true)
# Public: Add one or more command listeners associated with a selector.
#
# ## Arguments: Registering One Command
#
# * `selector` A {String} containing a CSS selector matching elements on which
# you want to handle the commands. The `,` combinator is not currently
# supported.
# * `commandName` A {String} containing the name of a command you want to
# handle such as `user:insert-date`.
# * `callback` A {Function} to call when the given command is invoked on an
# element matching the selector. It will be called with `this` referencing
# the matching DOM node.
# * `event` A standard DOM event instance. Call `stopPropagation` or
# `stopImmediatePropagation` to terminate bubbling early.
#
# ## Arguments: Registering Multiple Commands
#
# * `selector` A {String} containing a CSS selector matching elements on which
# you want to handle the commands. The `,` combinator is not currently
# supported.
# * `commands` An {Object} mapping command names like `user:insert-date` to
# listener {Function}s.
#
# Returns a {Disposable} on which `.dispose()` can be called to remove the
# added command handler(s).
add: (selector, commandName, callback) ->
if typeof commandName is 'object'
commands = commandName
disposable = new CompositeDisposable
for commandName, callback of commands
disposable.add @add(selector, commandName, callback)
return disposable
unless @listenersByCommandName[commandName]?
@rootNode?.addEventListener(commandName, @dispatchCommand, true)
@listenersByCommandName[commandName] = []
listener = new CommandListener(selector, callback)
listenersForCommand = @listenersByCommandName[commandName]
listenersForCommand.push(listener)
new Disposable =>
listenersForCommand.splice(listenersForCommand.indexOf(listener), 1)
if listenersForCommand.length is 0
delete @listenersByCommandName[commandName]
@rootNode.removeEventListener(commandName, @dispatchCommand, true)
dispatchCommand: (event) =>
propagationStopped = false
immediatePropagationStopped = false
currentTarget = event.target
syntheticEvent = Object.create event,
eventPhase: value: Event.BUBBLING_PHASE
currentTarget: get: -> currentTarget
stopPropagation: value: ->
propagationStopped = true
stopImmediatePropagation: value: ->
propagationStopped = true
immediatePropagationStopped = true
loop
matchingListeners =
@listenersByCommandName[event.type]
.filter (listener) -> currentTarget.webkitMatchesSelector(listener.selector)
.sort (a, b) -> a.compare(b)
for listener in matchingListeners
break if immediatePropagationStopped
listener.callback.call(currentTarget, syntheticEvent)
break if propagationStopped
break if currentTarget is @rootNode
currentTarget = currentTarget.parentNode
# Public: Find all registered commands matching a query.
#
# * `params` An {Object} containing one or more of the following keys:
# * `target` A DOM node that is the hypothetical target of a given command.
#
# Returns an {Array} of {Object}s containing the following keys:
# * `name` The name of the command. For example, `user:insert-date`.
# * `displayName` The display name of the command. For example,
# `User: Insert Date`.
# * `jQuery` Present if the command was registered with the legacy
# `$::command` method.
findCommands: ({target}) ->
commands = []
target = @rootNode unless @rootNode.contains(target)
currentTarget = target
loop
for commandName, listeners of @listenersByCommandName
for listener in listeners
if currentTarget.webkitMatchesSelector(listener.selector)
commands.push
name: commandName
displayName: _.humanizeEventName(commandName)
break if currentTarget is @rootNode
currentTarget = currentTarget.parentNode
for name, displayName of $(target).events() when displayName
commands.push({name, displayName, jQuery: true})
for name, displayName of $(window).events() when displayName
commands.push({name, displayName, jQuery: true})
commands
clear: ->
@listenersByCommandName = {}
class CommandListener
constructor: (@selector, @callback) ->
@specificity = (SpecificityCache[@selector] ?= specificity(@selector))
@sequenceNumber = SequenceCount++
compare: (other) ->
other.specificity - @specificity or
other.sequenceNumber - @sequenceNumber
+1 -1
Ver Arquivo
@@ -6,7 +6,7 @@ path = require 'path'
async = require 'async'
pathWatcher = require 'pathwatcher'
# Public: Used to access all of Atom's configuration details.
# Essential: Used to access all of Atom's configuration details.
#
# An instance of this class is always available as the `atom.config` global.
#
+2 -2
Ver Arquivo
@@ -5,7 +5,7 @@ path = require 'path'
CSON = require 'season'
fs = require 'fs-plus'
# Public: Provides a registry for commands that you'd like to appear in the
# Extended: Provides a registry for commands that you'd like to appear in the
# context menu.
#
# An instance of this class is always available as the `atom.contextMenu`
@@ -24,7 +24,7 @@ class ContextMenuManager
@commandOptions = x: e.pageX, y: e.pageY
]
atom.keymaps.on 'bundled-keymaps-loaded', => @loadPlatformItems()
atom.keymaps.onDidLoadBundledKeymaps => @loadPlatformItems()
loadPlatformItems: ->
menusDirPath = path.join(@resourcePath, 'menus')
+223 -159
Ver Arquivo
@@ -1,37 +1,14 @@
{Point, Range} = require 'text-buffer'
{Model} = require 'theorist'
{Emitter} = require 'event-kit'
_ = require 'underscore-plus'
Grim = require 'grim'
# Extended: The `Cursor` class represents the little blinking line identifying
# where text can be inserted.
#
# Cursors belong to {Editor}s and have some metadata attached in the form
# 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
@@ -42,9 +19,11 @@ class Cursor extends Model
# Instantiated by an {Editor}
constructor: ({@editor, @marker, id}) ->
@emitter = new Emitter
@assignId(id)
@updateVisibility()
@marker.on 'changed', (e) =>
@marker.onDidChange (e) =>
@updateVisibility()
{oldHeadScreenPosition, newHeadScreenPosition} = e
{oldHeadBufferPosition, newHeadBufferPosition} = e
@@ -63,28 +42,73 @@ class Cursor extends Model
newBufferPosition: newHeadBufferPosition
newScreenPosition: newHeadScreenPosition
textChanged: textChanged
cursor: this
@emit 'moved', movedEvent
@emitter.emit 'did-change-position'
@editor.cursorMoved(movedEvent)
@marker.on 'destroyed', =>
@marker.onDidDestroy =>
@destroyed = true
@editor.removeCursor(this)
@emit 'destroyed'
@emitter.emit 'did-destroy'
@emitter.dispose()
@needsAutoscroll = true
destroy: ->
@marker.destroy()
changePosition: (options, fn) ->
@clearSelection()
@needsAutoscroll = options.autoscroll ? @isLastCursor()
fn()
if @needsAutoscroll
@emit 'autoscrolled' # Support legacy editor
@autoscroll() if @needsAutoscroll and @editor.manageScrollPosition # Support react editor view
###
Section: Event Subscription
###
getPixelRect: ->
@editor.pixelRectForScreenRange(@getScreenRange())
# Public: Calls your `callback` when the cursor has been moved.
#
# * `callback` {Function}
# * `event` {Object}
# * `oldBufferPosition` {Point}
# * `oldScreenPosition` {Point}
# * `newBufferPosition` {Point}
# * `newScreenPosition` {Point}
# * `textChanged` {Boolean}
# * `Cursor` {Cursor} that triggered the event
#
# Returns a {Disposable} on which `.dispose()` can be called to unsubscribe.
onDidChangePosition: (callback) ->
@emitter.on 'did-change-position', callback
# Public: Calls your `callback` when the cursor is destroyed
#
# * `callback` {Function}
#
# Returns a {Disposable} on which `.dispose()` can be called to unsubscribe.
onDidDestroy: (callback) ->
@emitter.on 'did-destroy', callback
# Public: Calls your `callback` when the cursor's visibility has changed
#
# * `callback` {Function}
# * `visibility` {Boolean}
#
# Returns a {Disposable} on which `.dispose()` can be called to unsubscribe.
onDidChangeVisibility: (callback) ->
@emitter.on 'did-change-visibility', callback
on: (eventName) ->
switch eventName
when 'moved'
Grim.deprecate("Use Cursor::onDidChangePosition instead")
when 'destroyed'
Grim.deprecate("Use Cursor::onDidDestroy instead")
when 'destroyed'
Grim.deprecate("Use Cursor::onDidDestroy instead")
else
Grim.deprecate("::on is no longer supported. Use the event subscription methods instead")
super
###
Section: Managing Cursor Position
###
# Public: Moves a cursor to a given screen position.
#
@@ -100,10 +124,6 @@ class Cursor extends Model
getScreenPosition: ->
@marker.getHeadScreenPosition()
getScreenRange: ->
{row, column} = @getScreenPosition()
new Range(new Point(row, column), new Point(row, column + 1))
# Public: Moves a cursor to a given buffer position.
#
# * `bufferPosition` {Array} of two numbers: the buffer row, and the buffer column.
@@ -118,46 +138,38 @@ class Cursor extends Model
getBufferPosition: ->
@marker.getHeadBufferPosition()
autoscroll: (options) ->
@editor.scrollToScreenRange(@getScreenRange(), options)
# Public: Returns the cursor's current screen row.
getScreenRow: ->
@getScreenPosition().row
# Public: If the marker range is empty, the cursor is marked as being visible.
updateVisibility: ->
@setVisible(@marker.getBufferRange().isEmpty())
# Public: Returns the cursor's current screen column.
getScreenColumn: ->
@getScreenPosition().column
# Public: Sets whether the cursor is visible.
setVisible: (visible) ->
if @visible != visible
@visible = visible
@needsAutoscroll ?= true if @visible and @isLastCursor()
@emit 'visibility-changed', @visible
# Public: Retrieves the cursor's current buffer row.
getBufferRow: ->
@getBufferPosition().row
# Public: Returns the visibility of the cursor.
isVisible: -> @visible
# Public: Returns the cursor's current buffer column.
getBufferColumn: ->
@getBufferPosition().column
# Public: Get the RegExp used by the cursor to determine what a "word" is.
#
# * `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}={}) ->
includeNonWordCharacters ?= true
nonWordCharacters = atom.config.get('editor.nonWordCharacters')
segments = ["^[\t ]*$"]
segments.push("[^\\s#{_.escapeRegExp(nonWordCharacters)}]+")
if includeNonWordCharacters
segments.push("[#{_.escapeRegExp(nonWordCharacters)}]+")
new RegExp(segments.join("|"), "g")
# Public: Returns the cursor's current buffer row of text excluding its line
# ending.
getCurrentBufferLine: ->
@editor.lineTextForBufferRow(@getBufferRow())
# Public: Identifies if this cursor is the last in the {Editor}.
#
# "Last" is defined as the most recently added cursor.
#
# Returns a {Boolean}.
isLastCursor: ->
this == @editor.getLastCursor()
# Public: Returns whether the cursor is at the start of a line.
isAtBeginningOfLine: ->
@getBufferPosition().column == 0
# Public: Returns whether the cursor is on the line return character.
isAtEndOfLine: ->
@getBufferPosition().isEqual(@getCurrentLineBufferRange().end)
###
Section: Cursor Position Details
###
# Public: Identifies if the cursor is surrounded by whitespace.
#
@@ -195,34 +207,42 @@ class Cursor extends Model
range = [[row, column], [row, Infinity]]
@editor.getTextInBufferRange(range).search(@wordRegExp()) == 0
# Public: Prevents this cursor from causing scrolling.
clearAutoscroll: ->
@needsAutoscroll = null
# Public: Returns the indentation level of the current line.
getIndentLevel: ->
if @editor.getSoftTabs()
@getBufferColumn() / @editor.getTabLength()
else
@getBufferColumn()
# Public: Deselects the current selection.
clearSelection: ->
@selection?.clear()
# Public: Retrieves the grammar's token scopes for the line.
#
# Returns an {Array} of {String}s.
getScopes: ->
@editor.scopesForBufferPosition(@getBufferPosition())
# Public: Returns the cursor's current screen row.
getScreenRow: ->
@getScreenPosition().row
# Public: Returns true if this cursor has no non-whitespace characters before
# its current position.
hasPrecedingCharactersOnLine: ->
bufferPosition = @getBufferPosition()
line = @editor.lineTextForBufferRow(bufferPosition.row)
firstCharacterColumn = line.search(/\S/)
# Public: Returns the cursor's current screen column.
getScreenColumn: ->
@getScreenPosition().column
if firstCharacterColumn is -1
false
else
bufferPosition.column > firstCharacterColumn
# Public: Retrieves the cursor's current buffer row.
getBufferRow: ->
@getBufferPosition().row
# Public: Identifies if this cursor is the last in the {Editor}.
#
# "Last" is defined as the most recently added cursor.
#
# Returns a {Boolean}.
isLastCursor: ->
this == @editor.getLastCursor()
# Public: Returns the cursor's current buffer column.
getBufferColumn: ->
@getBufferPosition().column
# Public: Returns the cursor's current buffer row of text excluding its line
# ending.
getCurrentBufferLine: ->
@editor.lineTextForBufferRow(@getBufferRow())
###
Section: Moving the Cursor
###
# Public: Moves the cursor up one screen row.
#
@@ -383,6 +403,20 @@ class Cursor extends Model
@setBufferPosition(endOfLeadingWhitespace) if endOfLeadingWhitespace.isGreaterThan(position)
# Public: Moves the cursor to the beginning of the next paragraph
moveToBeginningOfNextParagraph: ->
if position = @getBeginningOfNextParagraphBufferPosition()
@setBufferPosition(position)
# Public: Moves the cursor to the beginning of the previous paragraph
moveToBeginningOfPreviousParagraph: ->
if position = @getBeginningOfPreviousParagraphBufferPosition()
@setBufferPosition(position)
###
Section: Local Positions and Ranges
###
# Public: Retrieves the buffer position of where the current word starts.
#
# * `options` (optional) An {Object} with the following keys:
@@ -519,15 +553,98 @@ class Cursor extends Model
getCurrentLineBufferRange: (options) ->
@editor.bufferRangeForBufferRow(@getBufferRow(), options)
# Public: Moves the cursor to the beginning of the next paragraph
moveToBeginningOfNextParagraph: ->
if position = @getBeginningOfNextParagraphBufferPosition()
@setBufferPosition(position)
# Public: Retrieves the range for the current paragraph.
#
# A paragraph is defined as a block of text surrounded by empty lines.
#
# Returns a {Range}.
getCurrentParagraphBufferRange: ->
@editor.languageMode.rowRangeForParagraphAtBufferRow(@getBufferRow())
# Public: Moves the cursor to the beginning of the previous paragraph
moveToBeginningOfPreviousParagraph: ->
if position = @getBeginningOfPreviousParagraphBufferPosition()
@setBufferPosition(position)
# Public: Returns the characters preceding the cursor in the current word.
getCurrentWordPrefix: ->
@editor.getTextInBufferRange([@getBeginningOfCurrentWordBufferPosition(), @getBufferPosition()])
###
Section: Visibility
###
# Public: If the marker range is empty, the cursor is marked as being visible.
updateVisibility: ->
@setVisible(@marker.getBufferRange().isEmpty())
# Public: Sets whether the cursor is visible.
setVisible: (visible) ->
if @visible != visible
@visible = visible
@needsAutoscroll ?= true if @visible and @isLastCursor()
@emit 'visibility-changed', @visible
@emitter.emit 'did-change-visibility', @visible
# Public: Returns the visibility of the cursor.
isVisible: -> @visible
###
Section: Comparing to another cursor
###
# 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())
###
Section: Utilities
###
# Public: Prevents this cursor from causing scrolling.
clearAutoscroll: ->
@needsAutoscroll = null
# Public: Deselects the current selection.
clearSelection: ->
@selection?.clear()
# Public: Get the RegExp used by the cursor to determine what a "word" is.
#
# * `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}={}) ->
includeNonWordCharacters ?= true
nonWordCharacters = atom.config.get('editor.nonWordCharacters')
segments = ["^[\t ]*$"]
segments.push("[^\\s#{_.escapeRegExp(nonWordCharacters)}]+")
if includeNonWordCharacters
segments.push("[#{_.escapeRegExp(nonWordCharacters)}]+")
new RegExp(segments.join("|"), "g")
###
Section: Private
###
changePosition: (options, fn) ->
@clearSelection()
@needsAutoscroll = options.autoscroll ? @isLastCursor()
fn()
if @needsAutoscroll
@emit 'autoscrolled' # Support legacy editor
@autoscroll() if @needsAutoscroll and @editor.manageScrollPosition # Support react editor view
getPixelRect: ->
@editor.pixelRectForScreenRange(@getScreenRange())
getScreenRange: ->
{row, column} = @getScreenPosition()
new Range(new Point(row, column), new Point(row, column + 1))
autoscroll: (options) ->
@editor.scrollToScreenRange(@getScreenRange(), options)
getBeginningOfNextParagraphBufferPosition: (editor) ->
start = @getBufferPosition()
@@ -555,56 +672,3 @@ class Cursor extends Model
position = range.start
stop()
@editor.screenPositionForBufferPosition(position)
# Public: Retrieves the range for the current paragraph.
#
# A paragraph is defined as a block of text surrounded by empty lines.
#
# Returns a {Range}.
getCurrentParagraphBufferRange: ->
@editor.languageMode.rowRangeForParagraphAtBufferRow(@getBufferRow())
# Public: Returns the characters preceding the cursor in the current word.
getCurrentWordPrefix: ->
@editor.getTextInBufferRange([@getBeginningOfCurrentWordBufferPosition(), @getBufferPosition()])
# Public: Returns whether the cursor is at the start of a line.
isAtBeginningOfLine: ->
@getBufferPosition().column == 0
# Public: Returns the indentation level of the current line.
getIndentLevel: ->
if @editor.getSoftTabs()
@getBufferColumn() / @editor.getTabLength()
else
@getBufferColumn()
# Public: Returns whether the cursor is on the line return character.
isAtEndOfLine: ->
@getBufferPosition().isEqual(@getCurrentLineBufferRange().end)
# Public: Retrieves the grammar's token scopes for the line.
#
# Returns an {Array} of {String}s.
getScopes: ->
@editor.scopesForBufferPosition(@getBufferPosition())
# Public: Returns true if this cursor has no non-whitespace characters before
# its current position.
hasPrecedingCharactersOnLine: ->
bufferPosition = @getBufferPosition()
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())
+105 -49
Ver Arquivo
@@ -1,5 +1,7 @@
_ = require 'underscore-plus'
{Subscriber, Emitter} = require 'emissary'
EmitterMixin = require('emissary').Emitter
{Emitter} = require 'event-kit'
Grim = require 'grim'
idCounter = 0
nextId = -> idCounter++
@@ -26,44 +28,76 @@ nextId = -> idCounter++
#
# You should only use {Decoration::destroy} when you still need or do not own
# the marker.
#
# ## Events
#
# ### updated
#
# 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)
EmitterMixin.includeInto(this)
# Extended: Check if the `decorationParams.type` matches `type`
# Private: Check if the `decorationProperties.type` matches `type`
#
# * `decorationParams` {Object} eg. `{type: 'gutter', class: 'my-new-class'}`
# * `decorationProperties` {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
@isType: (decorationProperties, type) ->
if _.isArray(decorationProperties.type)
type in decorationProperties.type
else
type is decorationParams.type
type is decorationProperties.type
constructor: (@marker, @displayBuffer, @params) ->
###
Section: Construction and Destruction
###
constructor: (@marker, @displayBuffer, @properties) ->
@emitter = new Emitter
@id = nextId()
@params.id = @id
@properties.id = @id
@flashQueue = null
@isDestroyed = false
@destroyed = false
@markerDestroyDisposable = @marker.onDidDestroy => @destroy()
# Essential: Destroy this marker.
#
# If you own the marker, you should use {Marker::destroy} which will destroy
# this decoration.
destroy: ->
return if @destroyed
@markerDestroyDisposable.dispose()
@markerDestroyDisposable = null
@destroyed = true
@emit 'destroyed'
@emitter.emit 'did-destroy'
@emitter.dispose()
###
Section: Event Subscription
###
# Essential: When the {Decoration} is updated via {Decoration::update}.
#
# * `callback` {Function}
# * `event` {Object}
# * `oldProperties` {Object} the old parameters the decoration used to have
# * `newProperties` {Object} the new parameters the decoration now has
#
# Returns a {Disposable} on which `.dispose()` can be called to unsubscribe.
onDidChangeProperties: (callback) ->
@emitter.on 'did-change-properties', callback
# Essential: Invoke the given callback when the {Decoration} is destroyed
#
# * `callback` {Function}
#
# Returns a {Disposable} on which `.dispose()` can be called to unsubscribe.
onDidDestroy: (callback) ->
@emitter.on 'did-destroy', callback
###
Section: Decoration Details
###
# Essential: An id unique across all {Decoration} objects
getId: -> @id
@@ -71,9 +105,6 @@ class Decoration
# 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
@@ -82,9 +113,20 @@ class Decoration
#
# Returns {Boolean}
isType: (type) ->
Decoration.isType(@params, type)
Decoration.isType(@properties, type)
# Essential: Update the marker with new params. Allows you to change the decoration's class.
###
Section: Properties
###
# Essential: Returns the {Decoration}'s properties.
getProperties: ->
@properties
getParams: ->
Grim.deprecate 'Use Decoration::getProperties instead'
@getProperties()
# Essential: Update the marker with new Properties. Allows you to change the decoration's class.
#
# ## Examples
#
@@ -92,37 +134,51 @@ class Decoration
# decoration.update({type: 'gutter', class: 'my-new-class'})
# ```
#
# * `newParams` {Object} eg. `{type: 'gutter', class: 'my-new-class'}`
update: (newParams) ->
return if @isDestroyed
oldParams = @params
@params = newParams
@params.id = @id
@displayBuffer.decorationUpdated(this)
@emit 'updated', {oldParams, newParams}
# * `newProperties` {Object} eg. `{type: 'gutter', class: 'my-new-class'}`
setProperties: (newProperties) ->
return if @destroyed
oldProperties = @properties
@properties = newProperties
@properties.id = @id
@emit 'updated', {oldParams: oldProperties, newParams: newProperties}
@emitter.emit 'did-change-properties', {oldProperties, newProperties}
update: (newProperties) ->
Grim.deprecate 'Use Decoration::setProperties instead'
@setProperties(newProperties)
# Essential: 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'
###
Section: Private methods
###
matchesPattern: (decorationPattern) ->
return false unless decorationPattern?
for key, value of decorationPattern
return false if @params[key] != value
return false if @properties[key] != value
true
onDidFlash: (callback) ->
@emitter.on 'did-flash', callback
flash: (klass, duration=500) ->
flashObject = {class: klass, duration}
@flashQueue ?= []
@flashQueue.push(flashObject)
@emit 'flash'
@emitter.emit 'did-flash'
consumeNextFlash: ->
return @flashQueue.shift() if @flashQueue?.length > 0
null
on: (eventName) ->
switch eventName
when 'updated'
Grim.deprecate 'Use Decoration::onDidChangeProperties instead'
when 'destroyed'
Grim.deprecate 'Use Decoration::onDidDestroy instead'
when 'flash'
Grim.deprecate 'Use Decoration::onDidFlash instead'
else
Grim.deprecate 'Decoration::on is deprecated. Use event subscription methods instead.'
EmitterMixin::on.apply(this, arguments)
+1 -1
Ver Arquivo
@@ -1,4 +1,4 @@
# Public: Manages the deserializers used for serialized state
# Extended: Manages the deserializers used for serialized state
#
# An instance of this class is always available as the `atom.deserializers`
# global.
-231
Ver Arquivo
@@ -1,231 +0,0 @@
{Range} = require 'text-buffer'
_ = require 'underscore-plus'
{Emitter, Subscriber} = require 'emissary'
module.exports =
class DisplayBufferMarker
Emitter.includeInto(this)
Subscriber.includeInto(this)
bufferMarkerSubscription: null
oldHeadBufferPosition: null
oldHeadScreenPosition: null
oldTailBufferPosition: null
oldTailScreenPosition: null
wasValid: true
constructor: ({@bufferMarker, @displayBuffer}) ->
@id = @bufferMarker.id
@oldHeadBufferPosition = @getHeadBufferPosition()
@oldHeadScreenPosition = @getHeadScreenPosition()
@oldTailBufferPosition = @getTailBufferPosition()
@oldTailScreenPosition = @getTailScreenPosition()
@wasValid = @isValid()
@subscribe @bufferMarker.onDidDestroy => @destroyed()
@subscribe @bufferMarker.onDidChange (event) => @notifyObservers(event)
copy: (attributes) ->
@displayBuffer.getMarker(@bufferMarker.copy(attributes).id)
# Gets the screen range of the display marker.
#
# Returns a {Range}.
getScreenRange: ->
@displayBuffer.screenRangeForBufferRange(@getBufferRange(), wrapAtSoftNewlines: true)
# Modifies the screen range of the display marker.
#
# screenRange - The new {Range} to use
# options - A hash of options matching those found in {Marker::setRange}
setScreenRange: (screenRange, options) ->
@setBufferRange(@displayBuffer.bufferRangeForScreenRange(screenRange), options)
# Gets the buffer range of the display marker.
#
# Returns a {Range}.
getBufferRange: ->
@bufferMarker.getRange()
# Modifies the buffer range of the display marker.
#
# screenRange - The new {Range} to use
# options - A hash of options matching those found in {Marker::setRange}
setBufferRange: (bufferRange, options) ->
@bufferMarker.setRange(bufferRange, options)
getPixelRange: ->
@displayBuffer.pixelRangeForScreenRange(@getScreenRange(), false)
# Retrieves the screen position of the marker's head.
#
# Returns a {Point}.
getHeadScreenPosition: ->
@displayBuffer.screenPositionForBufferPosition(@getHeadBufferPosition(), wrapAtSoftNewlines: true)
# Sets the screen position of the marker's head.
#
# screenRange - The new {Point} to use
# options - A hash of options matching those found in {DisplayBuffer::bufferPositionForScreenPosition}
setHeadScreenPosition: (screenPosition, options) ->
screenPosition = @displayBuffer.clipScreenPosition(screenPosition, options)
@setHeadBufferPosition(@displayBuffer.bufferPositionForScreenPosition(screenPosition, options))
# Retrieves the buffer position of the marker's head.
#
# Returns a {Point}.
getHeadBufferPosition: ->
@bufferMarker.getHeadPosition()
# Sets the buffer position of the marker's head.
#
# screenRange - The new {Point} to use
# options - A hash of options matching those found in {DisplayBuffer::bufferPositionForScreenPosition}
setHeadBufferPosition: (bufferPosition) ->
@bufferMarker.setHeadPosition(bufferPosition)
# Retrieves the screen position of the marker's tail.
#
# Returns a {Point}.
getTailScreenPosition: ->
@displayBuffer.screenPositionForBufferPosition(@getTailBufferPosition(), wrapAtSoftNewlines: true)
# Sets the screen position of the marker's tail.
#
# screenRange - The new {Point} to use
# options - A hash of options matching those found in {DisplayBuffer::bufferPositionForScreenPosition}
setTailScreenPosition: (screenPosition, options) ->
screenPosition = @displayBuffer.clipScreenPosition(screenPosition, options)
@setTailBufferPosition(@displayBuffer.bufferPositionForScreenPosition(screenPosition, options))
# Retrieves the buffer position of the marker's tail.
#
# Returns a {Point}.
getTailBufferPosition: ->
@bufferMarker.getTailPosition()
# Sets the buffer position of the marker's tail.
#
# screenRange - The new {Point} to use
# options - A hash of options matching those found in {DisplayBuffer::bufferPositionForScreenPosition}
setTailBufferPosition: (bufferPosition) ->
@bufferMarker.setTailPosition(bufferPosition)
# Retrieves the screen position of the marker's start. This will always be
# less than or equal to the result of {DisplayBufferMarker::getEndScreenPosition}.
#
# Returns a {Point}.
getStartScreenPosition: ->
@displayBuffer.screenPositionForBufferPosition(@getStartBufferPosition(), wrapAtSoftNewlines: true)
# Retrieves the buffer position of the marker's start. This will always be
# less than or equal to the result of {DisplayBufferMarker::getEndBufferPosition}.
#
# Returns a {Point}.
getStartBufferPosition: ->
@bufferMarker.getStartPosition()
# Retrieves the screen position of the marker's end. This will always be
# greater than or equal to the result of {DisplayBufferMarker::getStartScreenPosition}.
#
# Returns a {Point}.
getEndScreenPosition: ->
@displayBuffer.screenPositionForBufferPosition(@getEndBufferPosition(), wrapAtSoftNewlines: true)
# Retrieves the buffer position of the marker's end. This will always be
# greater than or equal to the result of {DisplayBufferMarker::getStartBufferPosition}.
#
# Returns a {Point}.
getEndBufferPosition: ->
@bufferMarker.getEndPosition()
# Sets the marker's tail to the same position as the marker's head.
#
# This only works if there isn't already a tail position.
#
# Returns a {Point} representing the new tail position.
plantTail: ->
@bufferMarker.plantTail()
# Removes the tail from the marker.
clearTail: ->
@bufferMarker.clearTail()
hasTail: ->
@bufferMarker.hasTail()
# Returns whether the head precedes the tail in the buffer
isReversed: ->
@bufferMarker.isReversed()
# Returns a {Boolean} indicating whether the marker is valid. Markers can be
# invalidated when a region surrounding them in the buffer is changed.
isValid: ->
@bufferMarker.isValid()
# Returns a {Boolean} indicating whether the marker has been destroyed. A marker
# can be invalid without being destroyed, in which case undoing the invalidating
# operation would restore the marker. Once a marker is destroyed by calling
# {Marker::destroy}, no undo/redo operation can ever bring it back.
isDestroyed: ->
@bufferMarker.isDestroyed()
getAttributes: ->
@bufferMarker.getProperties()
setAttributes: (attributes) ->
@bufferMarker.setProperties(attributes)
matchesAttributes: (attributes) ->
attributes = @displayBuffer.translateToBufferMarkerParams(attributes)
@bufferMarker.matchesAttributes(attributes)
# Destroys the marker
destroy: ->
@bufferMarker.destroy()
@unsubscribe()
isEqual: (other) ->
return false unless other instanceof @constructor
@bufferMarker.isEqual(other.bufferMarker)
compare: (other) ->
@bufferMarker.compare(other.bufferMarker)
# Returns a {String} representation of the marker
inspect: ->
"DisplayBufferMarker(id: #{@id}, bufferRange: #{@getBufferRange()})"
destroyed: ->
delete @displayBuffer.markers[@id]
@emit 'destroyed'
notifyObservers: ({textChanged}) ->
textChanged ?= false
newHeadBufferPosition = @getHeadBufferPosition()
newHeadScreenPosition = @getHeadScreenPosition()
newTailBufferPosition = @getTailBufferPosition()
newTailScreenPosition = @getTailScreenPosition()
isValid = @isValid()
return if _.isEqual(isValid, @wasValid) and
_.isEqual(newHeadBufferPosition, @oldHeadBufferPosition) and
_.isEqual(newHeadScreenPosition, @oldHeadScreenPosition) and
_.isEqual(newTailBufferPosition, @oldTailBufferPosition) and
_.isEqual(newTailScreenPosition, @oldTailScreenPosition)
@emit 'changed', {
@oldHeadScreenPosition, newHeadScreenPosition,
@oldTailScreenPosition, newTailScreenPosition,
@oldHeadBufferPosition, newHeadBufferPosition,
@oldTailBufferPosition, newTailBufferPosition,
textChanged,
isValid
}
@oldHeadBufferPosition = newHeadBufferPosition
@oldHeadScreenPosition = newHeadScreenPosition
@oldTailBufferPosition = newTailBufferPosition
@oldTailScreenPosition = newTailScreenPosition
@wasValid = isValid
+124 -80
Ver Arquivo
@@ -1,15 +1,17 @@
_ = require 'underscore-plus'
{Emitter} = require 'emissary'
EmitterMixin = require('emissary').Emitter
guid = require 'guid'
Serializable = require 'serializable'
{Model} = require 'theorist'
{Emitter} = require 'event-kit'
{Point, Range} = require 'text-buffer'
TokenizedBuffer = require './tokenized-buffer'
RowMap = require './row-map'
Fold = require './fold'
Token = require './token'
Decoration = require './decoration'
DisplayBufferMarker = require './display-buffer-marker'
Marker = require './marker'
Grim = require 'grim'
class BufferToScreenConversionError extends Error
constructor: (@message, @metadata) ->
@@ -22,7 +24,7 @@ class DisplayBuffer extends Model
@properties
manageScrollPosition: false
softWrap: null
softWrapped: null
editorWidthInChars: null
lineHeightInPixels: null
defaultCharWidth: null
@@ -40,7 +42,10 @@ class DisplayBuffer extends Model
constructor: ({tabLength, @editorWidthInChars, @tokenizedBuffer, buffer, @invisibles}={}) ->
super
@softWrap ?= atom.config.get('editor.softWrap') ? false
@emitter = new Emitter
@softWrapped ?= atom.config.get('editor.softWrap') ? false
@tokenizedBuffer ?= new TokenizedBuffer({tabLength, buffer, @invisibles})
@buffer = @tokenizedBuffer.buffer
@charWidthsByScope = {}
@@ -48,29 +53,23 @@ class DisplayBuffer extends Model
@foldsByMarkerId = {}
@decorationsById = {}
@decorationsByMarkerId = {}
@decorationMarkerChangedSubscriptions = {}
@decorationMarkerDestroyedSubscriptions = {}
@updateAllScreenLines()
@createFoldForMarker(marker) for marker in @buffer.findMarkers(@getFoldMarkerAttributes())
@subscribe @tokenizedBuffer, 'grammar-changed', (grammar) => @emit 'grammar-changed', grammar
@subscribe @tokenizedBuffer, 'tokenized', => @emit 'tokenized'
@subscribe @tokenizedBuffer, 'changed', @handleTokenizedBufferChange
@subscribe @tokenizedBuffer.onDidChange @handleTokenizedBufferChange
@subscribe @buffer.onDidUpdateMarkers @handleBufferMarkersUpdated
@subscribe @buffer.onDidCreateMarker @handleBufferMarkerCreated
@subscribe @$softWrap, (softWrap) =>
@emit 'soft-wrap-changed', softWrap
@updateWrappedScreenLines()
@subscribe atom.config.observe 'editor.preferredLineLength', callNow: false, =>
@updateWrappedScreenLines() if @softWrap and atom.config.get('editor.softWrapAtPreferredLineLength')
@updateWrappedScreenLines() if @isSoftWrapped() and atom.config.get('editor.softWrapAtPreferredLineLength')
@subscribe atom.config.observe 'editor.softWrapAtPreferredLineLength', callNow: false, =>
@updateWrappedScreenLines() if @softWrap
@updateWrappedScreenLines() if @isSoftWrapped()
@updateAllScreenLines()
serializeParams: ->
id: @id
softWrap: @softWrap
softWrapped: @isSoftWrapped()
editorWidthInChars: @editorWidthInChars
scrollTop: @scrollTop
scrollLeft: @scrollLeft
@@ -96,12 +95,71 @@ class DisplayBuffer extends Model
@rowMap = new RowMap
@updateScreenLines(0, @buffer.getLineCount(), null, suppressChangeEvent: true)
emitChanged: (eventProperties, refreshMarkers=true) ->
onDidChangeSoftWrapped: (callback) ->
@emitter.on 'did-change-soft-wrapped', callback
onDidChangeGrammar: (callback) ->
@tokenizedBuffer.onDidChangeGrammar(callback)
onDidTokenize: (callback) ->
@tokenizedBuffer.onDidTokenize(callback)
onDidChange: (callback) ->
@emitter.on 'did-change', callback
onDidChangeCharacterWidths: (callback) ->
@emitter.on 'did-change-character-widths', callback
observeDecorations: (callback) ->
callback(decoration) for decoration in @getDecorations()
@onDidAddDecoration(callback)
onDidAddDecoration: (callback) ->
@emitter.on 'did-add-decoration', callback
onDidRemoveDecoration: (callback) ->
@emitter.on 'did-remove-decoration', callback
onDidCreateMarker: (callback) ->
@emitter.on 'did-create-marker', callback
onDidUpdateMarkers: (callback) ->
@emitter.on 'did-update-markers', callback
on: (eventName) ->
switch eventName
when 'changed'
Grim.deprecate("Use DisplayBuffer::onDidChange instead")
when 'grammar-changed'
Grim.deprecate("Use DisplayBuffer::onDidChangeGrammar instead")
when 'soft-wrap-changed'
Grim.deprecate("Use DisplayBuffer::onDidChangeSoftWrap instead")
when 'character-widths-changed'
Grim.deprecate("Use DisplayBuffer::onDidChangeCharacterWidths instead")
when 'decoration-added'
Grim.deprecate("Use DisplayBuffer::onDidAddDecoration instead")
when 'decoration-removed'
Grim.deprecate("Use DisplayBuffer::onDidRemoveDecoration instead")
when 'decoration-changed'
Grim.deprecate("Use decoration.getMarker().onDidChange() instead")
when 'decoration-updated'
Grim.deprecate("Use Decoration::onDidChangeProperties instead")
when 'marker-created'
Grim.deprecate("Use Decoration::onDidCreateMarker instead")
when 'markers-updated'
Grim.deprecate("Use Decoration::onDidUpdateMarkers instead")
else
Grim.deprecate("DisplayBuffer::on is deprecated. Use event subscription methods instead.")
EmitterMixin::on.apply(this, arguments)
emitDidChange: (eventProperties, refreshMarkers=true) ->
if refreshMarkers
@pauseMarkerObservers()
@pauseMarkerChangeEvents()
@refreshMarkerScreenPositions()
@emit 'changed', eventProperties
@resumeMarkerObservers()
@emitter.emit 'did-change', eventProperties
@resumeMarkerChangeEvents()
updateWrappedScreenLines: ->
start = 0
@@ -109,7 +167,7 @@ class DisplayBuffer extends Model
@updateAllScreenLines()
screenDelta = @getLastRow() - end
bufferDelta = 0
@emitChanged({ start, end, screenDelta, bufferDelta })
@emitDidChange({ start, end, screenDelta, bufferDelta })
# Sets the visibility of the tokenized buffer.
#
@@ -153,7 +211,7 @@ class DisplayBuffer extends Model
horizontallyScrollable: (reentrant) ->
return false unless @width?
return false if @getSoftWrap()
return false if @isSoftWrapped()
if reentrant
@getScrollWidth() > @getWidth()
else
@@ -178,7 +236,7 @@ class DisplayBuffer extends Model
setWidth: (newWidth) ->
oldWidth = @width
@width = newWidth
@updateWrappedScreenLines() if newWidth isnt oldWidth and @softWrap
@updateWrappedScreenLines() if newWidth isnt oldWidth and @isSoftWrapped()
@setScrollTop(@getScrollTop()) # Ensure scrollTop is still valid in case horizontal scrollbar disappeared
@width
@@ -251,6 +309,7 @@ class DisplayBuffer extends Model
characterWidthsChanged: ->
@computeScrollWidth()
@emit 'character-widths-changed', @scopedCharacterWidthsChangeCount
@emitter.emit 'did-change-character-widths', @scopedCharacterWidthsChangeCount
clearScopedCharWidths: ->
@charWidthsByScope = {}
@@ -344,11 +403,15 @@ class DisplayBuffer extends Model
setInvisibles: (@invisibles) ->
@tokenizedBuffer.setInvisibles(@invisibles)
# Deprecated: Use the softWrap property directly
setSoftWrap: (@softWrap) -> @softWrap
setSoftWrapped: (softWrapped) ->
if softWrapped isnt @softWrapped
@softWrapped = softWrapped
@updateWrappedScreenLines()
@emit 'soft-wrap-changed', @softWrapped
@emitter.emit 'did-change-soft-wrapped', @softWrapped
@softWrapped
# Deprecated: Use the softWrap property directly
getSoftWrap: -> @softWrap
isSoftWrapped: -> @softWrapped
# Set the number of characters that fit horizontally in the editor.
#
@@ -357,7 +420,7 @@ class DisplayBuffer extends Model
if editorWidthInChars > 0
previousWidthInChars = @editorWidthInChars
@editorWidthInChars = editorWidthInChars
if editorWidthInChars isnt previousWidthInChars and @softWrap
if editorWidthInChars isnt previousWidthInChars and @isSoftWrapped()
@updateWrappedScreenLines()
# Returns the editor width in characters for soft wrap.
@@ -627,7 +690,7 @@ class DisplayBuffer extends Model
unless screenLine?
throw new BufferToScreenConversionError "No screen line exists when converting buffer row to screen row",
softWrapEnabled: @getSoftWrap()
softWrapEnabled: @isSoftWrapped()
foldCount: @findFoldMarkers().length
lastBufferRow: @buffer.getLastRow()
lastScreenRow: @getLastRow()
@@ -743,7 +806,7 @@ class DisplayBuffer extends Model
# Returns a {Number} representing the `line` position where the wrap would take place.
# Returns `null` if a wrap wouldn't occur.
findWrapColumn: (line, softWrapColumn=@getSoftWrapColumn()) ->
return unless @softWrap
return unless @isSoftWrapped()
return unless line.length > softWrapColumn
if /\s/.test(line[softWrapColumn])
@@ -766,6 +829,12 @@ class DisplayBuffer extends Model
decorationForId: (id) ->
@decorationsById[id]
getDecorations: ->
allDecorations = []
for markerId, decorations of @decorationsByMarkerId
allDecorations = allDecorations.concat(decorations) if decorations?
allDecorations
decorationsForScreenRowRange: (startScreenRow, endScreenRow) ->
decorationsByMarkerId = {}
for marker in @findMarkers(intersectsScreenRowRange: [startScreenRow, endScreenRow])
@@ -775,24 +844,13 @@ class DisplayBuffer extends Model
decorateMarker: (marker, decorationParams) ->
marker = @getMarker(marker.id)
@decorationMarkerDestroyedSubscriptions[marker.id] ?= @subscribe marker, 'destroyed', =>
@removeAllDecorationsForMarker(marker)
@decorationMarkerChangedSubscriptions[marker.id] ?= @subscribe marker, 'changed', (event) =>
decorations = @decorationsByMarkerId[marker.id]
# Why check existence? Markers may get destroyed or decorations removed
# in the change handler. Bookmarks does this.
if decorations?
for decoration in decorations
@emit 'decoration-changed', marker, decoration, event
decoration = new Decoration(marker, this, decorationParams)
@subscribe decoration.onDidDestroy => @removeDecoration(decoration)
@decorationsByMarkerId[marker.id] ?= []
@decorationsByMarkerId[marker.id].push(decoration)
@decorationsById[decoration.id] = decoration
@emit 'decoration-added', marker, decoration
@emit 'decoration-added', decoration
@emitter.emit 'did-add-decoration', decoration
decoration
removeDecoration: (decoration) ->
@@ -803,41 +861,25 @@ class DisplayBuffer extends Model
if index > -1
decorations.splice(index, 1)
delete @decorationsById[decoration.id]
@emit 'decoration-removed', marker, decoration
@removedAllMarkerDecorations(marker) if decorations.length is 0
@emit 'decoration-removed', decoration
@emitter.emit 'did-remove-decoration', decoration
delete @decorationsByMarkerId[marker.id] if decorations.length is 0
removeAllDecorationsForMarker: (marker) ->
decorations = @decorationsByMarkerId[marker.id].slice()
for decoration in decorations
@emit 'decoration-removed', marker, decoration
@removedAllMarkerDecorations(marker)
removedAllMarkerDecorations: (marker) ->
@decorationMarkerChangedSubscriptions[marker.id].off()
@decorationMarkerDestroyedSubscriptions[marker.id].off()
delete @decorationsByMarkerId[marker.id]
delete @decorationMarkerChangedSubscriptions[marker.id]
delete @decorationMarkerDestroyedSubscriptions[marker.id]
decorationUpdated: (decoration) ->
@emit 'decoration-updated', decoration
# Retrieves a {DisplayBufferMarker} based on its id.
# Retrieves a {Marker} based on its id.
#
# id - A {Number} representing a marker id
#
# Returns the {DisplayBufferMarker} (if it exists).
# Returns the {Marker} (if it exists).
getMarker: (id) ->
unless marker = @markers[id]
if bufferMarker = @buffer.getMarker(id)
marker = new DisplayBufferMarker({bufferMarker, displayBuffer: this})
marker = new Marker({bufferMarker, displayBuffer: this})
@markers[id] = marker
marker
# Retrieves the active markers in the buffer.
#
# Returns an {Array} of existing {DisplayBufferMarker}s.
# Returns an {Array} of existing {Marker}s.
getMarkers: ->
@buffer.getMarkers().map ({id}) => @getMarker(id)
@@ -892,7 +934,7 @@ class DisplayBuffer extends Model
#
# Refer to {DisplayBuffer::findMarkers} for details.
#
# Returns a {DisplayBufferMarker} or null
# Returns a {Marker} or null
findMarker: (params) ->
@findMarkers(params)[0]
@@ -913,7 +955,7 @@ class DisplayBuffer extends Model
# :containedInBufferRange - A {Range} or range-compatible {Array}. Only
# returns markers contained within this range.
#
# Returns an {Array} of {DisplayBufferMarker}s
# Returns an {Array} of {Marker}s
findMarkers: (params) ->
params = @translateToBufferMarkerParams(params)
@buffer.findMarkers(params).map (stringMarker) => @getMarker(stringMarker.id)
@@ -965,12 +1007,13 @@ class DisplayBuffer extends Model
getFoldMarkerAttributes: (attributes={}) ->
_.extend(attributes, class: 'fold', displayBufferId: @id)
pauseMarkerObservers: ->
marker.pauseEvents() for marker in @getMarkers()
pauseMarkerChangeEvents: ->
marker.pauseChangeEvents() for marker in @getMarkers()
resumeMarkerObservers: ->
marker.resumeEvents() for marker in @getMarkers()
resumeMarkerChangeEvents: ->
marker.resumeChangeEvents() for marker in @getMarkers()
@emit 'markers-updated'
@emitter.emit 'did-update-markers'
refreshMarkerScreenPositions: ->
for marker in @getMarkers()
@@ -1012,10 +1055,10 @@ class DisplayBuffer extends Model
bufferDelta: bufferDelta
if options.delayChangeEvent
@pauseMarkerObservers()
@pauseMarkerChangeEvents()
@pendingChangeEvent = changeEvent
else
@emitChanged(changeEvent, options.refreshMarkers)
@emitDidChange(changeEvent, options.refreshMarkers)
buildScreenLines: (startBufferRow, endBufferRow) ->
screenLines = []
@@ -1087,20 +1130,21 @@ class DisplayBuffer extends Model
computeScrollWidth: ->
@scrollWidth = @pixelPositionForScreenPosition([@longestScreenRow, @maxLineLength]).left
@scrollWidth += 1 unless @getSoftWrap()
@scrollWidth += 1 unless @isSoftWrapped()
@setScrollLeft(Math.min(@getScrollLeft(), @getMaxScrollLeft()))
handleBufferMarkersUpdated: =>
if event = @pendingChangeEvent
@pendingChangeEvent = null
@emitChanged(event, false)
@emitDidChange(event, false)
handleBufferMarkerCreated: (marker) =>
@createFoldForMarker(marker) if marker.matchesAttributes(@getFoldMarkerAttributes())
if displayBufferMarker = @getMarker(marker.id)
handleBufferMarkerCreated: (textBufferMarker) =>
@createFoldForMarker(textBufferMarker) if textBufferMarker.matchesParams(@getFoldMarkerAttributes())
if marker = @getMarker(textBufferMarker.id)
# The marker might have been removed in some other handler called before
# this one. Only emit when the marker still exists.
@emit 'marker-created', displayBufferMarker
@emit 'marker-created', marker
@emitter.emit 'did-create-marker', marker
createFoldForMarker: (marker) ->
@decorateMarker(marker, type: 'gutter', class: 'folded')
+46 -25
Ver Arquivo
@@ -31,9 +31,8 @@ EditorComponent = React.createClass
updateRequested: false
updatesPaused: false
updateRequestedWhilePaused: false
cursorsMoved: false
cursorMoved: false
selectionChanged: false
selectionAdded: false
scrollingVertically: false
mouseWheelScreenRow: null
mouseWheelScreenRowClearDelay: 150
@@ -129,6 +128,7 @@ EditorComponent = React.createClass
scrollableInOppositeDirection: verticallyScrollable
verticalScrollbarWidth: verticalScrollbarWidth
horizontalScrollbarHeight: horizontalScrollbarHeight
useHardwareAcceleration: @useHardwareAcceleration
ScrollbarComponent
ref: 'verticalScrollbar'
@@ -141,6 +141,7 @@ EditorComponent = React.createClass
scrollableInOppositeDirection: horizontallyScrollable
verticalScrollbarWidth: verticalScrollbarWidth
horizontalScrollbarHeight: horizontalScrollbarHeight
useHardwareAcceleration: @useHardwareAcceleration
# Also used to measure the height/width of scrollbars after the initial render
ScrollbarCornerComponent
@@ -177,10 +178,16 @@ EditorComponent = React.createClass
@listenForDOMEvents()
@listenForCommands()
@subscribe atom.themes, 'stylesheet-added stylesheet-removed stylesheet-updated', @onStylesheetsChanged
@subscribe atom.themes.onDidAddStylesheet @onStylesheetsChanged
@subscribe atom.themes.onDidUpdateStylesheet @onStylesheetsChanged
@subscribe atom.themes.onDidRemoveStylesheet @onStylesheetsChanged
unless atom.themes.isInitialLoadComplete()
@subscribe atom.themes.onDidReloadAll @onStylesheetsChanged
@subscribe scrollbarStyle.changes, @refreshScrollbars
@domPollingIntervalId = setInterval(@pollDOM, @domPollingInterval)
@updateParentViewFocusedClassIfNeeded({})
@updateParentViewMiniClassIfNeeded({})
@checkForVisibilityChange()
componentWillUnmount: ->
@@ -196,16 +203,16 @@ EditorComponent = React.createClass
@props.editor.setMini(newProps.mini)
componentDidUpdate: (prevProps, prevState) ->
cursorsMoved = @cursorsMoved
cursorMoved = @cursorMoved
selectionChanged = @selectionChanged
@pendingChanges.length = 0
@cursorsMoved = false
@cursorMoved = false
@selectionChanged = false
if @props.editor.isAlive()
@updateParentViewFocusedClassIfNeeded(prevState)
@updateParentViewMiniClassIfNeeded(prevState)
@props.parentView.trigger 'cursor:moved' if cursorsMoved
@props.parentView.trigger 'cursor:moved' if cursorMoved
@props.parentView.trigger 'selection:changed' if selectionChanged
@props.parentView.trigger 'editor:display-updated'
@@ -306,7 +313,7 @@ EditorComponent = React.createClass
if marker.isValid()
for decoration in decorations
if decoration.isType('gutter') or decoration.isType('line')
decorationParams = decoration.getParams()
decorationParams = decoration.getProperties()
screenRange ?= marker.getScreenRange()
headScreenRow ?= marker.getHeadScreenPosition().row
startRow = screenRange.start.row
@@ -333,7 +340,7 @@ EditorComponent = React.createClass
if marker.isValid() and not screenRange.isEmpty()
for decoration in decorations
if decoration.isType('highlight')
decorationParams = decoration.getParams()
decorationParams = decoration.getProperties()
filteredDecorations[markerId] ?=
id: markerId
startPixelPosition: editor.pixelPositionForScreenPosition(screenRange.start)
@@ -345,15 +352,12 @@ EditorComponent = React.createClass
observeEditor: ->
{editor} = @props
@subscribe editor, 'screen-lines-changed', @onScreenLinesChanged
@subscribe editor, 'cursors-moved', @onCursorsMoved
@subscribe editor, 'selection-removed selection-screen-range-changed', @onSelectionChanged
@subscribe editor, 'selection-added', @onSelectionAdded
@subscribe editor, 'decoration-added', @onDecorationChanged
@subscribe editor, 'decoration-removed', @onDecorationChanged
@subscribe editor, 'decoration-changed', @onDecorationChanged
@subscribe editor, 'decoration-updated', @onDecorationChanged
@subscribe editor, 'character-widths-changed', @onCharacterWidthsChanged
@subscribe editor.onDidChange(@onScreenLinesChanged)
@subscribe editor.observeCursors(@onCursorAdded)
@subscribe editor.observeSelections(@onSelectionAdded)
@subscribe editor.observeDecorations(@onDecorationAdded)
@subscribe editor.onDidRemoveDecoration(@onDecorationRemoved)
@subscribe editor.onDidChangeCharacterWidths(@onCharacterWidthsChanged)
@subscribe editor.$scrollTop.changes, @onScrollTopChanged
@subscribe editor.$scrollLeft.changes, @requestUpdate
@subscribe editor.$verticalScrollbarWidth.changes, @requestUpdate
@@ -478,7 +482,7 @@ EditorComponent = React.createClass
'editor:add-selection-above': -> editor.addSelectionAbove()
'editor:split-selections-into-lines': -> editor.splitSelectionsIntoLines()
'editor:toggle-soft-tabs': -> editor.toggleSoftTabs()
'editor:toggle-soft-wrap': -> editor.toggleSoftWrap()
'editor:toggle-soft-wrap': -> editor.toggleSoftWrapped()
'editor:fold-all': -> editor.foldAll()
'editor:unfold-all': -> editor.unfoldAll()
'editor:fold-current-row': -> editor.foldCurrentRow()
@@ -710,8 +714,9 @@ EditorComponent = React.createClass
onStylesheetsChanged: (stylesheet) ->
return unless @performedInitialMeasurement
return unless atom.themes.isInitialLoadComplete()
@refreshScrollbars() if @containsScrollbarSelector(stylesheet)
@refreshScrollbars() if not stylesheet? or @containsScrollbarSelector(stylesheet)
@sampleFontStyling()
@sampleBackgroundColors()
@remeasureCharacterWidths()
@@ -721,17 +726,22 @@ EditorComponent = React.createClass
@pendingChanges.push(change)
@requestUpdate() if editor.intersectsVisibleRowRange(change.start, change.end + 1) # TODO: Use closed-open intervals for change events
onSelectionChanged: (selection) ->
onSelectionAdded: (selection) ->
{editor} = @props
@subscribe selection.onDidChangeRange => @onSelectionChanged(selection)
@subscribe selection.onDidDestroy =>
@onSelectionChanged(selection)
@unsubscribe(selection)
if editor.selectionIntersectsVisibleRowRange(selection)
@selectionChanged = true
@requestUpdate()
onSelectionAdded: (selection) ->
onSelectionChanged: (selection) ->
{editor} = @props
if editor.selectionIntersectsVisibleRowRange(selection)
@selectionChanged = true
@selectionAdded = true
@requestUpdate()
onScrollTopChanged: ->
@@ -749,13 +759,24 @@ EditorComponent = React.createClass
onStoppedScrollingAfterDelay: null # created lazily
onCursorsMoved: ->
@cursorsMoved = true
onCursorAdded: (cursor) ->
@subscribe cursor.onDidChangePosition @onCursorMoved
onCursorMoved: ->
@cursorMoved = true
@requestUpdate()
onDecorationAdded: (decoration) ->
@subscribe decoration.onDidChangeProperties(@onDecorationChanged)
@subscribe decoration.getMarker().onDidChange(@onDecorationChanged)
@requestUpdate()
onDecorationChanged: ->
@requestUpdate()
onDecorationRemoved: ->
@requestUpdate()
onCharacterWidthsChanged: (@scopedCharacterWidthsChangeCount) ->
@requestUpdate()
@@ -935,7 +956,7 @@ EditorComponent = React.createClass
{verticalScrollbar, horizontalScrollbar, scrollbarCorner} = @refs
verticalNode = verticalScrollbar.getDOMNode()
horizontalNode = verticalScrollbar.getDOMNode()
horizontalNode = horizontalScrollbar.getDOMNode()
cornerNode = scrollbarCorner.getDOMNode()
originalVerticalDisplayValue = verticalNode.style.display
+24 -39
Ver Arquivo
@@ -9,6 +9,8 @@ EditorComponent = require './editor-component'
# Public: Represents the entire visual pane in Atom.
#
# The EditorView manages the {Editor}, which manages the file buffers.
# `EditorView` is intentionally sparse. Most of the things you'll want
# to do are on {Editor}.
#
# ## Examples
#
@@ -86,7 +88,7 @@ class EditorView extends View
props.placeholderText = placeholderText
@editor ?= new Editor
buffer: new TextBuffer
softWrap: false
softWrapped: false
tabLength: 2
softTabs: true
mini: mini
@@ -135,7 +137,7 @@ class EditorView extends View
Object.defineProperty @::, 'charWidth', get: -> @editor.getDefaultCharWidth()
Object.defineProperty @::, 'firstRenderedScreenRow', get: -> @component.getRenderedRowRange()[0]
Object.defineProperty @::, 'lastRenderedScreenRow', get: -> @component.getRenderedRowRange()[1]
Object.defineProperty @::, 'active', get: -> @is(@getPane()?.activeView)
Object.defineProperty @::, 'active', get: -> @is(@getPaneView()?.activeView)
Object.defineProperty @::, 'isFocused', get: -> @component?.state.focused
Object.defineProperty @::, 'mini', get: -> @component?.props.mini
@@ -143,12 +145,12 @@ class EditorView extends View
return unless onDom
return if @attached
@attached = true
@component.pollDOM()
@component.checkForVisibilityChange()
@focus() if @focusOnAttach
@addGrammarScopeAttribute()
@subscribe @editor, 'grammar-changed', =>
@addGrammarScopeAttribute()
@subscribe @editor.onDidChangeGrammar => @addGrammarScopeAttribute()
@trigger 'editor:attached', [this]
@@ -219,7 +221,7 @@ class EditorView extends View
To duplicate this editor into the split use:
editorView.getPaneView().getModel().splitLeft(copyActiveItem: true)
"""
pane = @getPane()
pane = @getPaneView()
pane?.splitLeft(pane?.copyActiveItem()).activeView
splitRight: ->
@@ -228,7 +230,7 @@ class EditorView extends View
To duplicate this editor into the split use:
editorView.getPaneView().getModel().splitRight(copyActiveItem: true)
"""
pane = @getPane()
pane = @getPaneView()
pane?.splitRight(pane?.copyActiveItem()).activeView
splitUp: ->
@@ -237,7 +239,7 @@ class EditorView extends View
To duplicate this editor into the split use:
editorView.getPaneView().getModel().splitUp(copyActiveItem: true)
"""
pane = @getPane()
pane = @getPaneView()
pane?.splitUp(pane?.copyActiveItem()).activeView
splitDown: ->
@@ -246,7 +248,7 @@ class EditorView extends View
To duplicate this editor into the split use:
editorView.getPaneView().getModel().splitDown(copyActiveItem: true)
"""
pane = @getPane()
pane = @getPaneView()
pane?.splitDown(pane?.copyActiveItem()).activeView
# Public: Get this {EditorView}'s {PaneView}.
@@ -282,56 +284,39 @@ class EditorView extends View
deprecate 'Use Editor::getLastVisibleScreenRow instead. You can get the editor via editorView.getModel()'
@editor.getLastVisibleScreenRow()
# Public: Gets the font family for the editor.
#
# Returns a {String} identifying the CSS `font-family`.
getFontFamily: ->
deprecate 'This is going away. Use atom.config.get("editor.fontFamily") instead'
@component?.getFontFamily()
# Public: Sets the font family for the editor.
#
# * `fontFamily` A {String} identifying the CSS `font-family`.
setFontFamily: (fontFamily) ->
deprecate 'This is going away. Use atom.config.set("editor.fontFamily", "my-font") instead'
@component?.setFontFamily(fontFamily)
# Public: Retrieves the font size for the editor.
#
# Returns a {Number} indicating the font size in pixels.
getFontSize: ->
deprecate 'This is going away. Use atom.config.get("editor.fontSize") instead'
@component?.getFontSize()
# Public: Sets the font size for the editor.
#
# * `fontSize` A {Number} indicating the font size in pixels.
setFontSize: (fontSize) ->
deprecate 'This is going away. Use atom.config.set("editor.fontSize", 12) instead'
@component?.setFontSize(fontSize)
setLineHeight: (lineHeight) ->
deprecate 'This is going away. Use atom.config.set("editor.lineHeight", 1.5) instead'
@component.setLineHeight(lineHeight)
setWidthInChars: (widthInChars) ->
@component.getDOMNode().style.width = (@editor.getDefaultCharWidth() * widthInChars) + 'px'
# Public: Sets the line height of the editor.
#
# Calling this method has no effect when called on a mini editor.
#
# * `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.
setShowIndentGuide: (showIndentGuide) ->
deprecate 'This is going away. Use atom.config.set("editor.showIndentGuide", true|false) instead'
@component.setShowIndentGuide(showIndentGuide)
setSoftWrap: (softWrap) ->
deprecate 'Use Editor::setSoftWrap instead. You can get the editor via editorView.getModel()'
@editor.setSoftWrap(softWrap)
setSoftWrap: (softWrapped) ->
deprecate 'Use Editor::setSoftWrapped instead. You can get the editor via editorView.getModel()'
@editor.setSoftWrapped(softWrapped)
# Public: Set whether invisible characters are shown.
#
# * `showInvisibles` A {Boolean} which, if `true`, show invisible characters.
setShowInvisibles: (showInvisibles) ->
deprecate 'This is going away. Use atom.config.set("editor.showInvisibles", true|false) instead'
@component.setShowInvisibles(showInvisibles)
getText: ->
+1039 -765
Ver Arquivo
Diferenças do arquivo suprimidas por serem muito extensas Carregar Diff
+332 -261
Ver Arquivo
@@ -1,13 +1,16 @@
{basename, join} = require 'path'
_ = require 'underscore-plus'
{Emitter, Subscriber} = require 'emissary'
{Subscriber} = require 'emissary'
EmitterMixin = require('emissary').Emitter
{Emitter} = require 'event-kit'
fs = require 'fs-plus'
GitUtils = require 'git-utils'
{deprecate} = require 'grim'
Task = require './task'
# Public: Represents the underlying git operations performed by Atom.
# Extended: Represents the underlying git operations performed by Atom.
#
# This class shouldn't be instantiated directly but instead by accessing the
# `atom.project` global and calling `getRepo()`. Note that this will only be
@@ -37,28 +40,13 @@ Task = require './task'
# ### Requiring in packages
#
# ```coffee
# {Git} = require 'atom'
# {GitRepository} = require 'atom'
# ```
module.exports =
class Git
Emitter.includeInto(this)
class GitRepository
EmitterMixin.includeInto(this)
Subscriber.includeInto(this)
# Public: Creates a new Git instance.
#
# * `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.
@open: (path, options) ->
return null unless path
try
new Git(path, options)
catch
null
@exists: (path) ->
if git = @open(path)
git.destroy()
@@ -66,7 +54,27 @@ class Git
else
false
###
Section: Construction and Destruction
###
# Public: Creates a new GitRepository instance.
#
# * `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 {GitRepository} instance or `null` if the repository could not be opened.
@open: (path, options) ->
return null unless path
try
new GitRepository(path, options)
catch
null
constructor: (path, options={}) ->
@emitter = new Emitter
@repo = GitUtils.open(path)
unless @repo?
throw new Error("No Git repository found searching path: #{path}")
@@ -88,6 +96,307 @@ class Git
if @project?
@subscribe @project.eachBuffer (buffer) => @subscribeToBuffer(buffer)
# Public: Destroy this {GitRepository} object.
#
# This destroys any tasks and subscriptions and releases the underlying
# libgit2 repository handle.
destroy: ->
if @statusTask?
@statusTask.terminate()
@statusTask = null
if @repo?
@repo.release()
@repo = null
@unsubscribe()
###
Section: Event Subscription
###
# Public: Invoke the given callback when a specific file's status has
# changed. When a file is updated, reloaded, etc, and the status changes, this
# will be fired.
#
# * `callback` {Function}
# * `event` {Object}
# * `path` {String} the old parameters the decoration used to have
# * `pathStatus` {Number} representing the status. This value can be passed to
# {::isStatusModified} or {::isStatusNew} to get more information.
#
# Returns a {Disposable} on which `.dispose()` can be called to unsubscribe.
onDidChangeStatus: (callback) ->
@emitter.on 'did-change-status', callback
# Public: Invoke the given callback when a multiple files' statuses have
# changed. For example, on window focus, the status of all the paths in the
# repo is checked. If any of them have changed, this will be fired. Call
# {::getPathStatus(path)} to get the status for your path of choice.
#
# * `callback` {Function}
#
# Returns a {Disposable} on which `.dispose()` can be called to unsubscribe.
onDidChangeStatuses: (callback) ->
@emitter.on 'did-change-statuses', callback
on: (eventName) ->
switch eventName
when 'status-changed'
deprecate 'Use GitRepository::onDidChangeStatus instead'
when 'statuses-changed'
deprecate 'Use GitRepository::onDidChangeStatuses instead'
else
deprecate 'GitRepository::on is deprecated. Use event subscription methods instead.'
EmitterMixin::on.apply(this, arguments)
###
Section: Repository Details
###
# Public: Returns the {String} path of the repository.
getPath: ->
@path ?= fs.absolute(@getRepo().getPath())
# Public: Returns the {String} working directory path of the repository.
getWorkingDirectory: -> @getRepo().getWorkingDirectory()
# Public: Returns true if at the root, false if in a subfolder of the
# repository.
isProjectAtRoot: ->
@projectAtRoot ?= @project?.relativize(@getWorkingDirectory()) is ''
# Public: Makes a path relative to the repository's working directory.
relativize: (path) -> @getRepo().relativize(path)
# Public: Returns true if the given branch exists.
hasBranch: (branch) -> @getReferenceTarget("refs/heads/#{branch}")?
# Public: Retrieves a shortened version of the HEAD reference value.
#
# This removes the leading segments of `refs/heads`, `refs/tags`, or
# `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.
#
# Returns a {String}.
getShortHead: (path) -> @getRepo(path).getShortHead()
# Public: Is the given path a submodule in the repository?
#
# * `path` The {String} path to check.
#
# Returns a {Boolean}.
isSubmodule: (path) ->
return false unless path
repo = @getRepo(path)
if repo.isSubmodule(repo.relativize(path))
true
else
# Check if the path is a working directory in a repo that isn't the root.
repo isnt @getRepo() and repo.relativize(join(path, 'dir')) is 'dir'
# 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.
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.
#
# Returns an {Object} with the following keys:
# * `ahead` The {Number} of commits ahead.
# * `behind` The {Number} of commits behind.
getCachedUpstreamAheadBehindCount: (path) ->
@getRepo(path).upstream ? @upstream
# 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.
getConfigValue: (key, path) -> @getRepo(path).getConfigValue(key)
# Public: Returns the origin url of the repository.
#
# * `path` (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.
#
# Returns a {String} branch name such as `refs/remotes/origin/master`.
getUpstreamBranch: (path) -> @getRepo(path).getUpstreamBranch()
# 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.
#
# 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.
getReferences: (path) -> @getRepo(path).getReferences()
# 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.
getReferenceTarget: (reference, path) ->
@getRepo(path).getReferenceTarget(reference)
###
Section: Reading Status
###
# Public: Returns true if the given path is modified.
isPathModified: (path) -> @isStatusModified(@getPathStatus(path))
# Public: Returns true if the given path is new.
isPathNew: (path) -> @isStatusNew(@getPathStatus(path))
# Public: Is the given path ignored?
#
# Returns a {Boolean}.
isPathIgnored: (path) -> @getRepo().isIgnored(@relativize(path))
# Public: Get the status of a directory in the repository's working directory.
#
# * `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.
getDirectoryStatus: (directoryPath) ->
directoryPath = "#{@relativize(directoryPath)}/"
directoryStatus = 0
for path, status of @statuses
directoryStatus |= status if path.indexOf(directoryPath) is 0
directoryStatus
# Public: Get the status of a single path in the repository.
#
# `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.
getPathStatus: (path) ->
repo = @getRepo(path)
relativePath = @relativize(path)
currentPathStatus = @statuses[relativePath] ? 0
pathStatus = repo.getStatus(repo.relativize(path)) ? 0
pathStatus = 0 if repo.isStatusIgnored(pathStatus)
if pathStatus > 0
@statuses[relativePath] = pathStatus
else
delete @statuses[relativePath]
if currentPathStatus isnt pathStatus
@emit 'status-changed', path, pathStatus
@emitter.emit 'did-change-status', {path, pathStatus}
pathStatus
# Public: Get the cached status for the given path.
#
# * `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) ->
@statuses[@relativize(path)]
# Public: Returns true if the given status indicates modification.
isStatusModified: (status) -> @getRepo().isStatusModified(status)
# Public: Returns true if the given status indicates a new path.
isStatusNew: (status) -> @getRepo().isStatusNew(status)
###
Section: Retrieving Diffs
###
# Public: Retrieves the number of lines added and removed to a path.
#
# This compares the working directory contents of the path to the `HEAD`
# version.
#
# * `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.
getDiffStats: (path) ->
repo = @getRepo(path)
repo.getDiffStats(repo.relativize(path))
# 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
#
# 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
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.
options = ignoreEolWhitespace: process.platform is 'win32'
repo = @getRepo(path)
repo.getLineDiffs(repo.relativize(path), text, options)
###
Section: Checking Out
###
# Public: Restore the contents of a path in the working directory and index
# to the version at `HEAD`.
#
# This is essentially the same as running:
#
# ```sh
# git reset HEAD -- <path>
# git checkout HEAD -- <path>
# ```
#
# * `path` The {String} path to checkout.
#
# Returns a {Boolean} that's true if the method was successful.
checkoutHead: (path) ->
repo = @getRepo(path)
headCheckedOut = repo.checkoutHead(repo.relativize(path))
@getPathStatus(path) if headCheckedOut
headCheckedOut
# 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.
#
# Returns a Boolean that's true if the method was successful.
checkoutReference: (reference, create) ->
@getRepo().checkoutReference(reference, create)
###
Section: Private
###
# Subscribes to buffer events.
subscribeToBuffer: (buffer) ->
getBufferPathStatus = =>
@@ -120,21 +429,6 @@ class Git
else
checkoutHead()
# Public: Destroy this {Git} object.
#
# This destroys any tasks and subscriptions and releases the underlying
# libgit2 repository handle.
destroy: ->
if @statusTask?
@statusTask.terminate()
@statusTask = null
if @repo?
@repo.release()
@repo = null
@unsubscribe()
# Returns the corresponding {Repository}
getRepo: (path) ->
if @repo?
@@ -146,231 +440,6 @@ class Git
# last time the index was read.
refreshIndex: -> @getRepo().refreshIndex()
# Public: Returns the {String} path of the repository.
getPath: ->
@path ?= fs.absolute(@getRepo().getPath())
# Public: Returns the {String} working directory path of the repository.
getWorkingDirectory: -> @getRepo().getWorkingDirectory()
# Public: Get the status of a single path in the repository.
#
# `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.
getPathStatus: (path) ->
repo = @getRepo(path)
relativePath = @relativize(path)
currentPathStatus = @statuses[relativePath] ? 0
pathStatus = repo.getStatus(repo.relativize(path)) ? 0
pathStatus = 0 if repo.isStatusIgnored(pathStatus)
if pathStatus > 0
@statuses[relativePath] = pathStatus
else
delete @statuses[relativePath]
if currentPathStatus isnt pathStatus
@emit 'status-changed', path, pathStatus
pathStatus
# Public: Is the given path ignored?
#
# Returns a {Boolean}.
isPathIgnored: (path) -> @getRepo().isIgnored(@relativize(path))
# Public: Returns true if the given status indicates modification.
isStatusModified: (status) -> @getRepo().isStatusModified(status)
# Public: Returns true if the given path is modified.
isPathModified: (path) -> @isStatusModified(@getPathStatus(path))
# Public: Returns true if the given status indicates a new path.
isStatusNew: (status) -> @getRepo().isStatusNew(status)
# Public: Returns true if the given path is new.
isPathNew: (path) -> @isStatusNew(@getPathStatus(path))
# Public: Returns true if at the root, false if in a subfolder of the
# repository.
isProjectAtRoot: ->
@projectAtRoot ?= @project?.relativize(@getWorkingDirectory()) is ''
# Public: Makes a path relative to the repository's working directory.
relativize: (path) -> @getRepo().relativize(path)
# Public: Retrieves a shortened version of the HEAD reference value.
#
# This removes the leading segments of `refs/heads`, `refs/tags`, or
# `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.
#
# Returns a {String}.
getShortHead: (path) -> @getRepo(path).getShortHead()
# Public: Restore the contents of a path in the working directory and index
# to the version at `HEAD`.
#
# This is essentially the same as running:
#
# ```sh
# git reset HEAD -- <path>
# git checkout HEAD -- <path>
# ```
#
# * `path` The {String} path to checkout.
#
# Returns a {Boolean} that's true if the method was successful.
checkoutHead: (path) ->
repo = @getRepo(path)
headCheckedOut = repo.checkoutHead(repo.relativize(path))
@getPathStatus(path) if headCheckedOut
headCheckedOut
# 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.
#
# Returns a Boolean that's true if the method was successful.
checkoutReference: (reference, create) ->
@getRepo().checkoutReference(reference, create)
# Public: Retrieves the number of lines added and removed to a path.
#
# This compares the working directory contents of the path to the `HEAD`
# version.
#
# * `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.
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.
#
# Returns a {Boolean}.
isSubmodule: (path) ->
return false unless path
repo = @getRepo(path)
if repo.isSubmodule(repo.relativize(path))
true
else
# Check if the path is a working directory in a repo that isn't the root.
repo isnt @getRepo() and repo.relativize(join(path, 'dir')) is 'dir'
# Public: Get the status of a directory in the repository's working directory.
#
# * `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.
getDirectoryStatus: (directoryPath) ->
directoryPath = "#{@relativize(directoryPath)}/"
directoryStatus = 0
for path, status of @statuses
directoryStatus |= status if path.indexOf(directoryPath) is 0
directoryStatus
# 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
#
# 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
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.
options = ignoreEolWhitespace: process.platform is 'win32'
repo = @getRepo(path)
repo.getLineDiffs(repo.relativize(path), text, options)
# 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.
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.
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.
#
# Returns a {String} branch name such as `refs/remotes/origin/master`.
getUpstreamBranch: (path) -> @getRepo(path).getUpstreamBranch()
# 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.
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.
#
# 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.
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.
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.
#
# Returns an {Object} with the following keys:
# * `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.
#
# Returns a status {Number} or null if the path is not in the cache.
getCachedPathStatus: (path) ->
@statuses[@relativize(path)]
# Public: Returns true if the given branch exists.
hasBranch: (branch) -> @getReferenceTarget("refs/heads/#{branch}")?
# Refreshes the current git status in an outside process and asynchronously
# updates the relevant properties.
refreshStatus: ->
@@ -391,4 +460,6 @@ class Git
for submodulePath, submoduleRepo of @getRepo().submodules
submoduleRepo.upstream = submodules[submodulePath]?.upstream ? {ahead: 0, behind: 0}
@emit 'statuses-changed' unless statusesUnchanged
unless statusesUnchanged
@emit 'statuses-changed'
@emitter.emit 'did-change-statuses'
+3 -2
Ver Arquivo
@@ -22,11 +22,12 @@ HighlightComponent = React.createClass
{editor, decoration} = @props
if decoration.id?
@decoration = editor.decorationForId(decoration.id)
@decoration.on 'flash', @startFlashAnimation
@decorationDisposable = @decoration.onDidFlash @startFlashAnimation
@startFlashAnimation()
componentWillUnmount: ->
@decoration?.off 'flash', @startFlashAnimation
@decorationDisposable?.dispose()
@decorationDisposable = null
startFlashAnimation: ->
return unless flash = @decoration.consumeNextFlash()
+5 -1
Ver Arquivo
@@ -4,9 +4,13 @@ KeymapManager = require 'atom-keymap'
CSON = require 'season'
{jQuery} = require 'space-pen'
KeymapManager::onDidLoadBundledKeymaps = (callback) ->
@emitter.on 'did-load-bundled-keymaps', callback
KeymapManager::loadBundledKeymaps = ->
@loadKeymap(path.join(@resourcePath, 'keymaps'))
@emit('bundled-keymaps-loaded')
@emit 'bundled-keymaps-loaded'
@emitter.emit 'did-load-bundled-keymaps'
KeymapManager::getUserKeymapPath = ->
if userKeymapPath = CSON.resolve(path.join(@configDirPath, 'keymap'))
+13 -8
Ver Arquivo
@@ -148,15 +148,20 @@ class LanguageMode
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.tokenizedLineForRow(currentRow).isComment()
startRow = currentRow
endRow = bufferRow
for currentRow in [bufferRow+1..@buffer.getLastRow()]
break if @buffer.isRowBlank(currentRow)
break unless @editor.displayBuffer.tokenizedBuffer.tokenizedLineForRow(currentRow).isComment()
endRow = currentRow
if bufferRow > 0
for currentRow in [bufferRow-1..0]
break if @buffer.isRowBlank(currentRow)
break unless @editor.displayBuffer.tokenizedBuffer.tokenizedLineForRow(currentRow).isComment()
startRow = currentRow
if bufferRow < @buffer.getLastRow()
for currentRow in [bufferRow+1..@buffer.getLastRow()]
break if @buffer.isRowBlank(currentRow)
break unless @editor.displayBuffer.tokenizedBuffer.tokenizedLineForRow(currentRow).isComment()
endRow = currentRow
return [startRow, endRow] if startRow isnt endRow
rowRangeForCodeFoldAtBufferRow: (bufferRow) ->
+399
Ver Arquivo
@@ -0,0 +1,399 @@
{Range} = require 'text-buffer'
_ = require 'underscore-plus'
{Subscriber} = require 'emissary'
EmitterMixin = require('emissary').Emitter
{Emitter} = require 'event-kit'
Grim = require 'grim'
# Essential: Represents a buffer annotation that remains logically stationary
# even as the buffer changes. This is used to represent cursors, folds, snippet
# targets, misspelled words, and anything else that needs to track a logical
# location in the buffer over time.
#
# ### Marker Creation
#
# Use {Editor::markBufferRange} rather than creating Markers directly.
#
# ### Head and Tail
#
# Markers always have a *head* and sometimes have a *tail*. If you think of a
# marker as an editor selection, the tail is the part that's stationary and the
# head is the part that moves when the mouse is moved. A marker without a tail
# always reports an empty range at the head position. A marker with a head position
# greater than the tail is in a "normal" orientation. If the head precedes the
# tail the marker is in a "reversed" orientation.
#
# ### Validity
#
# Markers are considered *valid* when they are first created. Depending on the
# invalidation strategy you choose, certain changes to the buffer can cause a
# marker to become invalid, for example if the text surrounding the marker is
# deleted. The strategies, in order of descending fragility:
#
# * __never__: The marker is never marked as invalid. This is a good choice for
# markers representing selections in an editor.
# * __surround__: The marker is invalidated by changes that completely surround it.
# * __overlap__: The marker is invalidated by changes that surround the
# start or end of the marker. This is the default.
# * __inside__: The marker is invalidated by changes that extend into the
# inside of the marker. Changes that end at the marker's start or
# start at the marker's end do not invalidate the marker.
# * __touch__: The marker is invalidated by a change that touches the marked
# region in any way, including changes that end at the marker's
# start or start at the marker's end. This is the most fragile strategy.
#
# See {Editor::markBufferRange} for usage.
module.exports =
class Marker
EmitterMixin.includeInto(this)
Subscriber.includeInto(this)
bufferMarkerSubscription: null
oldHeadBufferPosition: null
oldHeadScreenPosition: null
oldTailBufferPosition: null
oldTailScreenPosition: null
wasValid: true
deferredChangeEvents: null
###
Section: Construction and Destruction
###
constructor: ({@bufferMarker, @displayBuffer}) ->
@emitter = new Emitter
@id = @bufferMarker.id
@oldHeadBufferPosition = @getHeadBufferPosition()
@oldHeadScreenPosition = @getHeadScreenPosition()
@oldTailBufferPosition = @getTailBufferPosition()
@oldTailScreenPosition = @getTailScreenPosition()
@wasValid = @isValid()
@subscribe @bufferMarker.onDidDestroy => @destroyed()
@subscribe @bufferMarker.onDidChange (event) => @notifyObservers(event)
# Essential: Destroys the marker, causing it to emit the 'destroyed' event. Once
# destroyed, a marker cannot be restored by undo/redo operations.
destroy: ->
@bufferMarker.destroy()
@unsubscribe()
# Essential: Creates and returns a new {Marker} with the same properties as this
# marker.
#
# * `properties` {Object}
copy: (properties) ->
@displayBuffer.getMarker(@bufferMarker.copy(properties).id)
###
Section: Event Subscription
###
# Essential: Invoke the given callback when the state of the marker changes.
#
# * `callback` {Function} to be called when the marker changes.
# * `event` {Object} with the following keys:
# * `oldHeadPosition` {Point} representing the former head position
# * `newHeadPosition` {Point} representing the new head position
# * `oldTailPosition` {Point} representing the former tail position
# * `newTailPosition` {Point} representing the new tail position
# * `wasValid` {Boolean} indicating whether the marker was valid before the change
# * `isValid` {Boolean} indicating whether the marker is now valid
# * `hadTail` {Boolean} indicating whether the marker had a tail before the change
# * `hasTail` {Boolean} indicating whether the marker now has a tail
# * `oldProperties` {Object} containing the marker's custom properties before the change.
# * `newProperties` {Object} containing the marker's custom properties after the change.
# * `textChanged` {Boolean} indicating whether this change was caused by a textual change
# to the buffer or whether the marker was manipulated directly via its public API.
#
# Returns a {Disposable} on which `.dispose()` can be called to unsubscribe.
onDidChange: (callback) ->
@emitter.on 'did-change', callback
# Essential: Invoke the given callback when the marker is destroyed.
#
# * `callback` {Function} to be called when the marker is destroyed.
#
# Returns a {Disposable} on which `.dispose()` can be called to unsubscribe.
onDidDestroy: (callback) ->
@emitter.on 'did-destroy', callback
on: (eventName) ->
switch eventName
when 'changed'
Grim.deprecate("Use Marker::onDidChange instead")
when 'destroyed'
Grim.deprecate("Use Marker::onDidDestroy instead")
EmitterMixin::on.apply(this, arguments)
###
Section: Marker Details
###
# Essential: Returns a {Boolean} indicating whether the marker is valid. Markers can be
# invalidated when a region surrounding them in the buffer is changed.
isValid: ->
@bufferMarker.isValid()
# Essential: Returns a {Boolean} indicating whether the marker has been destroyed. A marker
# can be invalid without being destroyed, in which case undoing the invalidating
# operation would restore the marker. Once a marker is destroyed by calling
# {Marker::destroy}, no undo/redo operation can ever bring it back.
isDestroyed: ->
@bufferMarker.isDestroyed()
# Essential: Returns a {Boolean} indicating whether the head precedes the tail.
isReversed: ->
@bufferMarker.isReversed()
# Essential: Get the invalidation strategy for this marker.
#
# Valid values include: `never`, `surround`, `overlap`, `inside`, and `touch`.
#
# Returns a {String}.
getInvalidationStrategy: ->
@bufferMarker.getInvalidationStrategy()
# Essential: Returns an {Object} containing any custom properties associated with
# the marker.
getProperties: ->
@bufferMarker.getProperties()
getAttributes: ->
deprecate 'Use Marker::getProperties instead'
@getProperties()
# Essential: Merges an {Object} containing new properties into the marker's
# existing properties.
#
# * `properties` {Object}
setProperties: (properties) ->
@bufferMarker.setProperties(properties)
setAttributes: (properties) ->
deprecate 'Use Marker::getProperties instead'
@setProperties(properties)
matchesProperties: (attributes) ->
attributes = @displayBuffer.translateToBufferMarkerParams(attributes)
@bufferMarker.matchesParams(attributes)
matchesAttributes: (attributes) ->
deprecate 'Use Marker::matchesProperties instead'
@matchesProperties(attributes)
###
Section: Comparing to other markers
###
# Essential: Returns a {Boolean} indicating whether this marker is equivalent to
# another marker, meaning they have the same range and options.
#
# * `other` {Marker} other marker
isEqual: (other) ->
return false unless other instanceof @constructor
@bufferMarker.isEqual(other.bufferMarker)
# Essential: Compares this marker to another based on their ranges.
#
# * `other` {Marker}
#
# Returns a {Number}
compare: (other) ->
@bufferMarker.compare(other.bufferMarker)
###
Section: Managing the marker's range
###
# Essential: Gets the buffer range of the display marker.
#
# Returns a {Range}.
getBufferRange: ->
@bufferMarker.getRange()
# Essential: Modifies the buffer range of the display marker.
#
# * `bufferRange` The new {Range} to use
# * `properties` (optional) {Object} properties to associate with the marker.
# * `reversed` {Boolean} If true, the marker will to be in a reversed orientation.
setBufferRange: (bufferRange, properties) ->
@bufferMarker.setRange(bufferRange, properties)
# Essential: Gets the screen range of the display marker.
#
# Returns a {Range}.
getScreenRange: ->
@displayBuffer.screenRangeForBufferRange(@getBufferRange(), wrapAtSoftNewlines: true)
# Essential: Modifies the screen range of the display marker.
#
# * `screenRange` The new {Range} to use
# * `properties` (optional) {Object} properties to associate with the marker.
# * `reversed` {Boolean} If true, the marker will to be in a reversed orientation.
setScreenRange: (screenRange, options) ->
@setBufferRange(@displayBuffer.bufferRangeForScreenRange(screenRange), options)
# Essential: Retrieves the buffer position of the marker's start. This will always be
# less than or equal to the result of {Marker::getEndBufferPosition}.
#
# Returns a {Point}.
getStartBufferPosition: ->
@bufferMarker.getStartPosition()
# Essential: Retrieves the screen position of the marker's start. This will always be
# less than or equal to the result of {Marker::getEndScreenPosition}.
#
# Returns a {Point}.
getStartScreenPosition: ->
@displayBuffer.screenPositionForBufferPosition(@getStartBufferPosition(), wrapAtSoftNewlines: true)
# Essential: Retrieves the buffer position of the marker's end. This will always be
# greater than or equal to the result of {Marker::getStartBufferPosition}.
#
# Returns a {Point}.
getEndBufferPosition: ->
@bufferMarker.getEndPosition()
# Essential: Retrieves the screen position of the marker's end. This will always be
# greater than or equal to the result of {Marker::getStartScreenPosition}.
#
# Returns a {Point}.
getEndScreenPosition: ->
@displayBuffer.screenPositionForBufferPosition(@getEndBufferPosition(), wrapAtSoftNewlines: true)
# Extended: Retrieves the buffer position of the marker's head.
#
# Returns a {Point}.
getHeadBufferPosition: ->
@bufferMarker.getHeadPosition()
# Extended: Sets the buffer position of the marker's head.
#
# * `screenRange` The new {Point} to use
# * `properties` (optional) {Object} properties to associate with the marker.
setHeadBufferPosition: (bufferPosition, properties) ->
@bufferMarker.setHeadPosition(bufferPosition, properties)
# Extended: Retrieves the screen position of the marker's head.
#
# Returns a {Point}.
getHeadScreenPosition: ->
@displayBuffer.screenPositionForBufferPosition(@getHeadBufferPosition(), wrapAtSoftNewlines: true)
# Extended: Sets the screen position of the marker's head.
#
# * `screenRange` The new {Point} to use
# * `properties` (optional) {Object} properties to associate with the marker.
setHeadScreenPosition: (screenPosition, properties) ->
screenPosition = @displayBuffer.clipScreenPosition(screenPosition, properties)
@setHeadBufferPosition(@displayBuffer.bufferPositionForScreenPosition(screenPosition, properties))
# Extended: Retrieves the buffer position of the marker's tail.
#
# Returns a {Point}.
getTailBufferPosition: ->
@bufferMarker.getTailPosition()
# Extended: Sets the buffer position of the marker's tail.
#
# * `screenRange` The new {Point} to use
# * `properties` (optional) {Object} properties to associate with the marker.
setTailBufferPosition: (bufferPosition) ->
@bufferMarker.setTailPosition(bufferPosition)
# Extended: Retrieves the screen position of the marker's tail.
#
# Returns a {Point}.
getTailScreenPosition: ->
@displayBuffer.screenPositionForBufferPosition(@getTailBufferPosition(), wrapAtSoftNewlines: true)
# Extended: Sets the screen position of the marker's tail.
#
# * `screenRange` The new {Point} to use
# * `properties` (optional) {Object} properties to associate with the marker.
setTailScreenPosition: (screenPosition, options) ->
screenPosition = @displayBuffer.clipScreenPosition(screenPosition, options)
@setTailBufferPosition(@displayBuffer.bufferPositionForScreenPosition(screenPosition, options))
# Extended: Returns a {Boolean} indicating whether the marker has a tail.
hasTail: ->
@bufferMarker.hasTail()
# Extended: Plants the marker's tail at the current head position. After calling
# the marker's tail position will be its head position at the time of the
# call, regardless of where the marker's head is moved.
#
# * `properties` (optional) {Object} properties to associate with the marker.
plantTail: ->
@bufferMarker.plantTail()
# Extended: Removes the marker's tail. After calling the marker's head position
# will be reported as its current tail position until the tail is planted
# again.
#
# * `properties` (optional) {Object} properties to associate with the marker.
clearTail: (properties) ->
@bufferMarker.clearTail(properties)
###
Section: Private utility methods
###
# Returns a {String} representation of the marker
inspect: ->
"Marker(id: #{@id}, bufferRange: #{@getBufferRange()})"
destroyed: ->
delete @displayBuffer.markers[@id]
@emit 'destroyed'
@emitter.emit 'did-destroy'
@emitter.dispose()
notifyObservers: ({textChanged}) ->
textChanged ?= false
newHeadBufferPosition = @getHeadBufferPosition()
newHeadScreenPosition = @getHeadScreenPosition()
newTailBufferPosition = @getTailBufferPosition()
newTailScreenPosition = @getTailScreenPosition()
isValid = @isValid()
return if _.isEqual(isValid, @wasValid) and
_.isEqual(newHeadBufferPosition, @oldHeadBufferPosition) and
_.isEqual(newHeadScreenPosition, @oldHeadScreenPosition) and
_.isEqual(newTailBufferPosition, @oldTailBufferPosition) and
_.isEqual(newTailScreenPosition, @oldTailScreenPosition)
changeEvent = {
@oldHeadScreenPosition, newHeadScreenPosition,
@oldTailScreenPosition, newTailScreenPosition,
@oldHeadBufferPosition, newHeadBufferPosition,
@oldTailBufferPosition, newTailBufferPosition,
textChanged,
isValid
}
if @deferredChangeEvents?
@deferredChangeEvents.push(changeEvent)
else
@emit 'changed', changeEvent
@emitter.emit 'did-change', changeEvent
@oldHeadBufferPosition = newHeadBufferPosition
@oldHeadScreenPosition = newHeadScreenPosition
@oldTailBufferPosition = newTailBufferPosition
@oldTailScreenPosition = newTailScreenPosition
@wasValid = isValid
pauseChangeEvents: ->
@deferredChangeEvents = []
resumeChangeEvents: ->
if deferredChangeEvents = @deferredChangeEvents
@deferredChangeEvents = null
for event in deferredChangeEvents
@emit 'changed', event
@emitter.emit 'did-change', event
getPixelRange: ->
@displayBuffer.pixelRangeForScreenRange(@getScreenRange(), false)
+3 -3
Ver Arquivo
@@ -5,7 +5,7 @@ ipc = require 'ipc'
CSON = require 'season'
fs = require 'fs-plus'
# Public: Provides a registry for menu items that you'd like to appear in the
# Extended: Provides a registry for menu items that you'd like to appear in the
# application menu.
#
# An instance of this class is always available as the `atom.menu` global.
@@ -14,8 +14,8 @@ class MenuManager
constructor: ({@resourcePath}) ->
@pendingUpdateOperation = null
@template = []
atom.keymaps.on 'bundled-keymaps-loaded', => @loadPlatformItems()
atom.packages.on 'activated', => @sortPackagesMenu()
atom.keymaps.onDidLoadBundledKeymaps => @loadPlatformItems()
atom.packages.onDidActivateAll => @sortPackagesMenu()
# Public: Adds the given items to the application menu.
#
+206 -141
Ver Arquivo
@@ -1,14 +1,16 @@
path = require 'path'
_ = require 'underscore-plus'
{Emitter} = require 'emissary'
EmitterMixin = require('emissary').Emitter
{Emitter} = require 'event-kit'
fs = require 'fs-plus'
Q = require 'q'
{deprecate} = require 'grim'
Package = require './package'
ThemePackage = require './theme-package'
# Public: Package manager for coordinating the lifecycle of Atom packages.
# Extended: Package manager for coordinating the lifecycle of Atom packages.
#
# An instance of this class is always available as the `atom.packages` global.
#
@@ -25,9 +27,10 @@ ThemePackage = require './theme-package'
# settings and also by calling `enablePackage()/disablePackage()`.
module.exports =
class PackageManager
Emitter.includeInto(this)
EmitterMixin.includeInto(this)
constructor: ({configDirPath, devMode, safeMode, @resourcePath}) ->
@emitter = new Emitter
@packageDirPaths = []
unless safeMode
if devMode
@@ -41,7 +44,41 @@ class PackageManager
@packageActivators = []
@registerPackageActivator(this, ['atom', 'textmate'])
# Extended: Get the path to the apm command.
###
Section: Event Subscription
###
# Public: Invoke the given callback when all packages have been activated.
#
# * `callback` {Function}
#
# Returns a {Disposable} on which `.dispose()` can be called to unsubscribe.
onDidLoadAll: (callback) ->
@emitter.on 'did-load-all', callback
# Public: Invoke the given callback when all packages have been activated.
#
# * `callback` {Function}
#
# Returns a {Disposable} on which `.dispose()` can be called to unsubscribe.
onDidActivateAll: (callback) ->
@emitter.on 'did-activate-all', callback
on: (eventName) ->
switch eventName
when 'loaded'
deprecate 'Use PackageManager::onDidLoadAll instead'
when 'activated'
deprecate 'Use PackageManager::onDidActivateAll instead'
else
deprecate 'PackageManager::on is deprecated. Use event subscription methods instead.'
EmitterMixin::on.apply(this, arguments)
###
Section: Package system data
###
# Public: Get the path to the apm command.
#
# Return a {String} file path to apm.
getApmPath: ->
@@ -49,19 +86,43 @@ class PackageManager
commandName += '.cmd' if process.platform is 'win32'
@apmPath ?= path.resolve(__dirname, '..', 'apm', 'node_modules', 'atom-package-manager', 'bin', commandName)
# Extended: Get the paths being used to look for packages.
# Public: Get the paths being used to look for packages.
#
# Returns an {Array} of {String} directory paths.
getPackageDirPaths: ->
_.clone(@packageDirPaths)
getPackageState: (name) ->
@packageStates[name]
###
Section: General package data
###
setPackageState: (name, state) ->
@packageStates[name] = state
# Public: 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)
# Extended: Enable the package with the given name.
packagePath = fs.resolve(@packageDirPaths..., name)
return packagePath if fs.isDirectorySync(packagePath)
packagePath = path.join(@resourcePath, 'node_modules', name)
return packagePath if @hasAtomEngine(packagePath)
# Public: Is the package with the given name bundled with Atom?
#
# * `name` - The {String} package name.
#
# Returns a {Boolean}.
isBundledPackage: (name) ->
@getPackageDependencies().hasOwnProperty(name)
###
Section: Enabling and disabling packages
###
# Public: Enable the package with the given name.
#
# Returns the {Package} that was enabled or null if it isn't loaded.
enablePackage: (name) ->
@@ -69,7 +130,7 @@ class PackageManager
pack?.enable()
pack
# Extended: Disable the package with the given name.
# Public: Disable the package with the given name.
#
# Returns the {Package} that was disabled or null if it isn't loaded.
disablePackage: (name) ->
@@ -77,50 +138,23 @@ class PackageManager
pack?.disable()
pack
# Activate all the packages that should be activated.
activate: ->
for [activator, types] in @packageActivators
packages = @getLoadedPackagesForTypes(types)
activator.activatePackages(packages)
@emit 'activated'
# Public: 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)
# another type of package manager can handle other package types.
# See ThemeManager
registerPackageActivator: (activator, types) ->
@packageActivators.push([activator, types])
###
Section: Accessing active packages
###
activatePackages: (packages) ->
@activatePackage(pack.name) for pack in packages
@observeDisabledPackages()
# Activate a single package by name
activatePackage: (name) ->
if pack = @getActivePackage(name)
Q(pack)
else
pack = @loadPackage(name)
pack.activate().then =>
@activePackages[pack.name] = pack
pack
# Deactivate all packages
deactivatePackages: ->
@deactivatePackage(pack.name) for pack in @getLoadedPackages()
@unobserveDisabledPackages()
# Deactivate the package with the given name
deactivatePackage: (name) ->
pack = @getLoadedPackage(name)
if @isPackageActive(name)
@setPackageState(pack.name, state) if state = pack.serialize?()
pack.deactivate()
delete @activePackages[pack.name]
# Essential: Get an {Array} of all the active {Package}s.
# Public: Get an {Array} of all the active {Package}s.
getActivePackages: ->
_.values(@activePackages)
# Essential: Get the active {Package} with the given name.
# Public: Get the active {Package} with the given name.
#
# * `name` - The {String} package name.
#
@@ -136,6 +170,91 @@ class PackageManager
isPackageActive: (name) ->
@getActivePackage(name)?
###
Section: Accessing loaded packages
###
# Public: 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'].
getLoadedPackagesForTypes: (types) ->
pack for pack in @getLoadedPackages() when pack.getType() in types
# Public: 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?
#
# * `name` - The {String} package name.
#
# Returns a {Boolean}.
isPackageLoaded: (name) ->
@getLoadedPackage(name)?
###
Section: Accessing available packages
###
# Public: Get an {Array} of {String}s of all the available package paths.
getAvailablePackagePaths: ->
packagePaths = []
for packageDirPath in @packageDirPaths
for packagePath in fs.listSync(packageDirPath)
packagePaths.push(packagePath) if fs.isDirectorySync(packagePath)
packagesPath = path.join(@resourcePath, 'node_modules')
for packageName, packageVersion of @getPackageDependencies()
packagePath = path.join(packagesPath, packageName)
packagePaths.push(packagePath) if fs.isDirectorySync(packagePath)
_.uniq(packagePaths)
# Public: 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 {String}s of all the available package metadata.
getAvailablePackageMetadata: ->
packages = []
for packagePath in @getAvailablePackagePaths()
name = path.basename(packagePath)
metadata = @getLoadedPackage(name)?.metadata ? Package.loadMetadata(packagePath, true)
packages.push(metadata)
packages
###
Section: Private
###
getPackageState: (name) ->
@packageStates[name]
setPackageState: (name, state) ->
@packageStates[name] = state
getPackageDependencies: ->
unless @packageDependencies?
try
metadataPath = path.join(@resourcePath, 'package.json')
{@packageDependencies} = JSON.parse(fs.readFileSync(metadataPath)) ? {}
@packageDependencies ?= {}
@packageDependencies
hasAtomEngine: (packagePath) ->
metadata = Package.loadMetadata(packagePath, true)
metadata?.engines?.atom?
unobserveDisabledPackages: ->
@disabledPackagesSubscription?.off()
@disabledPackagesSubscription = null
@@ -159,8 +278,11 @@ class PackageManager
packagePaths = _.uniq packagePaths, (packagePath) -> path.basename(packagePath)
@loadPackage(packagePath) for packagePath in packagePaths
@emit 'loaded'
@emitter.emit 'did-load-all'
loadPackage: (nameOrPath) ->
return pack if pack = @getLoadedPackage(nameOrPath)
if packagePath = @resolvePackagePath(nameOrPath)
name = path.basename(nameOrPath)
return pack if pack = @getLoadedPackage(name)
@@ -193,99 +315,42 @@ class PackageManager
else
throw new Error("No loaded package for name '#{name}'")
# Essential: Get the loaded {Package} with the given name.
#
# * `name` - The {String} package name.
#
# Returns a {Package} or undefined.
getLoadedPackage: (name) ->
@loadedPackages[name]
# Activate all the packages that should be activated.
activate: ->
for [activator, types] in @packageActivators
packages = @getLoadedPackagesForTypes(types)
activator.activatePackages(packages)
@emit 'activated'
@emitter.emit 'did-activate-all'
# Essential: Is the package with the given name loaded?
#
# * `name` - The {String} package name.
#
# Returns a {Boolean}.
isPackageLoaded: (name) ->
@getLoadedPackage(name)?
# another type of package manager can handle other package types.
# See ThemeManager
registerPackageActivator: (activator, types) ->
@packageActivators.push([activator, types])
# Essential: Get an {Array} of all the loaded {Package}s
getLoadedPackages: ->
_.values(@loadedPackages)
activatePackages: (packages) ->
@activatePackage(pack.name) for pack in packages
@observeDisabledPackages()
# Get packages for a certain package type
#
# * `types` an {Array} of {String}s like ['atom', 'textmate'].
getLoadedPackagesForTypes: (types) ->
pack for pack in @getLoadedPackages() when pack.getType() in types
# Activate a single package by name
activatePackage: (name) ->
if pack = @getActivePackage(name)
Q(pack)
else
pack = @loadPackage(name)
pack.activate().then =>
@activePackages[pack.name] = pack
pack
# 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)
# Deactivate all packages
deactivatePackages: ->
@deactivatePackage(pack.name) for pack in @getLoadedPackages()
@unobserveDisabledPackages()
packagePath = fs.resolve(@packageDirPaths..., name)
return packagePath if fs.isDirectorySync(packagePath)
packagePath = path.join(@resourcePath, 'node_modules', name)
return packagePath if @hasAtomEngine(packagePath)
# 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)
hasAtomEngine: (packagePath) ->
metadata = Package.loadMetadata(packagePath, true)
metadata?.engines?.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)
getPackageDependencies: ->
unless @packageDependencies?
try
metadataPath = path.join(@resourcePath, 'package.json')
{@packageDependencies} = JSON.parse(fs.readFileSync(metadataPath)) ? {}
@packageDependencies ?= {}
@packageDependencies
# Extended: Get an {Array} of {String}s of all the available package paths.
getAvailablePackagePaths: ->
packagePaths = []
for packageDirPath in @packageDirPaths
for packagePath in fs.listSync(packageDirPath)
packagePaths.push(packagePath) if fs.isDirectorySync(packagePath)
packagesPath = path.join(@resourcePath, 'node_modules')
for packageName, packageVersion of @getPackageDependencies()
packagePath = path.join(packagesPath, packageName)
packagePaths.push(packagePath) if fs.isDirectorySync(packagePath)
_.uniq(packagePaths)
# Extended: Get an {Array} of {String}s of all the available package names.
getAvailablePackageNames: ->
_.uniq _.map @getAvailablePackagePaths(), (packagePath) -> path.basename(packagePath)
# Extended: Get an {Array} of {String}s of all the available package metadata.
getAvailablePackageMetadata: ->
packages = []
for packagePath in @getAvailablePackagePaths()
name = path.basename(packagePath)
metadata = @getLoadedPackage(name)?.metadata ? Package.loadMetadata(packagePath, true)
packages.push(metadata)
packages
# Deactivate the package with the given name
deactivatePackage: (name) ->
pack = @getLoadedPackage(name)
if @isPackageActive(name)
@setPackageState(pack.name, state) if state = pack.serialize?()
pack.deactivate()
delete @activePackages[pack.name]
+40 -4
Ver Arquivo
@@ -4,8 +4,10 @@ _ = require 'underscore-plus'
async = require 'async'
CSON = require 'season'
fs = require 'fs-plus'
{Emitter} = require 'emissary'
EmitterMixin = require('emissary').Emitter
{Emitter} = require 'event-kit'
Q = require 'q'
{deprecate} = require 'grim'
$ = null # Defer require in case this is in the window-less browser process
ScopedProperties = require './scoped-properties'
@@ -14,7 +16,7 @@ ScopedProperties = require './scoped-properties'
# stylesheets, keymaps, grammar, editor properties, and menus.
module.exports =
class Package
Emitter.includeInto(this)
EmitterMixin.includeInto(this)
@stylesheetsDir: 'stylesheets'
@@ -37,11 +39,40 @@ class Package
resolvedMainModulePath: false
mainModule: null
###
Section: Construction
###
constructor: (@path, @metadata) ->
@emitter = new Emitter
@metadata ?= Package.loadMetadata(@path)
@name = @metadata?.name ? path.basename(@path)
@reset()
###
Section: Event Subscription
###
# Essential: Invoke the given callback when all packages have been activated.
#
# * `callback` {Function}
#
# Returns a {Disposable} on which `.dispose()` can be called to unsubscribe.
onDidDeactivate: (callback) ->
@emitter.on 'did-deactivate', callback
on: (eventName) ->
switch eventName
when 'deactivated'
deprecate 'Use Package::onDidDeactivate instead'
else
deprecate 'Package::on is deprecated. Use event subscription methods instead.'
EmitterMixin::on.apply(this, arguments)
###
Section: Instance Methods
###
enable: ->
atom.config.removeAtKeyPath('core.disabledPackages', @name)
@@ -242,8 +273,13 @@ class Package
@unsubscribeFromActivationEvents()
@deactivateResources()
@deactivateConfig()
@mainModule?.deactivate?() if @mainActivated
@emit('deactivated')
if @mainActivated
try
@mainModule?.deactivate?()
catch e
console.error "Error deactivating package '#{@name}'", e.stack
@emit 'deactivated'
@emitter.emit 'did-deactivate'
deactivateConfig: ->
@mainModule?.deactivateConfig?()
+23 -6
Ver Arquivo
@@ -6,7 +6,7 @@ PropertyAccessors = require 'property-accessors'
Pane = require './pane'
# Extended: A container which can contains multiple items to be switched between.
# A container which can contains multiple items to be switched between.
#
# Items can be almost anything however most commonly they're {EditorView}s.
#
@@ -147,6 +147,9 @@ class PaneView extends View
@activeItem
onActiveItemChanged: (item) =>
@activeItemDisposables.dispose() if @activeItemDisposables?
@activeItemDisposables = new CompositeDisposable()
if @previousActiveItem?.off?
@previousActiveItem.off 'title-changed', @activeItemTitleChanged
@previousActiveItem.off 'modified-status-changed', @activeItemModifiedChanged
@@ -154,15 +157,29 @@ class PaneView extends View
return unless item?
hasFocus = @hasFocus()
if item.on?
item.on 'title-changed', @activeItemTitleChanged
item.on 'modified-status-changed', @activeItemModifiedChanged
if item.onDidChangeTitle?
disposable = item.onDidChangeTitle(@activeItemTitleChanged)
deprecate 'Please return a Disposable object from your ::onDidChangeTitle method!' unless disposable?.dispose?
@activeItemDisposables.add(disposable) if disposable?.dispose?
else if item.on?
deprecate '::on methods for items are no longer supported. If you would like your item to support title change behavior, please implement a ::onDidChangeTitle() method.'
disposable = item.on('title-changed', @activeItemTitleChanged)
@activeItemDisposables.add(disposable) if disposable?.dispose?
if item.onDidChangeModified?
disposable = item.onDidChangeModified(@activeItemModifiedChanged)
deprecate 'Please return a Disposable object from your ::onDidChangeModified method!' unless disposable?.dispose?
@activeItemDisposables.add(disposable) if disposable?.dispose?
else if item.on?
deprecate '::on methods for items are no longer supported. If you would like your item to support modified behavior, please implement a ::onDidChangeModified() method.'
item.on('modified-status-changed', @activeItemModifiedChanged)
@activeItemDisposables.add(disposable) if disposable?.dispose?
view = @viewForItem(item)
otherView.hide() for otherView in @itemViews.children().not(view).views()
@itemViews.append(view) unless view.parent().is(@itemViews)
view.show() if @attached
view.focus() if hasFocus
view.focus() if @hasFocus()
@trigger 'pane:active-item-changed', [item]
+1
Ver Arquivo
@@ -518,6 +518,7 @@ class Pane extends Model
destroyed: ->
@container.activateNextPane() if @isActive()
@emitter.emit 'did-destroy'
@emitter.dispose()
item.destroy?() for item in @items.slice()
###
+121 -112
Ver Arquivo
@@ -13,37 +13,26 @@ TextBuffer = require 'text-buffer'
Editor = require './editor'
Task = require './task'
Git = require './git'
GitRepository = require './git-repository'
# 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) ->
deprecate '::pathForRepositoryUrl will be removed. Please remove from your code.'
[repoName] = url.parse(repoUrl).path.split('/')[-1..]
repoName = repoName.replace(/\.git$/, '')
path.join(atom.config.get('core.projectHome'), repoName)
###
Section: Construction and Destruction
###
constructor: ({path, @buffers}={}) ->
@buffers ?= []
@@ -53,14 +42,6 @@ class Project extends Model
@setPath(path)
serializeParams: ->
path: @path
buffers: _.compact(@buffers.map (buffer) -> buffer.serialize() if buffer.isRetained())
deserializeParams: (params) ->
params.buffers = params.buffers.map (bufferState) -> atom.deserializers.deserialize(bufferState)
params
destroyed: ->
buffer.destroy() for buffer in @getBuffers()
@destroyRepo()
@@ -73,9 +54,29 @@ class Project extends Model
destroyUnretainedBuffers: ->
buffer.destroy() for buffer in @getBuffers() when not buffer.isRetained()
# Public: Returns the {Git} repository if available.
###
Section: Serialization
###
serializeParams: ->
path: @path
buffers: _.compact(@buffers.map (buffer) -> buffer.serialize() if buffer.isRetained())
deserializeParams: (params) ->
params.buffers = params.buffers.map (bufferState) -> atom.deserializers.deserialize(bufferState)
params
###
Section: Accessing the git repository
###
# Public: Returns the {GitRepository} if available.
getRepo: -> @repo
###
Section: Managing Paths
###
# Public: Returns the project's {String} fullpath.
getPath: ->
@rootDirectory?.path
@@ -92,7 +93,7 @@ class Project extends Model
if projectPath?
directory = if fs.isDirectorySync(projectPath) then projectPath else path.dirname(projectPath)
@rootDirectory = new Directory(directory)
if @repo = Git.open(directory, project: this)
if @repo = GitRepository.open(directory, project: this)
@repo.refreshIndex()
@repo.refreshStatus()
else
@@ -137,6 +138,99 @@ class Project extends Model
contains: (pathToCheck) ->
@rootDirectory?.contains(pathToCheck) ? false
###
Section: Searching and Replacing
###
# Public: Performs a search across all the files in the project.
#
# * `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
options = {}
deferred = Q.defer()
searchOptions =
ignoreCase: regex.ignoreCase
inclusions: options.paths
includeHidden: true
excludeVcsIgnores: atom.config.get('core.excludeVcsIgnoredPaths')
exclusions: atom.config.get('core.ignoredNames')
task = Task.once require.resolve('./scan-handler'), @getPath(), regex.source, searchOptions, ->
deferred.resolve()
task.on 'scan:result-found', (result) =>
iterator(result) unless @isPathModified(result.filePath)
task.on 'scan:file-error', (error) ->
iterator(null, error)
if _.isFunction(options.onPathsSearched)
task.on 'scan:paths-searched', (numberOfPathsSearched) ->
options.onPathsSearched(numberOfPathsSearched)
for buffer in @getBuffers() when buffer.isModified()
filePath = buffer.getPath()
continue unless @contains(filePath)
matches = []
buffer.scan regex, (match) -> matches.push match
iterator {filePath, matches} if matches.length > 0
promise = deferred.promise
promise.cancel = ->
task.terminate()
deferred.resolve('cancelled')
promise
# 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:
# * `options` {Object} with keys `filePath` and `replacements`
replace: (regex, replacementText, filePaths, iterator) ->
deferred = Q.defer()
openPaths = (buffer.getPath() for buffer in @getBuffers())
outOfProcessPaths = _.difference(filePaths, openPaths)
inProcessFinished = !openPaths.length
outOfProcessFinished = !outOfProcessPaths.length
checkFinished = ->
deferred.resolve() if outOfProcessFinished and inProcessFinished
unless outOfProcessFinished.length
flags = 'g'
flags += 'i' if regex.ignoreCase
task = Task.once require.resolve('./replace-handler'), outOfProcessPaths, regex.source, flags, replacementText, ->
outOfProcessFinished = true
checkFinished()
task.on 'replace:path-replaced', iterator
task.on 'replace:file-error', (error) -> iterator(null, error)
for buffer in @getBuffers()
continue unless buffer.getPath() in filePaths
replacements = buffer.replace(regex, replacementText, iterator)
iterator({filePath: buffer.getPath(), replacements}) if replacements
inProcessFinished = true
checkFinished()
deferred.promise
###
Section: Private
###
# Given a path to a file, this constructs and associates a new
# {Editor}, showing the file.
#
@@ -235,91 +329,6 @@ class Project extends Model
[buffer] = @buffers.splice(index, 1)
buffer?.destroy()
# Public: Performs a search across all the files in the project.
#
# * `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
options = {}
deferred = Q.defer()
searchOptions =
ignoreCase: regex.ignoreCase
inclusions: options.paths
includeHidden: true
excludeVcsIgnores: atom.config.get('core.excludeVcsIgnoredPaths')
exclusions: atom.config.get('core.ignoredNames')
task = Task.once require.resolve('./scan-handler'), @getPath(), regex.source, searchOptions, ->
deferred.resolve()
task.on 'scan:result-found', (result) =>
iterator(result) unless @isPathModified(result.filePath)
task.on 'scan:file-error', (error) ->
iterator(null, error)
if _.isFunction(options.onPathsSearched)
task.on 'scan:paths-searched', (numberOfPathsSearched) ->
options.onPathsSearched(numberOfPathsSearched)
for buffer in @getBuffers() when buffer.isModified()
filePath = buffer.getPath()
continue unless @contains(filePath)
matches = []
buffer.scan regex, (match) -> matches.push match
iterator {filePath, matches} if matches.length > 0
promise = deferred.promise
promise.cancel = ->
task.terminate()
deferred.resolve('cancelled')
promise
# 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:
# * `options` {Object} with keys `filePath` and `replacements`
replace: (regex, replacementText, filePaths, iterator) ->
deferred = Q.defer()
openPaths = (buffer.getPath() for buffer in @getBuffers())
outOfProcessPaths = _.difference(filePaths, openPaths)
inProcessFinished = !openPaths.length
outOfProcessFinished = !outOfProcessPaths.length
checkFinished = ->
deferred.resolve() if outOfProcessFinished and inProcessFinished
unless outOfProcessFinished.length
flags = 'g'
flags += 'i' if regex.ignoreCase
task = Task.once require.resolve('./replace-handler'), outOfProcessPaths, regex.source, flags, replacementText, ->
outOfProcessFinished = true
checkFinished()
task.on 'replace:path-replaced', iterator
task.on 'replace:file-error', (error) -> iterator(null, error)
for buffer in @getBuffers()
continue unless buffer.getPath() in filePaths
replacements = buffer.replace(regex, replacementText, iterator)
iterator({filePath: buffer.getPath(), replacements}) if replacements
inProcessFinished = true
checkFinished()
deferred.promise
buildEditorForBuffer: (buffer, editorOptions) ->
editor = new Editor(_.extend({buffer, registerEditor: true}, editorOptions))
editor
+1 -1
Ver Arquivo
@@ -1,6 +1,6 @@
{View} = require './space-pen-extensions'
# Public: Represents a view that scrolls.
# Extended: Represents a view that scrolls.
#
# Handles several core events to update scroll position:
#
+2
Ver Arquivo
@@ -9,9 +9,11 @@ ScrollbarComponent = React.createClass
render: ->
{orientation, className, scrollHeight, scrollWidth, visible} = @props
{scrollableInOppositeDirection, horizontalScrollbarHeight, verticalScrollbarWidth} = @props
{useHardwareAcceleration} = @props
style = {}
style.display = 'none' unless visible
style.transform = 'translateZ(0)' if useHardwareAcceleration # See atom/atom#3559
switch orientation
when 'vertical'
style.width = verticalScrollbarWidth
+130 -106
Ver Arquivo
@@ -46,7 +46,11 @@ class SelectListView extends View
inputThrottle: 50
cancelling: false
# Public: Initialize the select list view.
###
Section: Construction
###
# Essential: Initialize the select list view.
#
# This method can be overridden by subclasses but `super` should always
# be called.
@@ -85,13 +89,39 @@ class SelectListView extends View
@confirmSelection() if $(e.target).closest('li').hasClass('selected')
e.preventDefault()
schedulePopulateList: ->
clearTimeout(@scheduleTimeout)
populateCallback = =>
@populateList() if @isOnDom()
@scheduleTimeout = setTimeout(populateCallback, @inputThrottle)
###
Section: Methods that must be overridden
###
# Public: Set the array of items to display in the list.
# Essential: Create a view for the given model item.
#
# This method must be overridden by subclasses.
#
# 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}.
#
# Returns a String of HTML, DOM element, jQuery object, or View.
viewForItem: (item) ->
throw new Error("Subclass must implement a viewForItem(item) method")
# Essential: Callback function for when an item is selected.
#
# This method must be overridden by subclasses.
#
# * `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) ->
throw new Error("Subclass must implement a confirmed(item) method")
###
Section: Managing the list of items
###
# Essential: Set the array of items to display in the list.
#
# 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.
@@ -101,30 +131,26 @@ class SelectListView extends View
@populateList()
@setLoading()
# Public: Set the error message to display.
# Essential: Get the model item that is currently selected in the list view.
#
# * `message` The {String} error message (default: '').
setError: (message='') ->
if message.length is 0
@error.text('').hide()
else
@setLoading()
@error.text(message).show()
# Returns a model item.
getSelectedItem: ->
@getSelectedItemView().data('select-list-item')
# Public: Set the loading message to display.
# Extended: Get the property name to use when filtering items.
#
# * `message` The {String} loading message (default: '').
setLoading: (message='') ->
if message.length is 0
@loading.text("")
@loadingBadge.text("")
@loadingArea.hide()
else
@setError()
@loading.text(message)
@loadingArea.show()
# This method may be overridden by classes to allow fuzzy filtering based
# on a specific property of the item objects.
#
# For example if the objects you pass to {::setItems} are of the type
# `{"id": 3, "name": "Atom"}` then you would return `"name"` from this method
# to fuzzy filter by that property when text is entered into this view's
# editor.
#
# Returns the property name to fuzzy filter by.
getFilterKey: ->
# Public: Get the filter query to use when fuzzy filtering the visible
# Extended: Get the filter query to use when fuzzy filtering the visible
# elements.
#
# By default this method returns the text in the mini editor but it can be
@@ -134,7 +160,12 @@ class SelectListView extends View
getFilterQuery: ->
@filterEditorView.getEditor().getText()
# Public: Populate the list view with the model items previously set by
# Extended: Set the maximum numbers of items to display in the list.
#
# * `maxItems` The maximum {Number} of items to display.
setMaxItems: (@maxItems) ->
# Extended: Populate the list view with the model items previously set by
# calling {::setItems}.
#
# Subclasses may override this method but should always call `super`.
@@ -161,7 +192,34 @@ class SelectListView extends View
else
@setError(@getEmptyMessage(@items.length, filteredItems.length))
# Public: Get the message to display when there are no items.
###
Section: Messages to the user
###
# Essential: Set the error message to display.
#
# * `message` The {String} error message (default: '').
setError: (message='') ->
if message.length is 0
@error.text('').hide()
else
@setLoading()
@error.text(message).show()
# Essential: Set the loading message to display.
#
# * `message` The {String} loading message (default: '').
setLoading: (message='') ->
if message.length is 0
@loading.text("")
@loadingBadge.text("")
@loadingArea.hide()
else
@setError()
@loading.text(message)
@loadingArea.show()
# Extended: Get the message to display when there are no items.
#
# Subclasses may override this method to customize the message.
#
@@ -171,10 +229,36 @@ class SelectListView extends View
# 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.
###
Section: View Actions
###
# Essential: Cancel and close this select list view.
#
# * `maxItems` The maximum {Number} of items to display.
setMaxItems: (@maxItems) ->
# This restores focus to the previously focused element if
# {::storeFocusedElement} was called prior to this view being attached.
cancel: ->
@list.empty()
@cancelling = true
filterEditorViewFocused = @filterEditorView.isFocused
@cancelled()
@detach()
@restoreFocus() if filterEditorViewFocused
@cancelling = false
clearTimeout(@scheduleTimeout)
# Extended: Focus the fuzzy filter editor view.
focusFilterEditor: ->
@filterEditorView.focus()
# Extended: Store the currently focused element. This element will be given
# back focus when {::cancel} is called.
storeFocusedElement: ->
@previouslyFocusedElement = $(':focus')
###
Section: Private
###
selectPreviousItemView: ->
view = @getSelectedItemView().prev()
@@ -202,68 +286,6 @@ class SelectListView extends View
else if desiredBottom > @list.scrollBottom()
@list.scrollBottom(desiredBottom)
getSelectedItemView: ->
@list.find('li.selected')
# Public: Get the model item that is currently selected in the list view.
#
# Returns a model item.
getSelectedItem: ->
@getSelectedItemView().data('select-list-item')
confirmSelection: ->
item = @getSelectedItem()
if item?
@confirmed(item)
else
@cancel()
# Public: Create a view for the given model item.
#
# This method must be overridden by subclasses.
#
# 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}.
#
# Returns a String of HTML, DOM element, jQuery object, or View.
viewForItem: (item) ->
throw new Error("Subclass must implement a viewForItem(item) method")
# Public: Callback function for when an item is selected.
#
# This method must be overridden by subclasses.
#
# * `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) ->
throw new Error("Subclass must implement a confirmed(item) method")
# Public: Get the property name to use when filtering items.
#
# This method may be overridden by classes to allow fuzzy filtering based
# on a specific property of the item objects.
#
# For example if the objects you pass to {::setItems} are of the type
# `{"id": 3, "name": "Atom"}` then you would return `"name"` from this method
# to fuzzy filter by that property when text is entered into this view's
# editor.
#
# Returns the property name to fuzzy filter by.
getFilterKey: ->
# Public: Focus the fuzzy filter editor view.
focusFilterEditor: ->
@filterEditorView.focus()
# Public: Store the currently focused element. This element will be given
# back focus when {::cancel} is called.
storeFocusedElement: ->
@previouslyFocusedElement = $(':focus')
restoreFocus: ->
if @previouslyFocusedElement?.isOnDom()
@previouslyFocusedElement.focus()
@@ -273,16 +295,18 @@ class SelectListView extends View
cancelled: ->
@filterEditorView.getEditor().setText('')
# Public: Cancel and close this select list view.
#
# This restores focus to the previously focused element if
# {::storeFocusedElement} was called prior to this view being attached.
cancel: ->
@list.empty()
@cancelling = true
filterEditorViewFocused = @filterEditorView.isFocused
@cancelled()
@detach()
@restoreFocus() if filterEditorViewFocused
@cancelling = false
getSelectedItemView: ->
@list.find('li.selected')
confirmSelection: ->
item = @getSelectedItem()
if item?
@confirmed(item)
else
@cancel()
schedulePopulateList: ->
clearTimeout(@scheduleTimeout)
populateCallback = =>
@populateList() if @isOnDom()
@scheduleTimeout = setTimeout(populateCallback, @inputThrottle)
+276 -209
Ver Arquivo
@@ -1,21 +1,10 @@
{Point, Range} = require 'text-buffer'
{Model} = require 'theorist'
{pick} = require 'underscore-plus'
{Emitter} = require 'event-kit'
Grim = require 'grim'
# 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
@@ -26,42 +15,63 @@ class Selection extends Model
needsAutoscroll: null
constructor: ({@cursor, @marker, @editor, id}) ->
@emitter = new Emitter
@assignId(id)
@cursor.selection = this
@decoration = @editor.decorateMarker(@marker, type: 'highlight', class: 'selection')
@marker.on 'changed', => @screenRangeChanged()
@marker.on 'destroyed', =>
@destroyed = true
@editor.removeSelection(this)
@emit 'destroyed' unless @editor.isDestroyed()
@marker.onDidChange (e) => @screenRangeChanged(e)
@marker.onDidDestroy =>
unless @editor.isDestroyed()
@destroyed = true
@editor.removeSelection(this)
@emit 'destroyed'
@emitter.emit 'did-destroy'
@emitter.dispose()
destroy: ->
@marker.destroy()
finalize: ->
@initialScreenRange = null unless @initialScreenRange?.isEqual(@getScreenRange())
if @isEmpty()
@wordwise = false
@linewise = false
###
Section: Event Subscription
###
clearAutoscroll: ->
@needsAutoscroll = null
# Public: Determines if the selection contains anything.
isEmpty: ->
@getBufferRange().isEmpty()
# Public: Determines if the ending position of a marker is greater than the
# starting position.
# Extended: Calls your `callback` when the selection was moved.
#
# This can happen when, for example, you highlight text "up" in a {TextBuffer}.
isReversed: ->
@marker.isReversed()
# * `callback` {Function}
# * `event` {Object}
# * `oldBufferRange` {Range}
# * `oldScreenRange` {Range}
# * `newBufferRange` {Range}
# * `newScreenRange` {Range}
# * `selection` {Selection} that triggered the event
#
# Returns a {Disposable} on which `.dispose()` can be called to unsubscribe.
onDidChangeRange: (callback) ->
@emitter.on 'did-change-range', callback
# Public: Returns whether the selection is a single line or not.
isSingleScreenLine: ->
@getScreenRange().isSingleLine()
# Extended: Calls your `callback` when the selection was destroyed
#
# * `callback` {Function}
#
# Returns a {Disposable} on which `.dispose()` can be called to unsubscribe.
onDidDestroy: (callback) ->
@emitter.on 'did-destroy', callback
on: (eventName) ->
switch eventName
when 'screen-range-changed'
Grim.deprecate("Use Selection::onDidChangeRange instead. Call ::getScreenRange() yourself in your callback if you need the range.")
when 'destroyed'
Grim.deprecate("Use Selection::onDidDestroy instead.")
super
###
Section: Managing the selection range
###
# Public: Returns the screen {Range} for the selection.
getScreenRange: ->
@@ -120,55 +130,61 @@ class Selection extends Model
getHeadBufferPosition: ->
@marker.getHeadBufferPosition()
autoscroll: ->
@editor.scrollToScreenRange(@getScreenRange())
###
Section: Info about the selection
###
# Public: Determines if the selection contains anything.
isEmpty: ->
@getBufferRange().isEmpty()
# Public: Determines if the ending position of a marker is greater than the
# starting position.
#
# This can happen when, for example, you highlight text "up" in a {TextBuffer}.
isReversed: ->
@marker.isReversed()
# Public: Returns whether the selection is a single line or not.
isSingleScreenLine: ->
@getScreenRange().isSingleLine()
# Public: Returns the text in the selection.
getText: ->
@editor.buffer.getTextInRange(@getBufferRange())
# Public: Identifies if a selection intersects with a given buffer range.
#
# * `bufferRange` A {Range} to check against.
#
# Returns a {Boolean}
intersectsBufferRange: (bufferRange) ->
@getBufferRange().intersectsWith(bufferRange)
intersectsScreenRowRange: (startRow, endRow) ->
@getScreenRange().intersectsRowRange(startRow, endRow)
intersectsScreenRow: (screenRow) ->
@getScreenRange().intersectsRow(screenRow)
# Public: Identifies if a selection intersects with another selection.
#
# * `otherSelection` A {Selection} to check against.
#
# Returns a {Boolean}
intersectsWith: (otherSelection, exclusive) ->
@getBufferRange().intersectsWith(otherSelection.getBufferRange(), exclusive)
###
Section: Modifying the selected range
###
# Public: Clears the selection, moving the marker to the head.
clear: ->
@marker.setAttributes(goalBufferRange: null)
@marker.setProperties(goalBufferRange: null)
@marker.clearTail() unless @retainSelection
@finalize()
# Public: Modifies the selection to encompass the current word.
#
# Returns a {Range}.
selectWord: ->
options = {}
options.wordRegex = /[\t ]*/ if @cursor.isSurroundedByWhitespace()
if @cursor.isBetweenWordAndNonWord()
options.includeNonWordCharacters = false
@setBufferRange(@cursor.getCurrentWordBufferRange(options))
@wordwise = true
@initialScreenRange = @getScreenRange()
# Public: Expands the newest selection to include the entire word on which
# the cursors rests.
expandOverWord: ->
@setBufferRange(@getBufferRange().union(@cursor.getCurrentWordBufferRange()))
# Public: Selects an entire line in the buffer.
#
# * `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))
@linewise = true
@wordwise = false
@initialScreenRange = @getScreenRange()
# Public: Expands the newest selection to include the entire line on which
# the cursor currently rests.
#
# It also includes the newline character.
expandOverLine: ->
range = @getBufferRange().union(@cursor.getCurrentLineBufferRange(includeNewline: true))
@setBufferRange(range)
# Public: Selects the text from the current cursor position to a given screen
# position.
#
@@ -283,46 +299,45 @@ class Selection extends Model
selectToBeginningOfPreviousParagraph: ->
@modifySelection => @cursor.moveToBeginningOfPreviousParagraph()
# Public: Moves the selection down one row.
addSelectionBelow: ->
range = (@getGoalBufferRange() ? @getBufferRange()).copy()
nextRow = range.end.row + 1
# Public: Modifies the selection to encompass the current word.
#
# Returns a {Range}.
selectWord: ->
options = {}
options.wordRegex = /[\t ]*/ if @cursor.isSurroundedByWhitespace()
if @cursor.isBetweenWordAndNonWord()
options.includeNonWordCharacters = false
for row in [nextRow..@editor.getLastBufferRow()]
range.start.row = row
range.end.row = row
clippedRange = @editor.clipBufferRange(range)
@setBufferRange(@cursor.getCurrentWordBufferRange(options))
@wordwise = true
@initialScreenRange = @getScreenRange()
if range.isEmpty()
continue if range.end.column > 0 and clippedRange.end.column is 0
else
continue if clippedRange.isEmpty()
# Public: Expands the newest selection to include the entire word on which
# the cursors rests.
expandOverWord: ->
@setBufferRange(@getBufferRange().union(@cursor.getCurrentWordBufferRange()))
@editor.addSelectionForBufferRange(range, goalBufferRange: range)
break
# Public: Selects an entire line in the buffer.
#
# * `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))
@linewise = true
@wordwise = false
@initialScreenRange = @getScreenRange()
# FIXME: I have no idea what this does.
getGoalBufferRange: ->
if goalBufferRange = @marker.getAttributes().goalBufferRange
Range.fromObject(goalBufferRange)
# Public: Expands the newest selection to include the entire line on which
# the cursor currently rests.
#
# It also includes the newline character.
expandOverLine: ->
range = @getBufferRange().union(@cursor.getCurrentLineBufferRange(includeNewline: true))
@setBufferRange(range)
# Public: Moves the selection up one row.
addSelectionAbove: ->
range = (@getGoalBufferRange() ? @getBufferRange()).copy()
previousRow = range.end.row - 1
for row in [previousRow..0]
range.start.row = row
range.end.row = row
clippedRange = @editor.clipBufferRange(range)
if range.isEmpty()
continue if range.end.column > 0 and clippedRange.end.column is 0
else
continue if clippedRange.isEmpty()
@editor.addSelectionForBufferRange(range, goalBufferRange: range)
break
###
Section: Modifying the selected text
###
# Public: Replaces text at the current selection.
#
@@ -363,71 +378,6 @@ class Selection extends Model
newBufferRange
# 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.
normalizeIndents: (text, indentBasis) ->
textPrecedingCursor = @cursor.getCurrentBufferLine()[0...@cursor.getBufferColumn()]
isCursorInsideExistingLine = /\S/.test(textPrecedingCursor)
lines = text.split('\n')
firstLineIndentLevel = @editor.indentLevelForLine(lines[0])
if isCursorInsideExistingLine
minimumIndentLevel = @editor.indentationForBufferRow(@cursor.getBufferRow())
else
minimumIndentLevel = @cursor.getIndentLevel()
normalizedLines = []
for line, i in lines
if i == 0
indentLevel = 0
else if line == '' # remove all indentation from empty lines
indentLevel = 0
else
lineIndentLevel = @editor.indentLevelForLine(lines[i])
indentLevel = minimumIndentLevel + (lineIndentLevel - indentBasis)
normalizedLines.push(@setIndentationForLine(line, indentLevel))
normalizedLines.join('\n')
# Indent the current line(s).
#
# If the selection is empty, indents the current line if the cursor precedes
# non-whitespace characters, and otherwise inserts a tab. If the selection is
# non empty, calls {::indentSelectedRows}.
#
# * `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()
if @isEmpty()
@cursor.skipLeadingWhitespace()
desiredIndent = @editor.suggestedIndentForBufferRow(row)
delta = desiredIndent - @cursor.getIndentLevel()
if autoIndent and delta > 0
@insertText(@editor.buildIndentString(delta))
else
@insertText(@editor.buildIndentString(1, @cursor.getBufferColumn()))
else
@indentSelectedRows()
# Public: If the selection spans multiple rows, indent all of them.
indentSelectedRows: ->
[start, end] = @getBufferRowRange()
for row in [start..end]
@editor.buffer.insert([row, 0], @editor.getTabText()) unless @editor.buffer.lineLengthForRow(row) == 0
# Public: ?
setIndentationForLine: (line, indentLevel) ->
desiredIndentLevel = Math.max(0, indentLevel)
desiredIndentString = @editor.buildIndentString(desiredIndentLevel)
line.replace(/^[\t ]*/, desiredIndentString)
# Public: Removes the first character before the selection if the selection
# is empty otherwise it deletes the selection.
backspace: ->
@@ -604,41 +554,110 @@ class Selection extends Model
@editor.createFold(range.start.row, range.end.row)
@cursor.setBufferPosition([range.end.row + 1, 0])
modifySelection: (fn) ->
@retainSelection = true
@plantTail()
fn()
@retainSelection = false
# 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.
normalizeIndents: (text, indentBasis) ->
textPrecedingCursor = @cursor.getCurrentBufferLine()[0...@cursor.getBufferColumn()]
isCursorInsideExistingLine = /\S/.test(textPrecedingCursor)
# Sets the marker's tail to the same position as the marker's head.
#
# This only works if there isn't already a tail position.
#
# Returns a {Point} representing the new tail position.
plantTail: ->
@marker.plantTail()
lines = text.split('\n')
firstLineIndentLevel = @editor.indentLevelForLine(lines[0])
if isCursorInsideExistingLine
minimumIndentLevel = @editor.indentationForBufferRow(@cursor.getBufferRow())
else
minimumIndentLevel = @cursor.getIndentLevel()
# Public: Identifies if a selection intersects with a given buffer range.
#
# * `bufferRange` A {Range} to check against.
#
# Returns a {Boolean}
intersectsBufferRange: (bufferRange) ->
@getBufferRange().intersectsWith(bufferRange)
normalizedLines = []
for line, i in lines
if i == 0
indentLevel = 0
else if line == '' # remove all indentation from empty lines
indentLevel = 0
else
lineIndentLevel = @editor.indentLevelForLine(lines[i])
indentLevel = minimumIndentLevel + (lineIndentLevel - indentBasis)
intersectsScreenRowRange: (startRow, endRow) ->
@getScreenRange().intersectsRowRange(startRow, endRow)
normalizedLines.push(@setIndentationForLine(line, indentLevel))
intersectsScreenRow: (screenRow) ->
@getScreenRange().intersectsRow(screenRow)
normalizedLines.join('\n')
# Public: Identifies if a selection intersects with another selection.
# Indent the current line(s).
#
# * `otherSelection` A {Selection} to check against.
# If the selection is empty, indents the current line if the cursor precedes
# non-whitespace characters, and otherwise inserts a tab. If the selection is
# non empty, calls {::indentSelectedRows}.
#
# Returns a {Boolean}
intersectsWith: (otherSelection, exclusive) ->
@getBufferRange().intersectsWith(otherSelection.getBufferRange(), exclusive)
# * `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()
if @isEmpty()
@cursor.skipLeadingWhitespace()
desiredIndent = @editor.suggestedIndentForBufferRow(row)
delta = desiredIndent - @cursor.getIndentLevel()
if autoIndent and delta > 0
delta = Math.max(delta, 1) unless @editor.getSoftTabs()
@insertText(@editor.buildIndentString(delta))
else
@insertText(@editor.buildIndentString(1, @cursor.getBufferColumn()))
else
@indentSelectedRows()
# Public: If the selection spans multiple rows, indent all of them.
indentSelectedRows: ->
[start, end] = @getBufferRowRange()
for row in [start..end]
@editor.buffer.insert([row, 0], @editor.getTabText()) unless @editor.buffer.lineLengthForRow(row) == 0
setIndentationForLine: (line, indentLevel) ->
desiredIndentLevel = Math.max(0, indentLevel)
desiredIndentString = @editor.buildIndentString(desiredIndentLevel)
line.replace(/^[\t ]*/, desiredIndentString)
###
Section: Managing multiple selections
###
# Public: Moves the selection down one row.
addSelectionBelow: ->
range = (@getGoalBufferRange() ? @getBufferRange()).copy()
nextRow = range.end.row + 1
for row in [nextRow..@editor.getLastBufferRow()]
range.start.row = row
range.end.row = row
clippedRange = @editor.clipBufferRange(range)
if range.isEmpty()
continue if range.end.column > 0 and clippedRange.end.column is 0
else
continue if clippedRange.isEmpty()
@editor.addSelectionForBufferRange(range, goalBufferRange: range)
break
# Public: Moves the selection up one row.
addSelectionAbove: ->
range = (@getGoalBufferRange() ? @getBufferRange()).copy()
previousRow = range.end.row - 1
for row in [previousRow..0]
range.start.row = row
range.end.row = row
clippedRange = @editor.clipBufferRange(range)
if range.isEmpty()
continue if range.end.column > 0 and clippedRange.end.column is 0
else
continue if clippedRange.isEmpty()
@editor.addSelectionForBufferRange(range, goalBufferRange: range)
break
# Public: Combines the given selection into this selection and then destroys
# the given selection.
@@ -655,6 +674,10 @@ class Selection extends Model
@setBufferRange(@getBufferRange().union(otherSelection.getBufferRange()), options)
otherSelection.destroy()
###
Section: Comparing to other selections
###
# Public: Compare this selection's buffer range to another selection's buffer
# range.
#
@@ -664,7 +687,51 @@ class Selection extends Model
compare: (otherSelection) ->
@getBufferRange().compare(otherSelection.getBufferRange())
screenRangeChanged: ->
screenRange = @getScreenRange()
@emit 'screen-range-changed', screenRange
@editor.selectionScreenRangeChanged(this)
###
Section: Private Utilities
###
screenRangeChanged: (e) ->
{oldHeadBufferPosition, oldTailBufferPosition} = e
{oldHeadScreenPosition, oldTailScreenPosition} = e
eventObject =
oldBufferRange: new Range(oldHeadBufferPosition, oldTailBufferPosition)
oldScreenRange: new Range(oldHeadScreenPosition, oldTailScreenPosition)
newBufferRange: @getBufferRange()
newScreenRange: @getScreenRange()
selection: this
@emit 'screen-range-changed', @getScreenRange() # old event
@emitter.emit 'did-change-range'
@editor.selectionRangeChanged(eventObject)
finalize: ->
@initialScreenRange = null unless @initialScreenRange?.isEqual(@getScreenRange())
if @isEmpty()
@wordwise = false
@linewise = false
autoscroll: ->
@editor.scrollToScreenRange(@getScreenRange())
clearAutoscroll: ->
@needsAutoscroll = null
modifySelection: (fn) ->
@retainSelection = true
@plantTail()
fn()
@retainSelection = false
# Sets the marker's tail to the same position as the marker's head.
#
# This only works if there isn't already a tail position.
#
# Returns a {Point} representing the new tail position.
plantTail: ->
@marker.plantTail()
getGoalBufferRange: ->
if goalBufferRange = @marker.getProperties().goalBufferRange
Range.fromObject(goalBufferRange)
+1 -1
Ver Arquivo
@@ -9,7 +9,7 @@ PropertyAccessors = require 'property-accessors'
{$, $$} = require './space-pen-extensions'
Token = require './token'
# Public: Syntax class holding the grammars used for tokenizing.
# Extended: Syntax class holding the grammars used for tokenizing.
#
# An instance of this class is always available as the `atom.syntax` global.
#
+27 -3
Ver Arquivo
@@ -2,14 +2,38 @@ _ = require 'underscore-plus'
child_process = require 'child_process'
{Emitter} = require 'emissary'
# Public: Run a node script in a separate process.
# Extended: Run a node script in a separate process.
#
# Used by the fuzzy-finder.
# Used by the fuzzy-finder and [find in project](https://github.com/atom/atom/blob/master/src/scan-handler.coffee).
#
# For a real-world example, see the [scan-handler](https://github.com/atom/atom/blob/master/src/scan-handler.coffee)
# and the [instantiation of the task](https://github.com/atom/atom/blob/4a20f13162f65afc816b512ad7201e528c3443d7/src/project.coffee#L245).
#
# ## Examples
#
# In your package code:
#
# ```coffee
# {Task} = require 'atom'
#
# task = Task.once '/path/to/task-file.coffee', parameter1, parameter2, ->
# console.log 'task has finished'
#
# task.on 'some-event-from-the-task', (data) =>
# console.log data.someString # prints 'yep this is it'
# ```
#
# In `'/path/to/task-file.coffee'`:
#
# ```coffee
# module.exports = (parameter1, parameter2) ->
# # Indicates that this task will be async.
# # Call the `callback` to finish the task
# callback = @async()
#
# emit('some-event-from-the-task', {someString: 'yep this is it'})
#
# callback()
# ```
#
# ## Events
@@ -55,7 +79,7 @@ class Task
# receives a completion callback, this is overridden.
callback: null
# Public: Creates a task.
# Public: Creates a task. You should probably use {.once}
#
# * `taskPath` The {String} path to the CoffeeScript/JavaScript file that
# exports a single {Function} to execute.
+30 -17
Ver Arquivo
@@ -4,34 +4,47 @@ isHighSurrogate = (string, index) ->
isLowSurrogate = (string, index) ->
0xDC00 <= string.charCodeAt(index) <= 0xDFFF
isVariationSelector = (string, index) ->
0xFE00 <= string.charCodeAt(index) <= 0xFE0F
# Is the character at the given index the start of a high/low surrogate pair?
#
# string - The {String} to check for a surrogate pair.
# index - The {Number} index to look for a surrogate pair at.
# * `string` The {String} to check for a surrogate pair.
# * `index` The {Number} index to look for a surrogate pair at.
#
# Return a {Boolean}.
isSurrogatePair = (string, index=0) ->
isHighSurrogate(string, index) and isLowSurrogate(string, index + 1)
# Get the number of characters in the string accounting for surrogate pairs.
# Is the character at the given index the start of a variation sequence?
#
# This method counts high/low surrogate pairs as a single character and will
# always returns a value less than or equal to `string.length`.
# * `string` The {String} to check for a variation sequence.
# * `index` The {Number} index to look for a variation sequence at.
#
# string - The {String} to count the number of full characters in.
#
# Returns a {Number}.
getCharacterCount = (string) ->
count = string.length
count-- for index in [0...string.length] when isSurrogatePair(string, index)
count
# Return a {Boolean}.
isVariationSequence = (string, index=0) ->
not isVariationSelector(string, index) and isVariationSelector(string, index + 1)
# Does the given string contain at least one surrogate pair?
# Is the character at the given index the start of high/low surrogate pair
# or a variation sequence?
#
# string - The {String} to check for the presence of surrogate pairs.
# * `string` The {String} to check for a surrogate pair or variation sequence.
# * `index` The {Number} index to look for a surrogate pair at.
#
# Return a {Boolean}.
isPairedCharacter = (string, index=0) ->
isSurrogatePair(string, index) or isVariationSequence(string, index)
# Does the given string contain at least surrogate pair or variation sequence?
#
# * `string` The {String} to check for the presence of paired characters.
#
# Returns a {Boolean}.
hasSurrogatePair = (string) ->
string.length isnt getCharacterCount(string)
hasPairedCharacter = (string) ->
index = 0
while index < string.length
return true if isPairedCharacter(string, index)
index++
false
module.exports = {getCharacterCount, isSurrogatePair, hasSurrogatePair}
module.exports = {isPairedCharacter, hasPairedCharacter}
+223 -128
Ver Arquivo
@@ -1,56 +1,113 @@
path = require 'path'
_ = require 'underscore-plus'
{Emitter} = require 'emissary'
EmitterMixin = require('emissary').Emitter
{Emitter} = require 'event-kit'
{File} = require 'pathwatcher'
fs = require 'fs-plus'
Q = require 'q'
{deprecate} = require 'grim'
{$} = require './space-pen-extensions'
Package = require './package'
{File} = require 'pathwatcher'
# 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)
EmitterMixin.includeInto(this)
constructor: ({@packageManager, @resourcePath, @configDirPath, @safeMode}) ->
@emitter = new Emitter
@lessCache = null
@initialLoadComplete = false
@packageManager.registerPackageActivator(this, ['theme'])
###
Section: Event Subscription
###
# Essential: Invoke `callback` when all styles have been reloaded.
#
# * `callback` {Function}
onDidReloadAll: (callback) ->
@emitter.on 'did-reload-all', callback
# Essential: Invoke `callback` when a stylesheet has been added to the dom.
#
# * `callback` {Function}
# * `stylesheet` {StyleSheet} the style node
#
# Returns a {Disposable} on which `.dispose()` can be called to unsubscribe.
onDidAddStylesheet: (callback) ->
@emitter.on 'did-add-stylesheet', callback
# Essential: Invoke `callback` when a stylesheet has been removed from the dom.
#
# * `callback` {Function}
# * `stylesheet` {StyleSheet} the style node
#
# Returns a {Disposable} on which `.dispose()` can be called to unsubscribe.
onDidRemoveStylesheet: (callback) ->
@emitter.on 'did-remove-stylesheet', callback
# Essential: Invoke `callback` when a stylesheet has been updated.
#
# * `callback` {Function}
# * `stylesheet` {StyleSheet} the style node
#
# Returns a {Disposable} on which `.dispose()` can be called to unsubscribe.
onDidUpdateStylesheet: (callback) ->
@emitter.on 'did-update-stylesheet', callback
# Essential: Invoke `callback` when any stylesheet has been updated, added, or removed.
#
# * `callback` {Function}
#
# Returns a {Disposable} on which `.dispose()` can be called to unsubscribe.
onDidChangeStylesheets: (callback) ->
@emitter.on 'did-change-stylesheets', callback
on: (eventName) ->
switch eventName
when 'reloaded'
deprecate 'Use ThemeManager::onDidReloadAll instead'
when 'stylesheet-added'
deprecate 'Use ThemeManager::onDidAddStylesheet instead'
when 'stylesheet-removed'
deprecate 'Use ThemeManager::onDidRemoveStylesheet instead'
when 'stylesheet-updated'
deprecate 'Use ThemeManager::onDidUpdateStylesheet instead'
when 'stylesheets-changed'
deprecate 'Use ThemeManager::onDidChangeStylesheets instead'
else
deprecate 'ThemeManager::on is deprecated. Use event subscription methods instead.'
EmitterMixin::on.apply(this, arguments)
###
Section: Accessing Available Themes
###
getAvailableNames: ->
# TODO: Maybe should change to list all the available themes out there?
@getLoadedNames()
###
Section: Accessing Loaded Themes
###
# Public: Get an array of all the loaded theme names.
getLoadedNames: ->
theme.name for theme in @getLoadedThemes()
# Public: Get an array of all the loaded themes.
getLoadedThemes: ->
pack for pack in @packageManager.getLoadedPackages() when pack.isTheme()
###
Section: Accessing Active Themes
###
# Public: Get an array of all the active theme names.
getActiveNames: ->
theme.name for theme in @getActiveThemes()
@@ -59,13 +116,13 @@ class ThemeManager
getActiveThemes: ->
pack for pack in @packageManager.getActivePackages() when pack.isTheme()
# Public: Get an array of all the loaded themes.
getLoadedThemes: ->
pack for pack in @packageManager.getLoadedPackages() when pack.isTheme()
activatePackages: -> @activateThemes()
activatePackages: (themePackages) -> @activateThemes()
###
Section: Managing Enabled Themes
###
# Get the enabled theme names from the config.
# Public: Get the enabled theme names from the config.
#
# Returns an array of theme names in the order that they should be activated.
getEnabledThemeNames: ->
@@ -100,68 +157,15 @@ class ThemeManager
# the first/top theme to override later themes in the stack.
themeNames.reverse()
activateThemes: ->
deferred = Q.defer()
# atom.config.observe runs the callback once, then on subsequent changes.
atom.config.observe 'core.themes', =>
@deactivateThemes()
@refreshLessCache() # Update cache for packages in core.themes config
promises = []
for themeName in @getEnabledThemeNames()
if @packageManager.resolvePackagePath(themeName)
promises.push(@packageManager.activatePackage(themeName))
else
console.warn("Failed to activate theme '#{themeName}' because it isn't installed.")
Q.all(promises).then =>
@addActiveThemeClasses()
@refreshLessCache() # Update cache again now that @getActiveThemes() is populated
@loadUserStylesheet()
@reloadBaseStylesheets()
@emit 'reloaded'
deferred.resolve()
deferred.promise
deactivateThemes: ->
@removeActiveThemeClasses()
@unwatchUserStylesheet()
@packageManager.deactivatePackage(pack.name) for pack in @getActiveThemes()
null
addActiveThemeClasses: ->
for pack in @getActiveThemes()
atom.workspaceView?[0]?.classList.add("theme-#{pack.name}")
return
removeActiveThemeClasses: ->
for pack in @getActiveThemes()
atom.workspaceView?[0]?.classList.remove("theme-#{pack.name}")
return
refreshLessCache: ->
@lessCache?.setImportPaths(@getImportPaths())
# Public: Set the list of enabled themes.
#
# * `enabledThemeNames` An {Array} of {String} theme names.
setEnabledThemes: (enabledThemeNames) ->
atom.config.set('core.themes', enabledThemeNames)
getImportPaths: ->
activeThemes = @getActiveThemes()
if activeThemes.length > 0
themePaths = (theme.getStylesheetsPath() for theme in activeThemes when theme)
else
themePaths = []
for themeName in @getEnabledThemeNames()
if themePath = @packageManager.resolvePackagePath(themeName)
themePaths.push(path.join(themePath, Package.stylesheetsDir))
themePaths.filter (themePath) -> fs.isDirectorySync(themePath)
###
Section: Managing Stylesheets
###
# Public: Returns the {String} path to the user's stylesheet under ~/.atom
getUserStylesheetPath: ->
@@ -171,6 +175,23 @@ class ThemeManager
else
path.join(@configDirPath, 'styles.less')
# Public: Resolve and apply the stylesheet specified by the path.
#
# 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.
#
# Returns the absolute path to the required stylesheet.
requireStylesheet: (stylesheetPath, type='bundled') ->
if fullPath = @resolveStylesheet(stylesheetPath)
content = @loadStylesheet(fullPath)
@applyStylesheet(fullPath, content, type)
else
throw new Error("Could not find a file at path '#{stylesheetPath}'")
fullPath
unwatchUserStylesheet: ->
@userStylesheetFile?.off()
@userStylesheetFile = null
@@ -197,8 +218,8 @@ class ThemeManager
if nativeStylesheetPath = fs.resolveOnLoadPath(process.platform, ['css', 'less'])
@requireStylesheet(nativeStylesheetPath)
stylesheetElementForId: (id, htmlElement=$('html')) ->
htmlElement.find("""head style[id="#{id}"]""")
stylesheetElementForId: (id) ->
document.head.querySelector("""style[id="#{id}"]""")
resolveStylesheet: (stylesheetPath) ->
if path.extname(stylesheetPath).length > 0
@@ -206,23 +227,6 @@ class ThemeManager
else
fs.resolveOnLoadPath(stylesheetPath, ['css', 'less'])
# Public: Resolve and apply the stylesheet specified by the path.
#
# 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.
#
# Returns the absolute path to the required stylesheet.
requireStylesheet: (stylesheetPath, type = 'bundled', htmlElement) ->
if fullPath = @resolveStylesheet(stylesheetPath)
content = @loadStylesheet(fullPath)
@applyStylesheet(fullPath, content, type = 'bundled', htmlElement)
else
throw new Error("Could not find a file at path '#{stylesheetPath}'")
fullPath
loadStylesheet: (stylesheetPath, importFallbackVariables) ->
if path.extname(stylesheetPath) is '.less'
@loadLessStylesheet(stylesheetPath, importFallbackVariables)
@@ -244,36 +248,127 @@ class ThemeManager
@lessCache.cssForFile(lessStylesheetPath, [baseVarImports, less].join('\n'))
else
@lessCache.read(lessStylesheetPath)
catch e
catch error
console.error """
Error compiling less stylesheet: #{lessStylesheetPath}
Line number: #{e.line}
#{e.message}
Error compiling Less stylesheet: #{lessStylesheetPath}
Line number: #{error.line}
#{error.message}
"""
stringToId: (string) ->
string.replace(/\\/g, '/')
removeStylesheet: (stylesheetPath) ->
fullPath = @resolveStylesheet(stylesheetPath) ? stylesheetPath
element = @stylesheetElementForId(@stringToId(fullPath))
if element.length > 0
stylesheet = element[0].sheet
if element?
{sheet} = element
element.remove()
@emit 'stylesheet-removed', stylesheet
@emit 'stylesheet-removed', sheet
@emitter.emit 'did-remove-stylesheet', sheet
@emit 'stylesheets-changed'
@emitter.emit 'did-change-stylesheets'
applyStylesheet: (path, text, type = 'bundled', htmlElement=$('html')) ->
styleElement = @stylesheetElementForId(@stringToId(path), htmlElement)
if styleElement.length
@emit 'stylesheet-removed', styleElement[0].sheet
styleElement.text(text)
applyStylesheet: (path, text, type='bundled') ->
styleId = @stringToId(path)
styleElement = @stylesheetElementForId(styleId)
if styleElement?
@emit 'stylesheet-removed', styleElement.sheet
@emitter.emit 'did-remove-stylesheet', styleElement.sheet
styleElement.textContent = text
else
styleElement = $("<style class='#{type}' id='#{@stringToId(path)}'>#{text}</style>")
if htmlElement.find("head style.#{type}").length
htmlElement.find("head style.#{type}:last").after(styleElement)
else
htmlElement.find("head").append(styleElement)
styleElement = document.createElement('style')
styleElement.setAttribute('class', type)
styleElement.setAttribute('id', styleId)
styleElement.textContent = text
@emit 'stylesheet-added', styleElement[0].sheet
elementToInsertBefore = _.last(document.head.querySelectorAll("style.#{type}"))?.nextElementSibling
if elementToInsertBefore?
document.head.insertBefore(styleElement, elementToInsertBefore)
else
document.head.appendChild(styleElement)
@emit 'stylesheet-added', styleElement.sheet
@emitter.emit 'did-add-stylesheet', styleElement.sheet
@emit 'stylesheets-changed'
@emitter.emit 'did-change-stylesheets'
###
Section: Private
###
stringToId: (string) ->
string.replace(/\\/g, '/')
activateThemes: ->
deferred = Q.defer()
# atom.config.observe runs the callback once, then on subsequent changes.
atom.config.observe 'core.themes', =>
@deactivateThemes()
@refreshLessCache() # Update cache for packages in core.themes config
promises = []
for themeName in @getEnabledThemeNames()
if @packageManager.resolvePackagePath(themeName)
promises.push(@packageManager.activatePackage(themeName))
else
console.warn("Failed to activate theme '#{themeName}' because it isn't installed.")
Q.all(promises).then =>
@addActiveThemeClasses()
@refreshLessCache() # Update cache again now that @getActiveThemes() is populated
@loadUserStylesheet()
@reloadBaseStylesheets()
@initialLoadComplete = true
@emit 'reloaded'
@emitter.emit 'did-reload-all'
deferred.resolve()
deferred.promise
deactivateThemes: ->
@removeActiveThemeClasses()
@unwatchUserStylesheet()
@packageManager.deactivatePackage(pack.name) for pack in @getActiveThemes()
null
isInitialLoadComplete: -> @initialLoadComplete
addActiveThemeClasses: ->
for pack in @getActiveThemes()
atom.workspaceView?[0]?.classList.add("theme-#{pack.name}")
return
removeActiveThemeClasses: ->
for pack in @getActiveThemes()
atom.workspaceView?[0]?.classList.remove("theme-#{pack.name}")
return
refreshLessCache: ->
@lessCache?.setImportPaths(@getImportPaths())
getImportPaths: ->
activeThemes = @getActiveThemes()
if activeThemes.length > 0
themePaths = (theme.getStylesheetsPath() for theme in activeThemes when theme)
else
themePaths = []
for themeName in @getEnabledThemeNames()
if themePath = @packageManager.resolvePackagePath(themeName)
themePaths.push(path.join(themePath, Package.stylesheetsDir))
themePaths.filter (themePath) -> fs.isDirectorySync(themePath)
updateGlobalEditorStyle: (property, value) ->
unless styleNode = @stylesheetElementForId('global-editor-styles')
@applyStylesheet('global-editor-styles', '.editor {}')
styleNode = @stylesheetElementForId('global-editor-styles')
{sheet} = styleNode
editorRule = sheet.cssRules[0]
editorRule.style[property] = value
@emit 'stylesheet-updated', sheet
@emitter.emit 'did-update-stylesheet', sheet
@emit 'stylesheets-changed'
@emitter.emit 'did-change-stylesheets'
+16 -14
Ver Arquivo
@@ -12,7 +12,7 @@ MaxTokenLength = 20000
module.exports =
class Token
value: null
hasSurrogatePair: false
hasPairedCharacter: false
scopes: null
isAtomic: null
isHardTab: null
@@ -23,7 +23,7 @@ class Token
constructor: ({@value, @scopes, @isAtomic, @bufferDelta, @isHardTab}) ->
@screenDelta = @value.length
@bufferDelta ?= @screenDelta
@hasSurrogatePair = textUtils.hasSurrogatePair(@value)
@hasPairedCharacter = textUtils.hasPairedCharacter(@value)
isEqual: (other) ->
@value == other.value and _.isEqual(@scopes, other.scopes) and !!@isAtomic == !!other.isAtomic
@@ -57,11 +57,11 @@ class Token
WhitespaceRegexesByTabLength[tabLength] ?= new RegExp("([ ]{#{tabLength}})|(\t)|([^\t]+)", "g")
breakOutAtomicTokens: (tabLength, breakOutLeadingSoftTabs, startColumn) ->
if @hasSurrogatePair
if @hasPairedCharacter
outputTokens = []
column = startColumn
for token in @breakOutSurrogatePairs()
for token in @breakOutPairedCharacters()
if token.isAtomic
outputTokens.push(token)
else
@@ -98,27 +98,27 @@ class Token
outputTokens
breakOutSurrogatePairs: ->
breakOutPairedCharacters: ->
outputTokens = []
index = 0
nonSurrogatePairStart = 0
nonPairStart = 0
while index < @value.length
if textUtils.isSurrogatePair(@value, index)
if nonSurrogatePairStart isnt index
outputTokens.push(new Token({value: @value[nonSurrogatePairStart...index], @scopes}))
outputTokens.push(@buildSurrogatePairToken(@value, index))
if textUtils.isPairedCharacter(@value, index)
if nonPairStart isnt index
outputTokens.push(new Token({value: @value[nonPairStart...index], @scopes}))
outputTokens.push(@buildPairedCharacterToken(@value, index))
index += 2
nonSurrogatePairStart = index
nonPairStart = index
else
index++
if nonSurrogatePairStart isnt index
outputTokens.push(new Token({value: @value[nonSurrogatePairStart...index], @scopes}))
if nonPairStart isnt index
outputTokens.push(new Token({value: @value[nonPairStart...index], @scopes}))
outputTokens
buildSurrogatePairToken: (value, index) ->
buildPairedCharacterToken: (value, index) ->
new Token(
value: value[index..index + 1]
scopes: @scopes
@@ -153,6 +153,8 @@ class Token
getValueAsHtml: ({hasIndentGuide}) ->
if @isHardTab
classes = 'hard-tab'
classes += ' leading-whitespace' if @hasLeadingWhitespace()
classes += ' trailing-whitespace' if @hasTrailingWhitespace()
classes += ' indent-guide' if hasIndentGuide
classes += ' invisible-character' if @hasInvisibleCharacters
html = "<span class='#{classes}'>#{@escapeString(@value)}</span>"
+51 -12
Ver Arquivo
@@ -1,9 +1,12 @@
_ = require 'underscore-plus'
{Model} = require 'theorist'
EmitterMixin = require('emissary').Emitter
{Emitter} = require 'event-kit'
{Point, Range} = require 'text-buffer'
Serializable = require 'serializable'
TokenizedLine = require './tokenized-line'
Token = require './token'
Grim = require 'grim'
module.exports =
class TokenizedBuffer extends Model
@@ -20,16 +23,13 @@ class TokenizedBuffer extends Model
visible: false
constructor: ({@buffer, @tabLength, @invisibles}) ->
@emitter = new Emitter
@tabLength ?= atom.config.getPositiveInt('editor.tabLength', 2)
@subscribe atom.syntax, 'grammar-added grammar-updated', (grammar) =>
if grammar.injectionSelector?
@retokenizeLines() if @hasTokenForSelector(grammar.injectionSelector)
else
newScore = grammar.getScore(@buffer.getPath(), @buffer.getText())
@setGrammar(grammar, newScore) if newScore > @currentGrammarScore
@subscribe atom.syntax.onDidAddGrammar(@grammarAddedOrUpdated)
@subscribe atom.syntax.onDidUpdateGrammar(@grammarAddedOrUpdated)
@on 'grammar-changed grammar-updated', => @retokenizeLines()
@subscribe @buffer.onDidChange (e) => @handleBufferChange(e)
@subscribe @buffer.onDidChangePath (@bufferPath) => @reloadGrammar()
@@ -49,13 +49,44 @@ class TokenizedBuffer extends Model
params.buffer = atom.project.bufferForPathSync(params.bufferPath)
params
onDidChangeGrammar: (callback) ->
@emitter.on 'did-change-grammar', callback
onDidChange: (callback) ->
@emitter.on 'did-change', callback
onDidTokenize: (callback) ->
@emitter.on 'did-tokenize', callback
on: (eventName) ->
switch eventName
when 'changed'
Grim.deprecate("Use TokenizedBuffer::onDidChange instead")
when 'grammar-changed'
Grim.deprecate("Use TokenizedBuffer::onDidChangeGrammar instead")
when 'tokenized'
Grim.deprecate("Use TokenizedBuffer::onDidTokenize instead")
else
Grim.deprecate("TokenizedBuffer::on is deprecated. Use event subscription methods instead.")
EmitterMixin::on.apply(this, arguments)
grammarAddedOrUpdated: (grammar) =>
if grammar.injectionSelector?
@retokenizeLines() if @hasTokenForSelector(grammar.injectionSelector)
else
newScore = grammar.getScore(@buffer.getPath(), @buffer.getText())
@setGrammar(grammar, newScore) if newScore > @currentGrammarScore
setGrammar: (grammar, score) ->
return if grammar is @grammar
@unsubscribe(@grammar) if @grammar
@grammar = grammar
@currentGrammarScore = score ? grammar.getScore(@buffer.getPath(), @buffer.getText())
@subscribe @grammar, 'grammar-updated', => @retokenizeLines()
@subscribe @grammar.onDidUpdate => @retokenizeLines()
@retokenizeLines()
@emit 'grammar-changed', grammar
@emitter.emit 'did-change-grammar', grammar
reloadGrammar: ->
if grammar = atom.syntax.selectGrammar(@buffer.getPath(), @buffer.getText())
@@ -75,7 +106,9 @@ class TokenizedBuffer extends Model
@invalidRows = []
@invalidateRow(0)
@fullyTokenized = false
@emit "changed", {start: 0, end: lastRow, delta: 0}
event = {start: 0, end: lastRow, delta: 0}
@emit 'changed', event
@emitter.emit 'did-change', event
setVisible: (@visible) ->
@tokenizeInBackground() if @visible
@@ -125,12 +158,16 @@ class TokenizedBuffer extends Model
@validateRow(row)
@invalidateRow(row + 1) unless filledRegion
@emit "changed", { start: invalidRow, end: row, delta: 0 }
event = { start: invalidRow, end: row, delta: 0 }
@emit 'changed', event
@emitter.emit 'did-change', event
if @firstInvalidRow()?
@tokenizeInBackground()
else
@emit "tokenized" unless @fullyTokenized
unless @fullyTokenized
@emit 'tokenized'
@emitter.emit 'did-tokenize'
@fullyTokenized = true
firstInvalidRow: ->
@@ -171,7 +208,9 @@ class TokenizedBuffer extends Model
if newEndStack and not _.isEqual(newEndStack, previousEndStack)
@invalidateRow(end + delta + 1)
@emit "changed", { start, end, delta, bufferChange: e }
event = { start, end, delta, bufferChange: e }
@emit 'changed', event
@emitter.emit 'did-change', event
retokenizeWhitespaceRowsIfIndentLevelChanged: (row, increment) ->
line = @tokenizedLines[row]
+6 -3
Ver Arquivo
@@ -1,3 +1,4 @@
path = require 'path'
{$} = require './space-pen-extensions'
_ = require 'underscore-plus'
ipc = require 'ipc'
@@ -28,9 +29,11 @@ class WindowEventHandler
@subscribe $(window), 'blur', -> document.body.classList.add('is-blurred')
@subscribe $(window), 'window:open-path', (event, {pathToOpen, initialLine, initialColumn}) ->
if fs.isDirectorySync(pathToOpen)
atom.project.setPath(pathToOpen) unless atom.project.getPath()
else
unless atom.project?.getPath()
if fs.existsSync(pathToOpen) or fs.existsSync(path.dirname(pathToOpen))
atom.project?.setPath(pathToOpen)
unless fs.isDirectorySync(pathToOpen)
atom.workspace?.open(pathToOpen, {initialLine, initialColumn})
@subscribe $(window), 'beforeunload', =>
+272 -156
Ver Arquivo
@@ -15,7 +15,12 @@ PaneRowView = require './pane-row-view'
PaneContainerView = require './pane-container-view'
Editor = require './editor'
# Essential: The top-level view for the entire window. An instance of this class is
atom.commands.add '.workspace',
'window:increase-font-size': -> @getModel().increaseFontSize()
'window:decrease-font-size': -> @getModel().decreaseFontSize()
'window:reset-font-size': -> @getModel().resetFontSize()
# Extended: 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
@@ -77,8 +82,10 @@ class WorkspaceView extends View
@div class: 'vertical', outlet: 'vertical', =>
@div class: 'panes', outlet: 'panes'
initialize: (@model) ->
@model = atom.workspace ? new Workspace unless @model?
initialize: (model) ->
@model = model ? atom.workspace ? new Workspace unless @model?
@element.getModel = -> model
atom.commands.setRootNode(@[0])
panes = new PaneContainerView(@model.paneContainer)
@panes.replaceWith(panes)
@@ -136,12 +143,10 @@ class WorkspaceView extends View
@command 'application:open-your-stylesheet', -> ipc.send('command', 'application:open-your-stylesheet')
@command 'application:open-license', => @model.openLicense()
@command 'window:install-shell-commands', => @installShellCommands()
if process.platform is 'darwin'
@command 'window:install-shell-commands', => @installShellCommands()
@command 'window:run-package-specs', -> ipc.send('run-package-specs', path.join(atom.project.getPath(), 'spec'))
@command 'window:increase-font-size', => @increaseFontSize()
@command 'window:decrease-font-size', => @decreaseFontSize()
@command 'window:reset-font-size', => @model.resetFontSize()
@command 'window:focus-next-pane', => @focusNextPaneView()
@command 'window:focus-previous-pane', => @focusPreviousPaneView()
@@ -162,12 +167,175 @@ class WorkspaceView extends View
@command 'core:save', => @saveActivePaneItem()
@command 'core:save-as', => @saveActivePaneItemAs()
# Public: Get the underlying model object.
@deprecatedViewEvents()
###
Section: Accessing the Workspace Model
###
# Essential: Get the underlying model object.
#
# Returns a {Workspace}.
getModel: -> @model
# Public: Install the Atom shell commands on the user's system.
###
Section: Accessing Views
###
# Essential: Register a function to be called for every current and future
# editor view in the workspace (only includes {EditorView}s that are pane
# items).
#
# * `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.
eachEditorView: (callback) ->
callback(editorView) for editorView in @getEditorViews()
attachedCallback = (e, editorView) ->
callback(editorView) unless editorView.mini
@on('editor:attached', attachedCallback)
off: => @off('editor:attached', attachedCallback)
# Essential: 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.
# * `paneView` {PaneView}
#
# Returns a subscription object with an `.off` method that you can call to
# unregister the callback.
eachPaneView: (callback) ->
@panes.eachPaneView(callback)
# Essential: Get all existing pane views.
#
# Prefer {Workspace::getPanes} if you don't need access to the view objects.
# Also consider using {::eachPaneView} if you want to register a callback for
# all current and *future* pane views.
#
# Returns an Array of all open {PaneView}s.
getPaneViews: ->
@panes.getPaneViews()
# Essential: Get the active pane view.
#
# Prefer {Workspace::getActivePane} if you don't actually need access to the
# view.
#
# Returns a {PaneView}.
getActivePaneView: ->
@panes.getActivePaneView()
# Essential: Get the view associated with the active pane item.
#
# Returns a view.
getActiveView: ->
@panes.getActiveView()
###
Section: Adding elements to the workspace
###
# Essential: 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)
# Essential: 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)
# Essential: 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)
# Essential: 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)
# Essential: 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)
# Essential: 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)
# Essential: 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)
# Essential: 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)
###
Section: Focusing pane views
###
# Focus the previous pane by id.
focusPreviousPaneView: -> @model.activatePreviousPane()
# Focus the next pane by id.
focusNextPaneView: -> @model.activateNextPane()
# Focus the pane directly above the active pane.
focusPaneViewAbove: -> @panes.focusPaneViewAbove()
# Focus the pane directly below the active pane.
focusPaneViewBelow: -> @panes.focusPaneViewBelow()
# Focus the pane directly to the left of the active pane.
focusPaneViewOnLeft: -> @panes.focusPaneViewOnLeft()
# Focus the pane directly to the right of the active pane.
focusPaneViewOnRight: -> @panes.focusPaneViewOnRight()
###
Section: Private
###
afterAttach: (onDom) ->
@focus() if onDom
# Called by SpacePen
beforeRemove: ->
@model.destroy()
setEditorFontSize: (fontSize) ->
atom.themes.updateGlobalEditorStyle('font-size', fontSize + 'px')
setEditorFontFamily: (fontFamily) ->
atom.themes.updateGlobalEditorStyle('font-family', fontFamily)
setEditorLineHeight: (lineHeight) ->
atom.themes.updateGlobalEditorStyle('line-height', lineHeight)
# Install the Atom shell commands on the user's system.
installShellCommands: ->
showErrorDialog = (error) ->
installDirectory = CommandInstaller.getInstallDirectory()
@@ -202,9 +370,6 @@ class WorkspaceView extends View
$(document.body).focus()
true
afterAttach: (onDom) ->
@focus() if onDom
# Prompts to save all unsaved items
confirmClose: ->
@panes.confirmClose()
@@ -240,156 +405,107 @@ class WorkspaceView extends View
#
# Returns an {Array} of {EditorView}s.
getEditorViews: ->
@panes.find('.pane > .item-views > .editor').map(-> $(this).view()).toArray()
for editorElement in @panes.element.querySelectorAll('.pane > .item-views > .editor')
$(editorElement).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)
###
Section: Deprecated
###
# 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)
deprecatedViewEvents: ->
originalWorkspaceViewOn = @on
# 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)
@on = (eventName) =>
switch eventName
when 'beep'
deprecate('Use Atom::onDidBeep instead')
when 'cursor:moved'
deprecate('Use Editor::onDidChangeCursorPosition instead')
when 'editor:attached'
deprecate('Use Editor::onDidAddTextEditor instead')
when 'editor:detached'
deprecate('Use Editor::onDidDestroy instead')
when 'editor:will-be-removed'
deprecate('Use Editor::onDidDestroy instead')
when 'pane:active-item-changed'
deprecate('Use Pane::onDidChangeActiveItem instead')
when 'pane:active-item-modified-status-changed'
deprecate('Use Pane::onDidChangeActiveItem and call onDidChangeModified on the active item instead')
when 'pane:active-item-title-changed'
deprecate('Use Pane::onDidChangeActiveItem and call onDidChangeTitle on the active item instead')
when 'pane:attached'
deprecate('Use Workspace::onDidAddPane instead')
when 'pane:became-active'
deprecate('Use Pane::onDidActivate instead')
when 'pane:became-inactive'
deprecate('Use Pane::onDidChangeActive instead')
when 'pane:item-added'
deprecate('Use Pane::onDidAddItem instead')
when 'pane:item-moved'
deprecate('Use Pane::onDidMoveItem instead')
when 'pane:item-removed'
deprecate('Use Pane::onDidRemoveItem instead')
when 'pane:removed'
deprecate('Use Pane::onDidDestroy instead')
when 'pane-container:active-pane-item-changed'
deprecate('Use Workspace::onDidChangeActivePaneItem instead')
when 'selection:changed'
deprecate('Use Editor::onDidChangeSelectionRange instead')
when 'uri-opened'
deprecate('Use Workspace::onDidOpen instead')
originalWorkspaceViewOn.apply(this, arguments)
# 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)
EditorView = require './editor-view'
originalEditorViewOn = EditorView::on
EditorView::on = (eventName) ->
switch eventName
when 'cursor:moved'
deprecate('Use Editor::onDidChangeCursorPosition instead')
when 'editor:attached'
deprecate('Use Editor::onDidAddTextEditor instead')
when 'editor:detached'
deprecate('Use Editor::onDidDestroy instead')
when 'editor:will-be-removed'
deprecate('Use Editor::onDidDestroy instead')
when 'selection:changed'
deprecate('Use Editor::onDidChangeSelectionRange instead')
originalEditorViewOn.apply(this, arguments)
# 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)
# Public: Get the active pane view.
#
# Prefer {Workspace::getActivePane} if you don't actually need access to the
# view.
#
# Returns a {PaneView}.
getActivePaneView: ->
@panes.getActivePaneView()
# Public: Get the view associated with the active pane item.
#
# Returns a view.
getActiveView: ->
@panes.getActiveView()
# Focus the previous pane by id.
focusPreviousPaneView: -> @model.activatePreviousPane()
# Focus the next pane by id.
focusNextPaneView: -> @model.activateNextPane()
# Public: Focus the pane directly above the active pane.
focusPaneViewAbove: -> @panes.focusPaneViewAbove()
# Public: Focus the pane directly below the active pane.
focusPaneViewBelow: -> @panes.focusPaneViewBelow()
# Public: Focus the pane directly to the left of the active pane.
focusPaneViewOnLeft: -> @panes.focusPaneViewOnLeft()
# Public: Focus the pane directly to the right of the active pane.
focusPaneViewOnRight: -> @panes.focusPaneViewOnRight()
# 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.
# * `paneView` {PaneView}
#
# Returns a subscription object with an `.off` method that you can call to
# unregister the callback.
eachPaneView: (callback) ->
@panes.eachPaneView(callback)
# Public: Get all existing pane views.
#
# Prefer {Workspace::getPanes} if you don't need access to the view objects.
# Also consider using {::eachPaneView} if you want to register a callback for
# all current and *future* pane views.
#
# Returns an Array of all open {PaneView}s.
getPaneViews: ->
@panes.getPaneViews()
# Public: Register a function to be called for every current and future
# editor view in the workspace (only includes {EditorView}s that are pane
# items).
#
# * `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.
eachEditorView: (callback) ->
callback(editorView) for editorView in @getEditorViews()
attachedCallback = (e, editorView) ->
callback(editorView) unless editorView.mini
@on('editor:attached', attachedCallback)
off: => @off('editor:attached', attachedCallback)
# Called by SpacePen
beforeRemove: ->
@model.destroy()
setEditorFontSize: (fontSize) =>
@setEditorStyle('font-size', fontSize + 'px')
setEditorFontFamily: (fontFamily) =>
@setEditorStyle('font-family', fontFamily)
setEditorLineHeight: (lineHeight) =>
@setEditorStyle('line-height', lineHeight)
setEditorStyle: (property, value) ->
unless styleNode = atom.themes.stylesheetElementForId('global-editor-styles')[0]
atom.themes.applyStylesheet('global-editor-styles', '.editor {}')
styleNode = atom.themes.stylesheetElementForId('global-editor-styles')[0]
{sheet} = styleNode
editorRule = sheet.cssRules[0]
editorRule.style[property] = value
atom.themes.emit 'stylesheet-updated', sheet
atom.themes.emit 'stylesheets-changed'
originalPaneViewOn = PaneView::on
PaneView::on = (eventName) ->
switch eventName
when 'cursor:moved'
deprecate('Use Editor::onDidChangeCursorPosition instead')
when 'editor:attached'
deprecate('Use Editor::onDidAddTextEditor instead')
when 'editor:detached'
deprecate('Use Editor::onDidDestroy instead')
when 'editor:will-be-removed'
deprecate('Use Editor::onDidDestroy instead')
when 'pane:active-item-changed'
deprecate('Use Pane::onDidChangeActiveItem instead')
when 'pane:active-item-modified-status-changed'
deprecate('Use Pane::onDidChangeActiveItem and call onDidChangeModified on the active item instead')
when 'pane:active-item-title-changed'
deprecate('Use Pane::onDidChangeActiveItem and call onDidChangeTitle on the active item instead')
when 'pane:attached'
deprecate('Use Workspace::onDidAddPane instead')
when 'pane:became-active'
deprecate('Use Pane::onDidActivate instead')
when 'pane:became-inactive'
deprecate('Use Pane::onDidChangeActive instead')
when 'pane:item-added'
deprecate('Use Pane::onDidAddItem instead')
when 'pane:item-moved'
deprecate('Use Pane::onDidMoveItem instead')
when 'pane:item-removed'
deprecate('Use Pane::onDidRemoveItem instead')
when 'pane:removed'
deprecate('Use Pane::onDidDestroy instead')
when 'selection:changed'
deprecate('Use Editor::onDidChangeSelectionRange instead')
originalPaneViewOn.apply(this, arguments)
# Deprecated
eachPane: (callback) ->
+73 -44
Ver Arquivo
@@ -10,7 +10,7 @@ Editor = require './editor'
PaneContainer = require './pane-container'
Pane = require './pane'
# Public: Represents the state of the user interface for the entire window.
# Essential: Represents the state of the user interface for the entire window.
# An instance of this class is available via the `atom.workspace` global.
#
# Interact with this object to open files, be notified of current and future
@@ -91,6 +91,52 @@ class Workspace extends Model
Section: Event Subscription
###
# 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 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)
# Essential: Invoke the given callback when the active pane item changes.
#
# * `callback` {Function} to be called when the active pane item changes.
# * `event` {Object} with the following keys:
# * `activeItem` The active pane item.
#
# Returns a {Disposable} on which `.dispose()` can be called to unsubscribe.
onDidChangeActivePaneItem: (callback) -> @paneContainer.onDidChangeActivePaneItem(callback)
# 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
# Extended: Invoke the given callback when a pane is added to the workspace.
#
# * `callback` {Function} to be called panes are added.
@@ -110,10 +156,28 @@ class Workspace extends Model
# Returns a {Disposable} on which `.dispose()` can be called to unsubscribe.
observePanes: (callback) -> @paneContainer.observePanes(callback)
# Extended: Invoke the given callback when the active pane changes.
#
# * `callback` {Function} to be called when the active pane changes.
# * `pane` A {Pane} that is the current return value of {::getActivePane}.
#
# Returns a {Disposable} on which `.dispose()` can be called to unsubscribe.
onDidChangeActivePane: (callback) -> @paneContainer.onDidChangeActivePane(callback)
# Extended: Invoke the given callback with the current active pane and when
# the active pane changes.
#
# * `callback` {Function} to be called with the current and future active#
# panes.
# * `pane` A {Pane} that is the current return value of {::getActivePane}.
#
# Returns a {Disposable} on which `.dispose()` can be called to unsubscribe.
observeActivePane: (callback) -> @paneContainer.observeActivePane(callback)
# Extended: Invoke the given callback when a pane item is added to the
# workspace.
#
# * `callback` {Function} to be called panes are added.
# * `callback` {Function} to be called when panes are added.
# * `event` {Object} with the following keys:
# * `item` The added pane item.
# * `pane` {Pane} containing the added item.
@@ -122,16 +186,6 @@ class Workspace extends Model
# 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.
#
@@ -147,33 +201,6 @@ class Workspace extends Model
@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")
@@ -296,7 +323,7 @@ class Workspace extends Model
.catch (error) ->
console.error(error.stack ? error)
# Extended: Asynchronously reopens the last-closed item's URI if it hasn't already been
# Public: 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
@@ -312,7 +339,9 @@ class Workspace extends Model
if uri = @destroyedItemUris.pop()
@openSync(uri)
# Extended: Register an opener for a uri.
# TODO: make ::registerOpener() return a disposable
# Public: Register an opener for a uri.
#
# An {Editor} will be used if no openers return a value.
#
@@ -328,7 +357,7 @@ class Workspace extends Model
registerOpener: (opener) ->
@openers.push(opener)
# Extended: Unregister an opener registered with {::registerOpener}.
# Unregister an opener registered with {::registerOpener}.
unregisterOpener: (opener) ->
_.remove(@openers, opener)
@@ -362,14 +391,14 @@ class Workspace extends Model
# Returns an {Editor} or `undefined` if the current active item is not an
# {Editor}.
getActiveTextEditor: ->
activeItem = @getActiveItem()
activeItem = @getActivePaneItem()
activeItem if activeItem instanceof Editor
# Deprecated:
getActiveEditor: ->
@activePane?.getActiveEditor()
# Extended: Save all pane items.
# Save all pane items.
saveAll: ->
@paneContainer.saveAll()
-1
Ver Arquivo
@@ -20,7 +20,6 @@
@import "overlay";
@import "lists";
@import "popover-list";
@import "notification";
@import "messages";
@import "markdown";
@import "editor";
-56
Ver Arquivo
@@ -1,56 +0,0 @@
.notification {
position: absolute;
top: 40px;
left: 50%;
margin-left: -5%;
z-index: 9999;
border: 2px solid rgba(0, 0, 0, 0.2);
border-radius: 5px;
box-shadow:
inset 1px 1px 0 rgba(255, 255, 255, 0.05),
0 0 5px rgba(0, 0, 0, 0.5);
background: -webkit-linear-gradient(
rgba(20, 20, 20, 0.5),
rgba(0, 0, 0, 0.5));
color: #eee;
width: 300px;
}
.notification .content {
padding: 10px;
margin-left: 42px;
box-sizing: border-box;
}
.notification .content:after {
content: ".";
display: block;
clear: both;
visibility: hidden;
}
.notification .title {
font-size: 12px;
font-weight: bold;
margin-bottom: 3px;
}
.notification .message {
font-size: 12px;
color: #777;
}
.notification .icon {
display: inline-block;
font-family: 'Octicons Regular';
font-size: 32px;
width: 32px;
height: 32px;
margin-right: 5px;
-webkit-font-smoothing: antialiased;
}
/* TODO: Full Octicon Support */
.icon-gist {
content: "\f20e";
}
+3
Ver Arquivo
@@ -138,6 +138,9 @@ jasmine.JQuery.matchersClass = {};
var builtInMatcher = jasmine.Matchers.prototype[methodName];
jasmine.JQuery.matchersClass[methodName] = function() {
if (this.actual instanceof HTMLElement) {
this.actual = jQuery(this.actual);
}
if (this.actual instanceof jQuery) {
var result = jQueryMatchers[methodName].apply(this, arguments);
this.actual = jasmine.JQuery.elementToString(this.actual);