Comparar commits

..

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

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

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

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

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

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

This is achieved by calling .preventDefault() on mousedown events when
the editor is already focused, which prevents the moving of focus to
the editor itself.
2014-09-02 11:37:46 -06:00
Kevin Sawicki fbcef99aac Upgrade to language-todo@0.11 2014-09-02 09:04:49 -07:00
Kevin Sawicki 8fa8519924 Upgrade to language-python@0.19 2014-09-02 08:56:04 -07:00
Kevin Sawicki 5a36988930 Upgrade to language-xml@0.19 2014-09-02 08:49:06 -07:00
Ivan Zuzak 65cae0f68d Fix indentation to make coffeelint happy 2014-09-01 18:24:04 +02:00
Ivan Zuzak 7f14965ca8 Support selecting multiple rows with meta-click 2014-09-01 17:42:55 +02:00
Ivan Zuzak 8c36d2673b Select row when clicking the gutter 2014-08-30 20:20:09 +02:00
Kevin Sawicki 7f2d9984b8 Upgrade to language-go@0.17 2014-08-29 11:30:06 -07:00
Kevin Sawicki d43702f017 🐎 Use direct comparison instead of regex 2014-08-29 09:55:50 -07:00
Kevin Sawicki 690d32cca9 Document undefined case 2014-08-29 09:42:51 -07:00
Kevin Sawicki d870cb8f36 Return undefined to ? fallback works 2014-08-29 09:42:01 -07:00
Kevin Sawicki 7cd080786c Return a boolean like the comment says 2014-08-29 09:40:55 -07:00
Kevin Sawicki a8a251c457 💄 2014-08-29 09:36:55 -07:00
Kevin Sawicki 9574458feb 📝 💄 2014-08-29 09:34:59 -07:00
Kevin Sawicki 692bf534b6 Merge pull request #3369 from khakionion/master
Better autodetection of Soft Tabs.
2014-08-29 09:34:01 -07:00
Kevin Sawicki f35346c507 Upgrade to tree-view@0.113 2014-08-29 09:15:34 -07:00
Kevin Sawicki 78f7ff6ee7 Focus existing window after opening path 2014-08-29 09:10:12 -07:00
Kevin Sawicki 71470f88ad Merge pull request #3409 from syndbg/master
Added linux open-folder keybind.
2014-08-29 08:32:07 -07:00
Ben Ogle 4b4af946cf Fix specs 2014-08-28 18:30:08 -07:00
Ben Ogle 5163d0f810 Fix dupe functions 2014-08-28 18:19:12 -07:00
Ben Ogle 08388d87c0 Remove getSelectionAtIndex
We’re going to eventually get rid of the clone in 
getSelections / getCursors freeze those properties 
and return them directly. Then they can operate 
on the list garbage free.
2014-08-28 18:16:33 -07:00
Ben Ogle 9c53d6f014 Deprecate getCursor() 2014-08-28 18:10:18 -07:00
Nathan Sobo c9e5ff6606 Organize workspace API into sections. Add ::getActiveTextEditor 2014-08-28 19:06:57 -06:00
Ben Ogle 2fced0c1bc Deprecate getSelection 2014-08-28 17:51:16 -07:00
Ben Ogle 271af5dd99 Add Editor::setSelectedScreenRanges() 2014-08-28 17:28:24 -07:00
Nathan Sobo 6c2bb26e77 Add Workspace::observeTextEditors and ::onDidAddTextEditor 2014-08-28 18:28:10 -06:00
Nathan Sobo 70a23b0107 Add Workspace::getPanes and ::getPaneItems 2014-08-28 18:27:13 -06:00
Ben Ogle c6a76e6c62 De public a non-used method 2014-08-28 16:59:10 -07:00
Ben Ogle 535724fa84 Nothing uses this function, not internal nor packages. 2014-08-28 16:58:59 -07:00
Ben Ogle 14dcf50683 De-public a couple unused methods 2014-08-28 16:53:44 -07:00
Ben Ogle 882261e782 Break into Essential and extended 2014-08-28 16:53:21 -07:00
Nathan Sobo acb9bdaf33 Add pane and pane item observer methods to workspace. Also document. 2014-08-28 17:52:30 -06:00
Ben Ogle 713d82a895 Reorder selections section 2014-08-28 16:51:31 -07:00
Nathan Sobo a33706ddbc Add PaneContainer::onDidAddPaneItem and ::observePaneItems 2014-08-28 17:42:12 -06:00
Ben Ogle 2551313b58 Deprecate methods on cursor 2014-08-28 16:31:10 -07:00
Nathan Sobo 877fa40a49 Activate next pane on before invoking onDidDestroy observers 2014-08-28 17:23:49 -06:00
Nathan Sobo cee7539e35 Add PaneContainer::observePanes and ::onDidAddPane 2014-08-28 17:22:28 -06:00
Ben Ogle 7ca5ece68a Add methods to be symmetrical with selections
* getCursorsOrderedByBufferPosition
* getCursorBufferPositions
* getCursorScreenPositions
2014-08-28 16:06:44 -07:00
Nathan Sobo 5471e9bccc Add PaneContainer::onDidDestroyPaneItem 2014-08-28 16:58:38 -06:00
Nathan Sobo b60b9f3e3a Add Pane::observeItems 2014-08-28 16:40:54 -06:00
Nathan Sobo 12f78dd957 💄 2014-08-28 16:27:20 -06:00
Ben Ogle e74244fc25 Move less used function down in the order 2014-08-28 15:25:35 -07:00
Ben Ogle 65ba95a449 Add missing docs 2014-08-28 15:25:23 -07:00
Ben Ogle 370ad23f7c Remove Cursor from ::moveCursor* methods 2014-08-28 15:25:12 -07:00
Nathan Sobo cea4db5381 Break pane API into sections 2014-08-28 16:24:53 -06:00
Nathan Sobo 345617e0f3 Clean up existing pane API docs 2014-08-28 15:57:30 -06:00
Nathan Sobo 78c24fb737 Remove legacy event documentation 2014-08-28 15:54:16 -06:00
Ben Ogle 01b48d2a0a Move adding cursor functions under more heavily used functions 2014-08-28 14:44:23 -07:00
Ben Ogle 45a9bd21fc Deprecate getCursorScreenRow
It’s out of place, and unnecessary.
2014-08-28 14:43:36 -07:00
Ben Ogle db83375293 Buffer before screen, get before set 2014-08-28 14:38:58 -07:00
Ben Ogle a4a25576a2 Split cursor methods into essential and extended 2014-08-28 14:35:39 -07:00
Nathan Sobo e88eb3012e Document Pane event subscription methods 2014-08-28 15:32:02 -06:00
Nathan Sobo d7063c0932 Add Pane::onDidDestroy 2014-08-28 15:21:35 -06:00
Nathan Sobo 34cb5d6012 Don’t implement ::isActive in terms of the theorist model behavior 2014-08-28 15:21:10 -06:00
Nathan Sobo 95e9686b37 Emit legacy item-added DOM event correctly 2014-08-28 14:42:13 -06:00
Nathan Sobo b1916069de Delegate ::getActivePane[Item] directly to PaneContainer 2014-08-28 14:42:13 -06:00
Nathan Sobo 9223361c22 Add PaneContainer::onDidChange/observeRoot
Also, don’t use a behavior to monitor root changes
2014-08-28 14:42:13 -06:00
Nathan Sobo 7556b85806 Remove/add the *subscription*, not the child 2014-08-28 14:42:12 -06:00
Nathan Sobo b74554ad4c Actually subscribe 2014-08-28 14:42:12 -06:00
Nathan Sobo b34367ad44 💄 pane-container-spec 2014-08-28 14:42:12 -06:00
Nathan Sobo cf3e1177ab Upgrade event-kit to fix stupid bug 2014-08-28 14:42:12 -06:00
Nathan Sobo 74b2f26540 Add PaneContainer::onDidChangeActivePaneItem 2014-08-28 14:41:56 -06:00
Nathan Sobo b89202f82c Dispose of PaneAxis subscriptions when destroyed 2014-08-28 14:41:56 -06:00
Nathan Sobo 9487609f0c 💄 pane-container-spec 2014-08-28 14:41:56 -06:00
Nathan Sobo da63c6bab2 Add ::onDidDestroy to Pane and PaneAxis 2014-08-28 14:41:56 -06:00
Ivan Žužak a00b3b2cc9 Merge pull request #3394 from atom/iz-builtin-context-menu-commands
Add cut/copy/paste built-in context menu items
2014-08-28 20:41:21 +02:00
Ben Ogle 0888d8ac60 Upgrade atom-dark-ui 2014-08-28 11:27:45 -07:00
Ben Ogle b895f7074d Upgrade find and replace to remove deprecation 2014-08-28 11:19:40 -07:00
Ivan Zuzak 7b73d6749d Add undo, redo, delete and select all commands to context menu 2014-08-28 20:13:16 +02:00
Nathan Sobo 67c3a41a60 Upgrade event-kit to fix bug and get CompositeDisposable::remove 2014-08-28 11:43:33 -06:00
Nathan Sobo c25ab0db43 Rename ::disposables to ::subscriptions in PaneView
Now that emissary’s Subscriber no longer conflicts with the name
2014-08-28 11:43:09 -06:00
Nathan Sobo 9979ae4b09 Add child event methods to PaneAxis
This eliminates our reliance on the Sequence object for informing us
of changes
2014-08-28 11:43:09 -06:00
Nathan Sobo a9294aebc3 Don’t use Sequence in PaneAxis 2014-08-28 11:43:09 -06:00
Nathan Sobo f161f5352e Don’t rely on Sequences to reparent the last child 2014-08-28 11:43:09 -06:00
Nathan Sobo 4f826a70f8 Use Array instead of Sequence for Pane::items 2014-08-28 11:43:08 -06:00
Nathan Sobo 1d365db9df Use getActiveItem getter in pane-view-spec 2014-08-28 11:43:08 -06:00
Nathan Sobo b9feed8eb4 Handle objects in subscriptions instead of multiple args 2014-08-28 11:43:08 -06:00
Nathan Sobo 475dc6074c 💄 2014-08-28 11:43:08 -06:00
Nathan Sobo 40d93cd0cf Use Pane::setActiveItem internally so observers are invoked 2014-08-28 11:43:08 -06:00
Nathan Sobo 99d70b4a4e Don’t emit ::onDidChangeActiveItem events unless it really changes 2014-08-28 11:43:08 -06:00
Nathan Sobo 87cdc1a45d Don’t invoke ::onDidChangeActivePane events unless it really changes 2014-08-28 11:43:08 -06:00
Nathan Sobo e7a7e86dea Add Pane::observeActive and ::observeActiveItem
These have behavior semantics, invoking the observer immediately with
the current value of the observed property.
2014-08-28 11:43:07 -06:00
Nathan Sobo b6c669a292 Subscribe with new event methods in PaneView 2014-08-28 11:43:07 -06:00
Nathan Sobo 44d70aaa5b Add Pane::onDidChangeActive() 2014-08-28 11:43:07 -06:00
Nathan Sobo 2b63f8a4ee Add PaneContainer::onDidChangeActivePane 2014-08-28 11:43:07 -06:00
Nathan Sobo 8225f759bf Add Pane::onWillDestroyItem() 2014-08-28 11:43:07 -06:00
Nathan Sobo 2d58d9c8b5 Add Pane::onDidActivate 2014-08-28 11:43:07 -06:00
Nathan Sobo 548018e9b2 Add spec for onDidRemoveItem observers when moving items to other panes 2014-08-28 11:43:07 -06:00
Nathan Sobo 9bd2eec4bc Add Pane::onDidMoveItem() 2014-08-28 11:43:07 -06:00
Nathan Sobo b8fcbe9451 Start adding event subscription methods to pane
This branch uses EventKit, an ultra-simple library for implementing
events. The object implementing the methods maintains its own emitter
object rather than doing a mixin like Emissary encourages. This will
make it easier for us to deprecate ::on on the object itself. Unlike
emissary, the EventKit Emitter implements a super minimalistic API that
only allows one value to be emitted and always returns a Disposable
from subscriptions.
2014-08-28 11:43:06 -06:00
Ivan Zuzak 861dff107a 💄 simplify assignment using coffeescript magic 2014-08-28 19:42:59 +02:00
Nathan Sobo ebb02bcd37 Use public getters instead of properties in pane-spec 2014-08-28 11:42:42 -06:00
syndg fcb72049e1 Added linux open-folder keybind.
Moved application:open-dev to `ctrl-alt-o`
2014-08-28 14:05:42 +03:00
Michael Herring 039e61e960 updated regex in usesSoftTabs to only look for Tab and Space 2014-08-28 17:44:49 +09:00
Michael Herring 002f9ca2b1 merge latest upstream master 2014-08-28 17:35:09 +09:00
Ben Ogle 726b04ef80 Update find-and-replace 2014-08-27 19:21:49 -07:00
Kevin Sawicki 20b64dd744 Upgrade to tabs@0.50 2014-08-27 15:26:31 -07:00
Kevin Sawicki a3d2924484 Split on whitespace 2014-08-27 14:43:23 -07:00
Kevin Sawicki d225966374 installSize -> installedSize 2014-08-27 14:35:16 -07:00
Kevin Sawicki 6d23fa1620 🐧 Set installedSize value in control file
Closes #2183
2014-08-27 14:23:09 -07:00
Kevin Sawicki 682d84dea0 Log location of created .deb file 2014-08-27 14:09:57 -07:00
Kevin Sawicki 969e5b65df Upgrade to welcome@0.18 2014-08-27 12:36:36 -07:00
Kevin Sawicki 8e5f4ced21 🐧 Move settings items to Edit menu
Closes #2467
2014-08-27 12:34:48 -07:00
Ben Ogle bbdd304834 Merge pull request #3229 from atom/docs-metadata
New API docs
2014-08-27 11:33:04 -07:00
Kevin Sawicki 5360b719f2 Upgrade to oniguruma 3.0.4 2014-08-27 11:29:14 -07:00
Kevin Sawicki 17a9e397f3 🐧 Add ~/.atom open commands to File menu 2014-08-27 11:10:30 -07:00
Kevin Sawicki f01f0eb90b Upgrade to language-sass@0.20 2014-08-27 10:57:33 -07:00
Kevin Sawicki 53d16098ca Merge pull request #3396 from syndbg/master
Added missing keybind in linux.cson.
2014-08-27 10:17:25 -07:00
Ben Ogle cb34539508 Fix syntax highlighting 2014-08-27 09:36:08 -07:00
syndg 1221a140aa Added missing keybind in linux.cson.
`'ctrl-,': 'application:show-settings'` exists in `win32.cson` and `darwin32.cson`
2014-08-27 17:10:08 +03:00
Ivan Zuzak 776a8e935a Add cut/copy/paste built-in context menu items 2014-08-27 13:55:44 +02:00
Ivan Zuzak 096255f283 Support built-in context menu items 2014-08-27 13:54:55 +02:00
Ben Ogle 327749b6c5 Upgrade packages in the public docs.
They now are on the latest grunt-atomdoc and have docstrings that export
well
2014-08-26 19:23:51 -07:00
Kevin Sawicki cd3bd048fd Merge pull request #3389 from atom/ks-spec-task-on-linux
Add spec task on Linux
2014-08-26 18:38:34 -07:00
Ben Ogle d79807fbe5 Document atom.* globals as properties 2014-08-26 16:00:35 -07:00
Ben Ogle 7a67619216 Use donna 1.0 2014-08-26 15:59:53 -07:00
Kevin Sawicki 496e49a5b9 Use correct process name on Linux 2014-08-26 15:10:43 -07:00
Kevin Sawicki 08decbe533 Explicitly set app path perms to 755 on Linux 2014-08-26 14:59:42 -07:00
Kevin Sawicki 37fc8b5945 Add initial spec task support on linux 2014-08-26 14:59:42 -07:00
Kevin Sawicki f88c805466 Upgrade to markdown-preview@0.100 2014-08-26 14:59:28 -07:00
Kevin Sawicki e8cd59eaef Waits for reloaded event from ThemeManager
Previously disabling a theme wouldn't wait for the full reload
to finish since and the spec would intermittently fail because
the promise was fulfilled after the spec completed and the
subscription was leaked.
2014-08-26 14:23:20 -07:00
Kevin Sawicki 600005de15 Upgrade to go-to-line@0.25 2014-08-26 14:21:14 -07:00
Kevin Sawicki aaa788b8da Upgrade to settings-view@0.141 2014-08-26 12:53:44 -07:00
Kevin Sawicki 9a70fdc3d9 Prepare 0.125 2014-08-26 12:04:27 -07:00
Ben Ogle 48f161b63a Merge pull request #3388 from atom/bo-remove-all-old-editor
Remove ancillary old editor views
2014-08-26 11:39:51 -07:00
Kevin Sawicki f032dacebb Upgrade to background-tips@0.16 2014-08-26 11:24:10 -07:00
Ben Ogle a296364e53 Fixup doc strings that don’t parse correctly
We can’t have a huge indent on the second line of a list item. Markdown
parses it as a code block. :(
2014-08-26 10:47:36 -07:00
Kevin Sawicki 5ba86b3dbc Normalize file paths in Project::resolve
This ensures the drive case letter is consistent on Windows
when opening file paths from the command line.
2014-08-26 10:22:20 -07:00
Ben Ogle 790f134d7c Remove ancillary old editor views 2014-08-26 10:07:18 -07:00
Kevin Sawicki 32353a31eb Only restore window when it is minimized
Restoring a maximized windows on Windows unmaximizes it.

Closes #3381
2014-08-26 09:55:22 -07:00
Nathan Sobo 0bae432109 Revert "Merge the react and non-react editor styles"
This reverts commit 01c4fe5340.
2014-08-26 09:24:44 -06:00
Ben Ogle d8a4280df1 Upgrade text-buffer for updated doc strings 2014-08-25 19:05:50 -07:00
Nathan Sobo dccb2c295c Update status bar to fix specs 2014-08-25 18:48:03 -06:00
Nathan Sobo 2a94e4a33c Pass tokenizedLines to LinesComponent so measuring stays in sync
Fixes #3318
2014-08-25 18:16:45 -06:00
Nathan Sobo 3371ceadf3 Add regression coverage for remeasuring characters w/ requested update
The problem here is that the lines in the editor no longer reflect the
lines on screen, but we're looking for line nodes corresponding to the
editor's current contents.
2014-08-25 18:16:38 -06:00
Nathan Sobo 070ca1a4bb Call checkForVisibilityChange when showing editors via EditorView::show/hide 2014-08-25 18:16:29 -06:00
Kevin Sawicki 157a753bfb Upgrade to space-pen 3.4.3 2014-08-25 16:36:53 -07:00
Nathan Sobo 0849f1ea84 Perform a sync update after editor becomes visible
This pauses updates during measurements. If any updates were requested
while measuring, we force an update synchronously to prevent flicker.

This commit also removes the visibility check before updating, because
we can't force an update from this spot in the lifecycle. This shouldn't
be needed anyway because we are polling for visibility changes.
2014-08-25 17:31:29 -06:00
Nathan Sobo c4f5a3516b Assign atom.lastUncaughtError in window.onerror handler 2014-08-25 16:36:14 -06:00
Kevin Sawicki 08f39c6a5a Upgrade to atom-keymap@2.0.4 2014-08-25 15:35:47 -07:00
Kevin Sawicki 69aa34954f Remove call to no-op EditorView method 2014-08-25 15:31:39 -07:00
Ben Ogle d6d7d3942c 📝 Convert EditorView docs 2014-08-25 15:26:38 -07:00
Ben Ogle c3acd8cf0c 📝 Convert workspaceView docs 2014-08-25 15:13:46 -07:00
Ben Ogle 12f58f0478 📝 Convert workspace docs 2014-08-25 15:13:45 -07:00
Ben Ogle 66e6a481a4 📝 Convert ThemeManager docs 2014-08-25 15:13:45 -07:00
Ben Ogle de27dce6bf Convert SelectListView docs 2014-08-25 15:13:45 -07:00
Ben Ogle 6c19a58c7c 📝 Convert Project docs 2014-08-25 15:13:45 -07:00
Ben Ogle c294208f87 📝 Convert PaneView docs 2014-08-25 15:13:45 -07:00
Ben Ogle d7f3add250 📝 Convert Pane docs 2014-08-25 15:13:45 -07:00
Ben Ogle a93ef05e13 📝 Convert Selection docs 2014-08-25 15:13:45 -07:00
Kevin Sawicki 8241918b6e Include classes from node_modules in proper object and order 2014-08-25 15:13:45 -07:00
Ben Ogle 8aae7b983e 📝 Convert Cursor Docs 2014-08-25 15:13:45 -07:00
Ben Ogle ad4f464d7c Fix Decoration events 2014-08-25 15:13:45 -07:00
Ben Ogle 352f1e34ab No mo : 2014-08-25 15:08:46 -07:00
Kevin Sawicki 2cdae3c6c1 Upgrade to pathwatcher 2.0.9 2014-08-25 15:08:46 -07:00
Kevin Sawicki 5df944e804 📝 Update Task docs 2014-08-25 15:08:46 -07:00
Kevin Sawicki 762f8c2e5a 📝 Update Syntax docs 2014-08-25 15:08:46 -07:00
Kevin Sawicki 41c96a82a9 Upgrade to first-mate 2.0.4 2014-08-25 15:08:46 -07:00
Ben Ogle 5a51d3a0c9 Fix indentation 2014-08-25 15:08:46 -07:00
Ben Ogle d79eb8eed3 Update decoration docs 2014-08-25 15:08:46 -07:00
Ben Ogle 9bb6bdf666 Update decorateMarker docs 2014-08-25 15:08:46 -07:00
Ben Ogle 0ab282340f Upgrade to tello@0.2 2014-08-25 15:08:45 -07:00
Ben Ogle 393f6bdd35 Add optional to all optional args 2014-08-25 15:08:45 -07:00
Ben Ogle a4b2f3aa4b Editor event documentation 2014-08-25 15:08:45 -07:00
Kevin Sawicki ee4c7e996f 📝 Convert ScrollView docs 2014-08-25 15:08:45 -07:00
Kevin Sawicki 59bf16fed3 📝 Convert PackageManager docs 2014-08-25 15:08:45 -07:00
Ben Ogle 99917a536e Add a couple events for test purposes 2014-08-25 15:08:45 -07:00
Ben Ogle 61a82fa0e4 Upgrade tello to use new events format 2014-08-25 15:08:45 -07:00
Kevin Sawicki 0bca0810b9 📝 Convert MenuManager docs 2014-08-25 15:08:45 -07:00
Kevin Sawicki 7d910000a2 📝 Convert DeserializerManager docs 2014-08-25 15:08:45 -07:00
Kevin Sawicki af67671f60 📝 Convert ContextMenuManager docs 2014-08-25 15:08:45 -07:00
Kevin Sawicki 0079007bb6 📝 Convert Config docs 2014-08-25 15:08:45 -07:00
Kevin Sawicki c2fa20c543 📝 Convert Clipboard docs 2014-08-25 15:08:45 -07:00
Kevin Sawicki aa5870570f 📝 Convert BufferedProcess docs 2014-08-25 15:08:45 -07:00
Kevin Sawicki 0e0d62b54c 📝 Convert BufferedNodeProcess docs 2014-08-25 15:08:45 -07:00
Kevin Sawicki 37542e3117 📝 Convert Atom docs 2014-08-25 15:08:44 -07:00
Kevin Sawicki 90e89ebaf9 📝 Convert Git docs 2014-08-25 15:07:15 -07:00
Ben Ogle e4939a8d6d Add sections to editor docs 2014-08-25 15:07:15 -07:00
Kevin Sawicki 50ddb8e3cc Upload atom-api.json asset during publish 2014-08-25 15:04:22 -07:00
Kevin Sawicki c61e36c7d3 Remove donnatello output 2014-08-25 15:04:22 -07:00
Kevin Sawicki 3035242daf Task is no longer async 2014-08-25 15:04:22 -07:00
Kevin Sawicki cfc965c135 Write to docs/output/api.json 2014-08-25 15:04:22 -07:00
Kevin Sawicki 1bc879a9b0 Remove copy-docs unused task 2014-08-25 15:04:22 -07:00
Kevin Sawicki 6225acbe8b Genrate docs from local api.json files 2014-08-25 15:04:22 -07:00
Kevin Sawicki bdf68ba15f Upgrade to theorist 1.0.2 2014-08-25 15:04:22 -07:00
Kevin Sawicki bbef8083d5 Upgrade to text-buffer 3.0.2 2014-08-25 15:04:21 -07:00
Kevin Sawicki f2f88cb343 Upgrade to space-pen 3.4.2 2014-08-25 15:04:21 -07:00
Kevin Sawicki a42de1e9be Upgrade to pathwatcher@2.0.8 2014-08-25 15:04:21 -07:00
Kevin Sawicki 1c97eb977e 💄 2014-08-25 15:04:21 -07:00
Kevin Sawicki d13fd495e4 Upgrade to first-mate 2.0.3 2014-08-25 15:04:21 -07:00
Kevin Sawicki c49ef1fd9d Parse all api.json files in node_modules 2014-08-25 15:04:21 -07:00
Ben Ogle e011be3428 Update argument lists in editor.coffee 2014-08-25 15:04:21 -07:00
Kevin Sawicki f993b78479 Remove unused deploy-docs task 2014-08-25 15:04:21 -07:00
Ben Ogle 86ef06ebb1 Update to contain superclasses 2014-08-25 15:04:21 -07:00
Ben Ogle 9f27e53bf1 Remove unnecessary metadata.json 2014-08-25 15:04:21 -07:00
Ben Ogle 720770e2ba Dont dupe classes 2014-08-25 15:04:21 -07:00
Ben Ogle e86b8c1a66 Remove unnecessary things 2014-08-25 15:04:20 -07:00
Ben Ogle 3b9d25ae92 Use donna and tello. Together. 2014-08-25 15:04:20 -07:00
Ben Ogle 9ee6a3d430 Docs task uses metadoc 2014-08-25 15:04:19 -07:00
Ben Ogle 162713e5b5 Sync package.json files for doc imports 2014-08-25 15:04:19 -07:00
Ben Ogle 83659272ac Merge pull request #3132 from atom/bo-remove-oe
Remove old editor
2014-08-25 14:59:30 -07:00
Ben Ogle abadc9805c Add _all_ the defaults in from editorView 2014-08-25 14:46:48 -07:00
Ben Ogle ad269357b7 Ugh. No @mini. @mini is a prop. 2014-08-25 14:34:19 -07:00
Ben Ogle ae323d2083 Use @mini 2014-08-25 12:24:19 -07:00
Ben Ogle cef24a3979 Remove the react editor options 2014-08-25 12:15:34 -07:00
Ben Ogle 7220c61e98 upgrade to find-and-replace to remove old editor stuff 2014-08-25 12:13:41 -07:00
Ben Ogle 6e40f3b2f9 upgrade to bookmarks to remove old editor stuff 2014-08-25 12:11:39 -07:00
Ben Ogle c4811a8fb7 upgrade to git-diff to remove old editor stuff 2014-08-25 12:10:13 -07:00
Kevin Sawicki c7242ec964 Upgrade to language-yaml@0.17 2014-08-25 12:09:39 -07:00
Ben Ogle d37bd14a62 Deprecate getEditor() at a later date… 2014-08-25 12:07:48 -07:00
Ben Ogle 3d2d8c491f rename react-editor-view -> editor-view 2014-08-25 12:07:48 -07:00
Ben Ogle b05a83a6ce move getEditor fn 2014-08-25 12:07:48 -07:00
Ben Ogle 0d68430bb8 Deprecate gutter api 2014-08-25 12:07:48 -07:00
Ben Ogle d75485a2d8 Deprecate no-op’d things 2014-08-25 12:07:48 -07:00
Ben Ogle e54bc0fbaa Remove toggle soft wrap and toggle soft tabs
No one uses them in packages, and we don’t use them internally
2014-08-25 12:07:17 -07:00
Ben Ogle cf9208bc02 Deprecate pageUp / pageDown 2014-08-25 12:07:16 -07:00
Ben Ogle 35fd19f3ef 📝 Add docs for current public methods 2014-08-25 12:07:16 -07:00
Ben Ogle 97bcdcc9b0 Rename ReactEditorView -> EditorView 2014-08-25 12:05:55 -07:00
Ben Ogle fc441ef5e2 📝 fix return doc 2014-08-25 12:05:55 -07:00
Ben Ogle 01c4fe5340 Merge the react and non-react editor styles 2014-08-25 12:05:10 -07:00
Ben Ogle 431fab1a43 Remove the editor-view 2014-08-25 12:05:10 -07:00
Ben Ogle 0e62c98768 Fix the mini-editor test 2014-08-25 12:02:38 -07:00
Ben Ogle f8026bb005 Require the react-editor-view where we require the editor-view 2014-08-25 12:02:38 -07:00
Ben Ogle ef889a50ed Merge pull request #3376 from atom/bo-marker-in-splits
Only emit the marker-created event when the marker exists
2014-08-25 11:55:12 -07:00
Ben Ogle c3c91ae6c3 Only emit the marker-created event when the marker exists
This caused problems in the case of find-and-replace:select-all with 
multiple editors into the same file. 

* a marker is created on the TextBuffer capturing the selection
* DisplayBuffer:create-marker is fired from the first DisplayBuffer. 
The marker is turned into a selection which is merged into the current 
selection, deleting the marker that was created.
* DisplayBuffer::handleBufferMarkerCreated is called on the second
DisplayBuffer. The marker has been destroyed at this point, so it emits 
DisplayBuffer:create-marker with undefined. 
* ERROR>

Closes #3364
2014-08-25 11:42:44 -07:00
Ben Ogle c073d042b8 Merge pull request #3371 from atom/iz-fix-context-menu-again
Dont handle ctrl+click mouse events on OSX
2014-08-25 10:44:11 -07:00
Kevin Sawicki ecf237697b Add react editor view spec for data grammar attrs 2014-08-25 10:22:44 -07:00
Kevin Sawicki 4b8fd222f1 Merge pull request #2996 from thomasjo/editorview-grammarscopes
Add grammar scope to EditorView
2014-08-25 10:14:46 -07:00
Kevin Sawicki 62a1888c6b Upgrade to language-mustache@0.10 2014-08-25 10:06:29 -07:00
Kevin Sawicki 176d73dfcc Upgrade to apm 0.92 2014-08-25 09:58:09 -07:00
Kevin Sawicki c0704edb0d Merge pull request #3355 from atom/ks-open-files-in-current-window
Open file paths in focused window
2014-08-25 09:39:11 -07:00
Kevin Sawicki fb53f85573 Rename topWindow to lastFocusedWindow 2014-08-25 09:21:27 -07:00
Kevin Sawicki 6610447e09 📝 Clarify safeMode description 2014-08-25 09:21:27 -07:00
Kevin Sawicki 9f7560bb89 📝 Doc other atom.open options 2014-08-25 09:21:27 -07:00
Kevin Sawicki a853a27857 Open folder in current untitled window
Untitled windows will now have their project path set when a folder
is opened.
2014-08-25 09:21:27 -07:00
Kevin Sawicki 154fe4006f 📝 Doc file/folder path behavior in usage message 2014-08-25 09:21:27 -07:00
Kevin Sawicki 17feb91876 📝 Move comment above isFile check 2014-08-25 09:21:27 -07:00
Kevin Sawicki 5bdf8a14a7 Use once for closed event 2014-08-25 09:21:27 -07:00
Kevin Sawicki 1196e5a264 📝 Doc dev mode case 2014-08-25 09:21:27 -07:00
Kevin Sawicki a4ae314b00 💄 2014-08-25 09:21:27 -07:00
Kevin Sawicki c9390b61de Track AtomWindow from ipc open event
This ensures the window where the file is dropped is used to open
that file into even when that window does not have focus.
2014-08-25 09:21:27 -07:00
Kevin Sawicki 2811663177 Open file paths in focused window 2014-08-25 09:21:26 -07:00
Thomas Johansen 4dc89f1b1e 🐛 Fix incorrect assertions 2014-08-24 14:14:26 +02:00
Ivan Zuzak b0a9eefa04 Dont handle ctrl+click mouse events on OSX
Ctrl+click on OSX brings up the context menu. In that case, handling the click
event deselects any selection, and that shouldn't happen. See
https://github.com/atom/atom/issues/3308.
2014-08-24 13:33:30 +02:00
Michael Herring aa9728c004 Better autodetection of Soft Tabs.
Check for the presence of a space, instead of the absence of a tab.
This ensures that Soft Tabs will not be activated on a file that (for
example) starts with a BOM or something, but is otherwise full of hard
tabs.
2014-08-24 19:04:46 +09:00
Thomas Johansen dc55d42491 Add test to verify implementation 2014-08-24 10:17:26 +02:00
Thomas Johansen d3b06542a5 Change attribute name to data-grammar 2014-08-24 10:17:25 +02:00
Thomas Johansen 9c154a2f5a Implement support for React Editor 2014-08-24 10:17:25 +02:00
Thomas Johansen 6b1868efd5 Make sure the scope data attribute is always set 2014-08-24 10:17:25 +02:00
Thomas Johansen e50887aab8 Use data attribute instead of CSS classes 2014-08-24 10:17:25 +02:00
Thomas Johansen c6ca03fa49 Add grammar scope to EditorView
Only works when the `grammar-changed` event has been triggered,
and only implemented for Space Pen views.
2014-08-24 10:17:25 +02:00
Ben Ogle a15deaef81 Upgrade to git-diff@0.38.0 to add arrow for deletions. 2014-08-23 10:43:46 -07:00
Kevin Sawicki 461cca2d22 Upgrade to incompatible-packages@0.9 2014-08-22 12:01:41 -07:00
Nathan Sobo d15728321c Merge pull request #3353 from atom/ns-fix-char-width-measurement
Rework DOM measurement to try to prevent measurement errors
2014-08-22 12:07:42 -06:00
Nathan Sobo 9164b0ea3b Don't remeasure char widths until we've performed initial measurement 2014-08-22 11:37:04 -06:00
Nathan Sobo 59a80dcd60 Don't use guard clauses in short measurement methods 2014-08-22 11:36:17 -06:00
Nathan Sobo 72354ebf32 Check for visibility change when mounting instead of polling DOM 2014-08-22 11:35:51 -06:00
Kevin Sawicki a56cea2408 Upgrade to language-ruby-on-rails@0.18 2014-08-22 10:29:05 -07:00
Kevin Sawicki cc28eaf6d2 Upgrade to language-mustache@0.9 2014-08-22 08:56:29 -07:00
Kevin Sawicki 283c76ad3c Upgrade to language-make@0.12 2014-08-22 08:50:53 -07:00
Nathan Sobo a71a524ec7 Rework DOM measurement to try to prevent measurement errors
* Simplify scrollbar refresh and measurement by using imperative DOM
  manipulation instead of React to hide/show scrollbars.
* Rename `::performInitialMeasurement` to `::becameVisible`
* Break `::checkForVisibilityChange` out of `::pollDOM` and use it in
  to check for the element becoming visible in `componentWillUpdate`.
* Don't rely on stored visibility state anywhere. Always check again.
  This could potentially be cached for an update cycle but being wrong
  about this is disastrous so I'm being conservative.
2014-08-21 17:50:46 -06:00
Ben Ogle a2f7ec9d73 Merge pull request #3350 from atom/bo-theme-classes
Add classes to the workspace for themes
2014-08-21 12:01:53 -07:00
Ben Ogle 26d696a93d Add classes to the workspace for themes
Fixes #3097
2014-08-21 11:53:10 -07:00
Ben Ogle 30aa47026d Do not move cursor when interacting with horiz scrollbar
Fix #3284
2014-08-21 10:40:16 -07:00
Kevin Sawicki ec6bfbb9e6 Merge pull request #3349 from aaronshaf/patch-1
Removed unnecessary comma
2014-08-21 10:11:00 -06:00
Aaron Shafovaloff d986ab0293 Removed unnecessary comma 2014-08-21 10:09:32 -06:00
Kevin Sawicki c7f5321d14 Upgrade to language-make@0.11 2014-08-21 09:59:38 -06:00
Kevin Sawicki cb868bab4c Upgrade to language-hyperlink@0.12 2014-08-21 09:57:15 -06:00
Kevin Sawicki 024d7f8d88 Upgrade to language-sass@0.19 2014-08-20 10:13:32 -06:00
Cheng Zhao 1022d8ab4b Upgrade to atom-shell@0.15.9 2014-08-20 19:04:45 +08:00
Kevin Sawicki 760e6c6c29 Upgrade to language-sass@0.18 2014-08-19 16:37:42 -06:00
Nathan Sobo beae15ef7f Update find-and-replace for new config settings 2014-08-19 16:24:14 -06: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
Nathan Sobo 5cb084d568 Fix editor:move-to-first-character-of-line with leading hard tabs
Fixes #3314
2014-08-19 11:50:04 -06:00
Kevin Sawicki f72daffdbb Upgrade to spell-check@0.42 2014-08-19 11:44:09 -06:00
Kevin Sawicki 4aba8fef7e 📝 Mention Task::start/Task::send throw errors
Refs #3326
2014-08-19 11:39:20 -06:00
Kevin Sawicki 75853e2f9c Upgrade to language-ruby-on-rails@0.17 2014-08-19 10:28:46 -06:00
Kevin Sawicki 3baeb3797f Merge pull request #3289 from abahgat/mkdeb-permissions
🐧 Set file mode to 755 to directories created for mkdeb.
2014-08-19 10:03:15 -06:00
Kevin Sawicki 7d0452f093 Upgrade to language-ruby@0.35 2014-08-19 09:45:50 -06:00
Kevin Sawicki 7edcadb50a Upgrade to language-ruby-on-rails@0.16 2014-08-18 19:11:17 -06:00
Kevin Sawicki fc198b6e17 Upgrade to language-gfm@0.48 2014-08-18 18:57:03 -06:00
Kevin Sawicki 86f8944aaf Remove default Window menu on Windows/Linux
This is really only a thing on Mac OS X

Closes #3307
2014-08-18 09:31:10 -06:00
Kevin Sawicki dda0e7f4ce Upgrade to language-c@0.28 2014-08-18 08:35:07 -06:00
Kevin Sawicki e1ff6ab327 Upgrade to setings-view@0.140 2014-08-18 08:22:29 -06:00
Kevin Sawicki 2b87f4bcb5 Merge pull request #3315 from dmnd/fix-checkout-head
Fix error when running `checkout-head-revision`
2014-08-18 08:07:07 -06:00
Cheng Zhao 3190c0c517 Upgrade to atom-shell@0.15.8 2014-08-18 20:02:15 +08:00
Desmond Brand a1d8ee86f9 Fix error when running checkout-head-revision
I got the following error when running `checkout-head-revision`:

```
Uncaught TypeError: undefined is not a function /Applications/Atom.app/Contents/Resources/app/src/editor-component.js:804
addCommandListeners.editor:checkout-head-revision /Applications/Atom.app/Contents/Resources/app/src/editor-component.js:804
(anonymous function) /Applications/Atom.app/Contents/Resources/app/src/editor-component.js:840
jQuery.event.dispatch /Applications/Atom.app/Contents/Resources/app/node_modules/space-pen/vendor/jquery.js:4676
elemData.handle /Applications/Atom.app/Contents/Resources/app/node_modules/space-pen/vendor/jquery.js:4360
module.exports.KeymapManager.dispatchCommandEvent /Applications/Atom.app/Contents/Resources/app/node_modules/atom-keymap/lib/keymap-manager.js:400
module.exports.KeymapManager.handleKeyboardEvent /Applications/Atom.app/Contents/Resources/app/node_modules/atom-keymap/lib/keymap-manager.js:181
module.exports.WindowEventHandler.onKeydown
```

It looks like it was caused by a bad merge conflict resolution in 0eaec57.

Test Plan:

Built new Atom and pressed `cmd-alt-z` and didn't get an error.

Looked at a side-by-side diff to check for any other merge issues:

```
git difftool -t opendiff 32e59ce..32e59ce^ src/editor-component.coffee
```
2014-08-17 17:57:08 -07:00
Kevin Sawicki ebbea64b3d Merge pull request #3295 from dmnd/tighten-lint-rules
Tighten lint rules
2014-08-15 17:18:34 -07:00
Desmond Brand a20f04149c remove line_endings rule 2014-08-15 17:06:43 -07:00
Kevin Sawicki b46e03437c Upgrade to styleguide@0.30 2014-08-15 16:58:24 -07:00
Desmond Brand ccd32cd084 💄 arrow spacing warn -> error 2014-08-15 15:57:50 -07:00
Desmond Brand 6b5d16173b 💄 more lint rules 2014-08-15 15:55:22 -07:00
Kevin Sawicki 237d71417d Upgrade to language-coffee-script@0.30 2014-08-15 15:54:59 -07:00
Desmond Brand 590bfa0c86 💄 Tighten lint rules
coffeelint.json had some rules set to ignore, but since #3116 was merged there
are no violations of these rules in the code anymore. Tighten up the rules to
prevent those kinds of errors from creeping back in.

Test Plan:

Lint executes without finding any errors

```
$ ./script/grunt coffeelint
Running "coffeelint:src" (coffeelint) task
>> 80 files lint free.

Running "coffeelint:build" (coffeelint) task
>> 23 files lint free.

Running "coffeelint:test" (coffeelint) task
>> 40 files lint free.
Done, without errors.
```
2014-08-15 15:34:33 -07:00
Ben Ogle 881c21829b Fix benchmark requires 2014-08-15 14:13:03 -07:00
Ben Ogle 34f96b2ea2 Correctly bootstrap the benchmarks 2014-08-15 14:13:03 -07:00
Ben Ogle c989557b5e Run benchmarks passes specDir 2014-08-15 14:13:03 -07:00
Kevin Sawicki 0a07e862c2 Upgrade to language-html@0.25 2014-08-15 14:02:37 -07:00
Kevin Sawicki 0eaec57f7b Merge pull request #3116 from maschs/ms-srcLint
coffeelint!
2014-08-15 13:52:15 -07:00
Kevin Sawicki 5873a03145 Prepare 0.124 2014-08-15 12:43:52 -07:00
Kevin Sawicki 3ff8f35863 Swap order of ctrl-w and ctrl-f4
This allows `Ctrl-W` to appear in the system menu again until
the atom-shell issue with function keys is fixed.

Refs atom/atom-shell#485
Closes #3283
2014-08-15 12:17:09 -07:00
Nathan Sobo 6c52bcf20c Assign ::firstNonWhitespace/TrailingWhitespaceIndex in Token::split
Fixes #3277
2014-08-15 12:58:27 -06:00
Kevin Sawicki 5975548cec Upgrade to space-pen@3.4.1 2014-08-15 11:56:42 -07:00
Kevin Sawicki 3742dadbb9 Upgrade to language-gfm@0.47 2014-08-15 11:39:28 -07:00
Ben Ogle 919f541685 Merge pull request #3261 from atom/bo-default-react-mini
Default to the react mini editors
2014-08-15 11:16:28 -07:00
Kevin Sawicki 8bebfdb871 Start shipping language-mustache 2014-08-15 11:00:30 -07:00
Alessandro Bahgat cda8382902 🐧 Set file mode to 755 to directories created for mkdeb. 2014-08-15 13:41:42 -04:00
Kevin Sawicki dfbf0de961 Upgrade to language-yaml@0.16 2014-08-15 09:48:38 -07:00
Kevin Sawicki 4a9e397be0 Upgrade to language-less@0.14 2014-08-15 09:00:09 -07:00
Kevin Sawicki e10a578c04 Upgrade to open-on-github@0.30 2014-08-15 08:45:21 -07:00
Nathan Sobo 2bd8456923 Preserve invisibles in editor model across serialization
Fixes #3281
2014-08-15 08:18:53 -06:00
Cheng Zhao c5f0126078 Merge pull request #3286 from atom/atom-shell-v0.15.7
Upgrade to atom-shell@0.15.7
2014-08-15 22:18:49 +08:00
Cheng Zhao 28500e189b Upgrade to atom-shell@0.15.7 2014-08-15 18:55:34 +08:00
Kevin Sawicki a62e90820d Upgrade to autoflow@0.18 2014-08-14 16:45:43 -07:00
Kevin Sawicki 853e8e8f17 Upgrade to status-bar@0.43 2014-08-14 16:27:29 -07:00
Kevin Sawicki 1da47dbbbd Upgrade to grammar-selectoro@0.29 2014-08-14 16:18:52 -07:00
Kevin Sawicki f96ac09c36 Merge pull request #3276 from atom/ks-restore-maximized-state
Restore maximized state of window
2014-08-14 15:55:53 -07:00
Kevin Sawicki d6852cab15 Don't maximize on Mac OS X
Just setting size, position, and full screen state is sufficient since
there is no explicit maximized state.
2014-08-14 15:46:44 -07:00
Kevin Sawicki 75f01f87da Maximize window after it is shown 2014-08-14 15:30:04 -07:00
Kevin Sawicki f901007892 Document darwin check 2014-08-14 14:37:42 -07:00
Kevin Sawicki a7a6236b26 Add maximized parameter 2014-08-14 14:37:15 -07:00
Kevin Sawicki ef47bdab3f Remove unused method 2014-08-14 14:34:14 -07:00
Kevin Sawicki 8cf999f73b Store maximized state in window dimensions 2014-08-14 14:33:02 -07:00
Kevin Sawicki 20b44500d1 Restore maximized state of window
On Linux and Windows there is a maximized state that isn't the
same as simply restoring the window's size on Mac OS X.
2014-08-14 14:22:20 -07:00
Kevin Sawicki e0ebc661f2 Upgrade to language-sass@0.17 2014-08-14 14:14:19 -07:00
Kevin Sawicki d38711e2bf Uprade to atom-keymap@2.0.2 2014-08-14 13:11:51 -07:00
Kevin Sawicki 753f47ef21 Upgrade to pathwatcher@2.0.7 2014-08-14 13:11:08 -07:00
Kevin Sawicki e202ecd1b6 📝 Bool -> Boolean 2014-08-14 13:07:05 -07:00
Kevin Sawicki 02557d36c2 Prepare 0.123 2014-08-14 13:05:19 -07:00
Nathan Sobo eabad3dcef Use opacity to blink cursor instead of visibility so blink can be styled 2014-08-14 13:20:43 -06:00
Kevin Sawicki 6ad099260e Upgrade to incompatible-packages@0.8 2014-08-14 12:13:30 -07:00
Kevin Sawicki ebfd921807 Update to deprecation-cop@0.9 2014-08-14 12:11:13 -07:00
Kevin Sawicki 83c77b6e4b Upgrade to autosave@0.15 2014-08-14 11:39:16 -07:00
Maximilian Schüßler cbe5593381 Do not use "-> return" to mark empty function 2014-08-14 19:42:50 +02:00
Maximilian Schüßler 32e59ce238 Cleanup code according to coffeelint 2014-08-14 19:41:49 +02:00
Kevin Sawicki 654a4392a4 📝 Use script/build in --build-dir example 2014-08-14 09:53:10 -07:00
Kevin Sawicki 8457c74f2f 📝 💄 2014-08-14 09:52:20 -07:00
Kevin Sawicki 88366cb5d4 📝 Mention --build-dir and --install-dir
Closes #3220
2014-08-14 09:51:25 -07:00
Kevin Sawicki c70c819aa2 Upgrade to apm 0.91 2014-08-14 09:47:31 -07:00
Kevin Sawicki 4ac8aba31f Merge pull request #3264 from atom/ks-move-checkout-head-to-git-class
Move checkout head to Git class
2014-08-13 19:12:23 -07:00
Kevin Sawicki 776e431cc5 confirmCheckoutHead -> confirmCheckoutHeadRevision 2014-08-13 19:02:09 -07:00
Kevin Sawicki 5a966240b9 Make message map to command name 2014-08-13 18:51:20 -07:00
Kevin Sawicki 27f0c525ac Add since the last Git commit to detailed message 2014-08-13 18:51:19 -07:00
Kevin Sawicki 00170804e5 Remove spec now covered in git spec 2014-08-13 18:51:19 -07:00
Kevin Sawicki d7e5f05f83 💄 2014-08-13 18:51:19 -07:00
Kevin Sawicki 3ce641f53b Move checkout head editor specs to git spec 2014-08-13 18:51:19 -07:00
Kevin Sawicki 27ca957629 revert -> checkoutHead 2014-08-13 18:51:19 -07:00
Kevin Sawicki 84d0abc52c Use same dialog language as GitHub for Mac 2014-08-13 18:51:19 -07:00
Kevin Sawicki 41c62e8628 Add Git::checkoutHeadForEditor
This moves the logic from Editor::checkoutHead
2014-08-13 18:51:19 -07:00
Kevin Sawicki 1515690302 💄 2014-08-13 17:53:54 -07:00
Kevin Sawicki 2be658b894 Use async BrowserWindow::setRepresentedFilename 2014-08-13 17:47:49 -07:00
Kevin Sawicki d3e1c004fb Add status segment to event name 2014-08-13 17:46:23 -07:00
Kevin Sawicki 62924dfcd1 Use async BrowserWindow::setDocumentEdited 2014-08-13 17:44:15 -07:00
Kevin Sawicki 770e97efff Merge pull request #3171 from dmnd/proxy-icon
Add OS X proxy icon to title bar
2014-08-13 17:41:57 -07:00
Kevin Sawicki 2704d2f15a Upgrade to apm 0.90 2014-08-13 17:32:44 -07:00
Kevin Sawicki 957e45944a Upgrade to spell-check@0.41 2014-08-13 17:32:44 -07:00
Nathan Sobo 16fd14d295 Merge pull request #3206 from atom/ns-invisibles-in-tokens
Handle invisibles at the token level to fix char width measurement
2014-08-13 16:59:11 -06:00
Nathan Sobo 20daed176b Don't show invisibles in mini editors
This moves observation of the config keys to Editor, which assigns the
invisibles hash or null on the TokenizedBuffer via the DisplayBuffer to
control whether we render invisibles or not.
2014-08-13 16:32:14 -06:00
Nathan Sobo 8c11c4a4c6 Deprecate EditorComponent::setInvisibles with grim 2014-08-13 16:32:13 -06:00
Nathan Sobo 7cb44b69ef Don't assign defaults to array config values 2014-08-13 16:32:13 -06:00
Nathan Sobo d37cfb9042 Assign default invisible character glyphs via config defaults
This commit also extends config.get to merge default values into the
returned object if both the assigned and default values are objects.
This allows 'atom.invisibles' to be treated as an object that always has
the default values filled in.
2014-08-13 16:32:13 -06:00
Nathan Sobo 986753981d Use config defaults to assign default invisible characters 2014-08-13 16:32:13 -06:00
Nathan Sobo 970bde9361 Run animation frame after toggling invisibles in EditorComponent spec 2014-08-13 16:31:40 -06:00
Nathan Sobo 7b55946abf Make Editor::moveCursorToFirstCharacterOfLine work with invisible chars 2014-08-13 16:31:40 -06:00
Nathan Sobo c74f6bb615 Remove handling of invisibles from EditorComponent 2014-08-13 16:31:40 -06:00
Nathan Sobo 63f2ab3088 Render end-of-line invisibles based on state of TokenizedLine 2014-08-13 16:31:39 -06:00
Nathan Sobo 742ec6df0d Determine the endOfLineInvisibles for each TokenizedLine 2014-08-13 16:31:39 -06:00
Nathan Sobo 864f9bc2b4 Preserve hasLeading/TrailingWhitespace when copying lines w/ invisibles
This fixes the styling of the leading whitespace of folded lines
2014-08-13 16:31:39 -06:00
Nathan Sobo 73896d100e Add specs for firstNonWhitespaceIndex and firstTrailingWhitespaceIndex 2014-08-13 16:31:39 -06:00
Nathan Sobo 193001d793 Assign invisibles via config in editor-view-spec 2014-08-13 16:31:39 -06:00
Nathan Sobo 052f9580f2 Render correct classes on leading/trailing whitespace spans 2014-08-13 16:31:39 -06:00
Nathan Sobo 2daf70f0e5 Handle invisibles at the token level to fix char width measurement
Fixes #3188
2014-08-13 16:31:39 -06:00
Kevin Sawicki fca9ed07e6 Merge pull request #3169 from lee-dohm/ld-checkout-head
Add confirmation dialog to checkoutHead
2014-08-13 15:24:06 -07:00
Ben Ogle e725a8ffeb Default to on in the specs 2014-08-13 14:51:05 -07:00
Ben Ogle 23c67c53dc Default the react mini editors to on 2014-08-13 14:43:18 -07:00
Ben Ogle c6fc0d050d Upgrade text-buffer and atom-keymap for grim upgrade 2014-08-13 14:40:53 -07:00
Kevin Sawicki 6e913c47ef Upgrade to language-sass@0.16 2014-08-13 14:39:17 -07:00
Ben Ogle a245624211 Upgrade deprecation-cop to add status item 2014-08-13 13:57:03 -07:00
Ben Ogle 8af8caca55 Upgrade to grim 0.12.0 2014-08-13 13:50:19 -07:00
Ben Ogle bbeb4be5b1 Fix the status bar nested inline blocks.
They were 1 - 2px too low due to nesting inline-blocks.
2014-08-13 13:42:46 -07:00
Ben Ogle 449da91216 Add toShow matcher 2014-08-13 13:42:46 -07:00
Kevin Sawicki 521647e8ac Upgrade to incompatible-packages@0.7 2014-08-13 13:42:19 -07:00
Kevin Sawicki d863638c24 Upgrade to archive-view@0.36 2014-08-13 12:43:42 -07:00
Kevin Sawicki 651df12f9b Upgrade to bracket-matcher@0.54 2014-08-13 11:19:55 -07:00
Kevin Sawicki 83706647d1 Prepare 0.122 2014-08-13 10:01:35 -07:00
Cheng Zhao 59fb4a839e Merge pull request #3248 from atom/atom-shell-0.15.6
Uprade to atom-shell@0.15.6
2014-08-13 20:25:03 +08:00
Cheng Zhao 04e23f581a Uprade to atom-shell@0.15.6 2014-08-13 20:13:57 +08:00
Kevin Sawicki 4574a9e35d Upgrade to language-html@0.24 2014-08-12 18:56:08 -07:00
Kevin Sawicki a2eb4d9303 Keep Packages submenu sorted
This ensures packages are in a predictable order regardless of whether
they are bundled or installed to ~/.atom/packages

Closes #3155
2014-08-12 18:16:00 -07:00
Kevin Sawicki c0a845bc56 Don't run ~/.atom/packages specs when in safe mode
Closes #3215
2014-08-12 17:49:33 -07:00
Kevin Sawicki 1ace5a313c Upgrade to dev-live-reload@0.34 2014-08-12 17:18:55 -07:00
Ben Ogle 161eb3c3d2 Upgrade autocomplete and go-to-line to fix preempt 2014-08-12 17:10:37 -07:00
Ben Ogle 6632a1c63d Merge pull request #3244 from atom/bo-stop-propagation
Stop propagation on all commands in the editor
2014-08-12 17:08:22 -07:00
Ben Ogle ce5eff100c Stop propagation on all commands 2014-08-12 16:54:43 -07:00
Kevin Sawicki 1bf9e14f9f Upgrade to language-xml@0.18 2014-08-12 16:44:10 -07:00
Nathan Sobo 94f40f0ed9 Only allow ReactEditorView::beforeRemove to run once 2014-08-12 17:40:53 -06:00
Nathan Sobo 640881a15e Destroy the editor when an EditorComponent is unmounted
Fixes #3222
2014-08-12 17:40:53 -06:00
Kevin Sawicki ee6c4d7b65 Merge pull request #3243 from kaiserfro/remove-unnecessary-getScrollWidth-params
Remove unnecessary params from Editor::getScrollWidth
2014-08-12 16:35:54 -07:00
Jeffrey Oliver a37aeba909 Remove unnecessary params from Editor::getScrollWidth 2014-08-12 16:33:22 -07:00
Kevin Sawicki 2449fda01d Merge pull request #3230 from atom/ks-really-kill-buffered-process-on-windows
Really kill buffered processes on windows
2014-08-12 16:30:30 -07:00
Kevin Sawicki b572594f92 Ignore errors from process object 2014-08-12 16:15:42 -07:00
Kevin Sawicki fbde059748 Ignore errors killing child processes 2014-08-12 16:15:42 -07:00
Kevin Sawicki 6084ef52e7 Ensure pid is positive 2014-08-12 16:15:42 -07:00
Kevin Sawicki a9f4dfc6b7 Split on whitespace when parsing pids 2014-08-12 16:15:42 -07:00
Kevin Sawicki 8032d6dab2 Return undefined from BufferedProcess::kill 2014-08-12 16:15:42 -07:00
Kevin Sawicki 01ec449fce Kill parent process after children on Windows 2014-08-12 16:15:42 -07:00
Kevin Sawicki e79d66497c Remove comment about killing process 2014-08-12 16:15:41 -07:00
Kevin Sawicki a205c6d190 Use wmic to kill child processes 2014-08-12 16:15:41 -07:00
Nathan Sobo 2911b395ee Handle 'focus' events in ReactEditorView and transfer to the component
Fixes #3234
2014-08-12 17:15:19 -06:00
Nathan Sobo 64c25f17df Shim ReactEditorView::mini property 2014-08-12 17:15:19 -06:00
Ben Ogle 9d3082ec95 Upgrade autocomplete to fix #3242 2014-08-12 16:07:05 -07:00
Ben Ogle 034a377c5e Merge pull request #3241 from atom/bo-add-will-insert
Add will-insert-event with cancel() function
2014-08-12 16:03:10 -07:00
Ben Ogle f0fbdc9842 Revert "Sometimes there might not be a selection."
This reverts commit a73e6e5bd0.
2014-08-12 15:54:32 -07:00
Ben Ogle 96804096e9 Fix specs 2014-08-12 15:44:58 -07:00
Ben Ogle e2c41136f3 preventDefault -> cancel() 2014-08-12 15:35:54 -07:00
Ben Ogle 8b20e2e031 Remove duplicate getModel() 2014-08-12 15:32:18 -07:00
Ben Ogle 722d8cb48b Need to return a range when the text is inserted 2014-08-12 15:30:19 -07:00
Ben Ogle a73e6e5bd0 Sometimes there might not be a selection. 2014-08-12 15:30:02 -07:00
Ben Ogle 4cf68ef017 ::getModel() returns the editor 2014-08-12 15:29:47 -07:00
Ben Ogle b037395551 Add will-insert-text and did-insert-text to insertText() 2014-08-12 15:28:26 -07:00
Ben Ogle 7a26a16511 Only focus when the component is mounted 2014-08-12 15:28:13 -07:00
Kevin Sawicki 30fc3d9e66 Merge pull request #3240 from atom/ks-drop-num-pad-support
Remove number pad support
2014-08-12 15:02:15 -07:00
Ben Ogle 7de2ad34aa Remove opaque backgrounds on mini editors
Fixes #3239
2014-08-12 14:53:09 -07:00
Kevin Sawicki 1bba631ab7 Remove num- keybindings 2014-08-12 14:51:53 -07:00
Kevin Sawicki cbf4087a3a Upgrade to atom-keymap 2.0 2014-08-12 14:51:19 -07:00
Kevin Sawicki a3d72f5e6a Upgrade to bracket-matcher@0.53 2014-08-12 14:27:46 -07:00
Kevin Sawicki aeaa2fad06 Upgrade to atom-package-manager@0.89 2014-08-12 13:07:55 -07:00
Kevin Sawicki a219b90eea Upgrade to exception-reporting@0.20 2014-08-12 13:01:03 -07:00
Kevin Sawicki 7086c60e6b Upgrade to git-utils@2.1.4 2014-08-12 12:48:23 -07:00
Kevin Sawicki 0af4c82f36 Upgrade to settings-view@0.139 2014-08-12 12:44:42 -07:00
Kevin Sawicki acf5ab816e Bump grunt-coffeelint for JSON fix 2014-08-12 10:45:39 -07:00
Kevin Sawicki 6aa8c8bab9 Go back to using grunt-coffeelint fork for CI fixes 2014-08-12 10:37:13 -07:00
Kevin Sawicki b5c939dee1 Upgrade to incompatible-packages@0.6 2014-08-12 10:25:18 -07:00
Kevin Sawicki 90d9315d45 Merge pull request #3223 from atom/ks-use-beforeunload
Save state during beforeunload event
2014-08-12 10:22:03 -07:00
Kevin Sawicki 7de2f57088 💄 2014-08-12 09:37:48 -07:00
Kevin Sawicki 1488867063 Remove hiding of body during reload
This appears to no longer be needed on Chrome 36
2014-08-12 08:49:28 -07:00
Kevin Sawicki 59d62d48db Remove views and destroy project during unload 2014-08-12 08:49:28 -07:00
Kevin Sawicki 97c2fc09f0 Only unload editor window when confirmed 2014-08-12 08:49:28 -07:00
Kevin Sawicki 16d2e41309 Use beforeunload instead of unload
unload is asynchronous in Chrome 36 and so saving the state while
reloading may not happen before the state is read on the new render
process.
2014-08-12 08:49:28 -07:00
Lee Dohm 13f66fb2ae Add a step to revert unsaved changes
I took the key part from PR #3183 and added it to the post-confirmation
flow.
2014-08-12 00:37:51 -07:00
Lee Dohm d6a8217e94 Add config option for checkoutHead confirmation
Per the discussion with @kevinsawicki in #3168, I have added a config
option `editor.confirmCheckoutHead` that defaults to `true`. When the
`editor:checkout-head-revision` command is executed, a confirmation
dialog now shows that states which file is to be reverted and asks the
user to "Revert" or "Cancel". If the config option is set to `false`,
the old behavior, simply reverting without prompting, is used.

I also added tests to ensure that the confirmation dialog is displayed
or not in the right configurations.
2014-08-12 00:19:47 -07:00
Lee Dohm 8e649e3008 Add confirmation dialog to checkoutHead
There have been a few reports of files mysteriously going back to the
last version in the tree. My theory is that it is because of people
fat-fingering the Undo command because the default keyboard mapping is
too similar. This will at least prevent most accidental data loss.
2014-08-11 20:58:42 -07:00
Kevin Sawicki 8dffb45fd7 Upgrade to language-c@0.27 2014-08-11 20:34:37 -07:00
Kevin Sawicki c34ce0d2d0 Merge pull request #3218 from dmnd/coffeelint-config-file
Move coffeelint settings to external file
2014-08-11 16:41:42 -07:00
Desmond Brand 61daf1cc36 Use grunt-coffeelint@0.0.13 instead of forked version
Test Plan:

```
$ ./script/grunt coffeelint
Running "coffeelint:src" (coffeelint) task
>> 80 files lint free.

Running "coffeelint:build" (coffeelint) task
>> 23 files lint free.

Running "coffeelint:test" (coffeelint) task
>> 40 files lint free.
Done, without errors.
```
2014-08-11 16:38:24 -07:00
Desmond Brand 1201fb6a5d ignore no_unnecessary_fat_arrows too 2014-08-11 16:32:13 -07:00
Kevin Sawicki 7a5a329393 Upgrade to language-sass@0.15 2014-08-11 15:33:10 -07:00
Kevin Sawicki f447781e01 Allow any bundled theme when in safe mode
Check enabled names against the bundled names and ensure
one bundled UI and one bundled syntax theme are enabled,
defaulting to the dark themes when necessary.
2014-08-11 15:24:49 -07:00
Kevin Sawicki 070d9d0b46 Merge pull request #3186 from maschs/ms-safeModeThemes
Load the default themes in safe mode
2014-08-11 14:51:14 -07:00
Kevin Sawicki 49b4671076 Merge pull request #3208 from XemsDoom/fix-win32-buffprocess
Fixes additional quotes on win32 in BufferedProcess
2014-08-11 14:45:08 -07:00
Luca Moser 28a0e94bb9 Fixes unexecutable commands on win32 in BP
Signed-off-by: Luca Moser <moser.luca@gmail.com>
2014-08-11 20:24:57 +02:00
Kevin Sawicki ab2c5bfc35 Upgrade to bracket-matcher@0.52 2014-08-11 11:21:03 -07:00
Ben Ogle 80c64deb21 Merge pull request #3219 from wernight/patch-1
Update linux.md
2014-08-11 11:06:33 -07:00
Kevin Sawicki 69af432965 Upgrade to base16-tomorrow-dark-theme 2014-08-11 09:41:59 -07:00
Cheng Zhao e788612ef4 Merge pull request #3196 from atom/atom-shell-v0.15.4
Upgrade to atom-shell@0.15.4
2014-08-11 21:24:15 +08:00
Cheng Zhao 62803efde0 Upgrade to atom-shell@0.15.5 2014-08-11 20:54:43 +08:00
Cheng Zhao 01696b4d11 Revert "Make menu bar auto-hide."
This reverts commit 64731bff46.
2014-08-11 20:54:26 +08:00
Werner Beroux 2c2dc61fa0 Update linux.md
Clarify the build steps. The most important is that initialy "Create ..." and "Install ..." could be interpreted as "(User should) create/install ..." while it should mean "(To) create/install ... (do)".
2014-08-11 11:00:47 +02:00
Desmond Brand 66ce001961 Move coffeelint settings to external file
The motivation is for this is to allow `coffeelint` config to be shared by
`script/grunt coffeelint`, global `coffeelint` and inline linting via
`AtomLinter`.

Test Plan:

Made some deliberate lint errors then ran `script/grunt coffeelint` and
verified the output looked the same with and without this change.
2014-08-10 21:41:55 -07:00
Kevin Sawicki 3aa6cc827c Upgrade to markdown-preview@0.99 2014-08-08 11:44:47 -07:00
Maximilian Schüßler c2304e1124 Fix indentation 2014-08-08 19:59:45 +02:00
Kevin Sawicki 07f8f0915c Upgrade to language-sql@0.10 2014-08-08 10:35:58 -07:00
Kevin Sawicki 7725c78c5e Upgrade to language-yaml@0.15 2014-08-08 09:45:28 -07:00
Ivan Žužak 0624720634 Upgrade to markdown-preview@0.97.0 2014-08-08 17:59:57 +02:00
Cheng Zhao 64731bff46 Make menu bar auto-hide. 2014-08-07 21:24:20 +08:00
Cheng Zhao 878c393e8e Upgrade to atom-shell@0.15.4 2014-08-07 20:30:20 +08:00
Nathan Sobo 84064a811c :non_potable_water: Unsubscribe from window resize in EditorComponent
This fixes a major memory leak
2014-08-07 04:59:02 -06:00
Cheng Zhao 3c932d6d91 Upgrade to atom-shell@0.15.3 2014-08-07 00:11:40 +08:00
Ben Ogle a24d1d1af7 Upgrade find-and-replace 2014-08-05 11:31:58 -07:00
Ben Ogle edb5b43d64 Upgrade settings view for #3176 2014-08-05 11:20:38 -07:00
Ben Ogle ac496e1fa4 Upgrade tabs to fix hanging in #1663 2014-08-05 10:54:57 -07:00
Ben Ogle 103f3f8597 Merge pull request #3185 from sryze/patch-1
Add build fix from #2435
2014-08-05 10:17:24 -07:00
Kevin Sawicki 9842baedce Use Atom as FileDescription
This is the text presented when the app is presented in a select list.

Closes #3179
2014-08-05 07:59:02 -07:00
Kevin Sawicki aaa916f78d Upgrade to language-coffee-script@0.29 2014-08-05 07:52:49 -07:00
Maximilian Schüßler b463d9d876 Load the default themes in safe mode 2014-08-05 13:32:16 +02:00
Sergey Zolotarev 7f6a4cccaf Add build fix from #2435 2014-08-05 18:00:25 +07:00
Desmond Brand d5e30e83f6 Don't use project path as fallback icon for item with no path
Stops the project folder icon appearing in places that don't make sense
like settings and new files.

Test Plan:

  * Opened settings and didn't see the project folder icon
  * Closed all tabs and saw the project folder icon
2014-08-04 20:51:37 -07:00
Desmond Brand d16c0e9e41 Implement setDocumentEdited too
As requested by @philipgiuliani

Test Plan:
Opened an existing file and made a modification. The icon fades at the same
time the tab close button changes to a circle. Undo makes the icon opaque
again.
2014-08-04 20:45:24 -07:00
Desmond Brand bd8ac3bb32 path -> proxyIconPath
Test plan:
Crossed fingers
2014-08-04 11:28:29 -07:00
Kevin Sawicki 87edff1e42 Upgrade to language-gfm@0.46 2014-08-04 11:09:42 -07:00
Kevin Sawicki 96f35d3cde Upgrade to language-ruby@0.34 2014-08-04 11:09:41 -07:00
Nathan Sobo 7e45ffa4c3 Center around the cursor in Editor::scrollToCursorPosition by default
Fixes #3131
2014-08-04 11:58:07 -06:00
Kevin Sawicki 6af69b0fc7 Merge pull request #3164 from Bengt/patch-1
Correct Node.js' spelling, link Git and GNOME Keyring
2014-08-04 10:39:12 -07:00
Cheng Zhao 99e02570d1 Upgrade to atom-shell@0.15.2 2014-08-04 22:12:44 +08:00
Desmond Brand e1f4b7415a Add OS X proxy icon to title bar
Fixes #1891.

Test Plan:

  * Opened Atom window in directory, verified directory icon shows up
  * Opened a file and verified icon changed
  * Right clicked icon, verified menu appears
  * Drag file to terminal and it pastes the file path (yay)
  * Opened a new Atom window and opened some files in that to make sure that
    it didn't change the original window

I didn't add any specs for this - advice welcome here. I also haven't tested
on Windows or Linux but it looks like `setRepresentedFilename` is a noop on
those platforms.
2014-08-03 17:14:17 -07:00
Bengt Lüers 823cfcac57 Correct Node.js' spelling, link Git and GNOME Keyring 2014-08-03 16:06:18 +02:00
Nathan Sobo de6ccd8c08 Merge pull request #3146 from atom/ns-latency
Improve cursor movement and typing latency a bit
2014-08-02 09:21:51 -07:00
Ben Ogle 2135d3be83 Update statusbar to add toggle 2014-08-01 10:22:14 -07:00
Nathan Sobo 1c3720c160 Upgrade keybinding-resolver for spec fix 2014-07-31 15:23:58 -06:00
Nathan Sobo 6c72b13adc Upgrade keymap to avoid temp objects in keystrokeForKeyboardEvent 2014-07-31 15:21:37 -06:00
Kevin Sawicki 1404904d24 Upgrade to language-gfm@0.45 2014-07-31 14:15:01 -07:00
Nathan Sobo db243936b4 Update emissary for Emitter::emit optimization 2014-07-31 15:11:25 -06:00
Nathan Sobo 6e72627e9e Stop propagation of keydown/textInput events to prevent React handler
React's global synthetic event handler is somewhat expensive. This
prevents it from being invoked on every keystroke, saving ~1ms.
2014-07-31 15:11:06 -06:00
Kevin Sawicki 3d36ba7ecc Upgrade to scrollbar-style 1.0.2 2014-07-31 13:30:27 -07:00
Kevin Sawicki a7c0d6073f Upgrade to markdown-preview@0.95 2014-07-31 13:24:18 -07:00
Kevin Sawicki f25b468272 Upgrade to apm 0.88 2014-07-31 13:07:44 -07:00
Kevin Sawicki 2d0fb8ee6b Upgrade to incompatible-packages@0.5 2014-07-31 09:19:15 -07:00
Kevin Sawicki d875becc7a Upgrade to snippets@0.51 2014-07-31 09:06:38 -07:00
Kevin Sawicki cb72af63fd Upgrade to language-yaml@0.14 2014-07-31 08:57:09 -07:00
Kevin Sawicki f7187f1d5a Spy on atom.inDevMode() 2014-07-31 08:42:31 -07:00
Kevin Sawicki 700acdc5a2 Upgrade to incompatible-packages@0.4 2014-07-31 08:37:18 -07:00
Kevin Sawicki 18016ae9df 💄 Use unless instead of if not 2014-07-31 08:33:36 -07:00
Kevin Sawicki a30faa5bea Merge pull request #3139 from maschs/ms-incompatibleModulesDev
In devmode do not load incompatible modules from cache
2014-07-31 08:32:58 -07:00
Kevin Sawicki 05a113bb7a Merge pull request #3120 from atom/ks-remove-vendored-dlls
Remove vendored dlls
2014-07-31 08:32:53 -07:00
Kevin Sawicki f5d4ece9cd Remove vendored dlls
These are now provided by atom-shell
2014-07-31 08:20:33 -07:00
Cheng Zhao 3bda37c56c Upgrade to atom-shell@0.15.1 2014-07-31 23:19:50 +08:00
Maximilian Schüßler 62b52cb70a In devmode do not load incompatible from cache 2014-07-31 16:24:29 +02:00
134 arquivos alterados com 10312 adições e 11181 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.87.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
+2 -3
Ver Arquivo
@@ -1,6 +1,6 @@
require '../src/window'
Atom = require '../src/atom'
atom = new Atom()
window.atom = Atom.loadOrCreate('spec')
atom.show() unless atom.getLoadSettings().exitWhenDone
window.atom = atom
@@ -9,5 +9,4 @@ window.atom = atom
atom.openDevTools()
document.title = "Benchmark Suite"
benchmarkSuite = require.resolve('./benchmark-suite')
runSpecSuite(benchmarkSuite, true)
runSpecSuite('../benchmark/benchmark-suite', atom.getLoadSettings().logFile)
+4 -2
Ver Arquivo
@@ -1,7 +1,9 @@
require '../spec/spec-helper'
path = require 'path'
{$, _, Point, fs} = require 'atom'
{$, Point} = require 'atom'
_ = require 'underscore-plus'
fs = require 'fs-plus'
Project = require '../src/project'
TokenizedBuffer = require '../src/tokenized-buffer'
@@ -101,7 +103,7 @@ $.fn.resultOfTrigger = (type) ->
event.result
$.fn.enableKeymap = ->
@on 'keydown', (e) => window.keymap.handleKeyEvent(e)
@on 'keydown', (e) -> window.keymap.handleKeyEvent(e)
$.fn.attachToDom = ->
$('#jasmine-content').append(this)
+9 -9
Ver Arquivo
@@ -53,7 +53,7 @@ describe "editorView.", ->
describe "at-end.", ->
beforeEach ->
editorView.moveCursorToBottom()
editorView.moveToBottom()
benchmark "insert-delete", ->
editorView.insertText('"')
@@ -62,8 +62,8 @@ describe "editorView.", ->
describe "empty-vs-set-innerHTML.", ->
[firstRow, lastRow] = []
beforeEach ->
firstRow = editorView.getFirstVisibleScreenRow()
lastRow = editorView.getLastVisibleScreenRow()
firstRow = editorView.getModel().getFirstVisibleScreenRow()
lastRow = editorView.getModel().getLastVisibleScreenRow()
benchmark "build-gutter-html.", 1000, ->
editorView.gutter.renderLineNumbers(null, firstRow, lastRow)
@@ -97,13 +97,13 @@ describe "editorView.", ->
describe "multiple-lines.", ->
[firstRow, lastRow] = []
beforeEach ->
firstRow = editorView.getFirstVisibleScreenRow()
lastRow = editorView.getLastVisibleScreenRow()
firstRow = editorView.getModel().getFirstVisibleScreenRow()
lastRow = editorView.getModel().getLastVisibleScreenRow()
benchmark "cache-entire-visible-area", 100, ->
for i in [firstRow..lastRow]
line = editorView.lineElementForScreenRow(i)[0]
editorView.positionLeftForLineAndColumn(line, i, Math.max(0, editorView.lineLengthForBufferRow(i)))
editorView.positionLeftForLineAndColumn(line, i, Math.max(0, editorView.getModel().lineTextForBufferRow(i).length))
describe "text-rendering.", ->
beforeEach ->
@@ -178,7 +178,7 @@ describe "editorView.", ->
atom.workspaceView.openSync('huge.js')
benchmark "moving-to-eof.", 1, ->
editorView.moveCursorToBottom()
editorView.moveToBottom()
describe "on-first-line.", ->
benchmark "inserting-newline", 5, ->
@@ -195,11 +195,11 @@ describe "editorView.", ->
endPosition = null
beforeEach ->
editorView.moveCursorToBottom()
editorView.moveToBottom()
endPosition = editorView.getCursorScreenPosition()
benchmark "move-to-beginning-of-word", ->
editorView.moveCursorToBeginningOfWord()
editorView.moveToBeginningOfWord()
editorView.setCursorScreenPosition(endPosition)
benchmark "insert", ->
+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)
+11 -9
Ver Arquivo
@@ -60,7 +60,7 @@ module.exports = (grunt) ->
contentsDir = shellAppDir
appDir = path.join(shellAppDir, 'resources', 'app')
installDir ?= process.env.INSTALL_PREFIX ? '/usr/local'
killCommand ='pkill -9 Atom'
killCommand ='pkill -9 atom'
coffeeConfig =
glob_to_multiple:
@@ -130,7 +130,7 @@ module.exports = (grunt) ->
atom: {appDir, appName, symbolsDir, buildDir, contentsDir, installDir, shellAppDir}
docsOutputDir: 'docs/output/api'
docsOutputDir: 'docs/output'
coffee: coffeeConfig
@@ -144,12 +144,7 @@ module.exports = (grunt) ->
coffeelint:
options:
no_empty_param_list:
level: 'error'
max_line_length:
level: 'ignore'
indentation:
level: 'ignore'
configFile: 'coffeelint.json'
src: [
'dot-atom/**/*.coffee'
'exports/**/*.coffee'
@@ -230,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)
+4 -3
Ver Arquivo
@@ -7,13 +7,14 @@
},
"dependencies": {
"async": "~0.2.9",
"biscotto": ">=2.1.1 <3.0",
"donna": "1.0.1",
"tello": "1.0.3",
"formidable": "~1.0.14",
"fs-plus": "2.x",
"github-releases": "~0.2.0",
"grunt": "~0.4.1",
"grunt-cli": "~0.1.9",
"grunt-coffeelint": "git+https://github.com/atom/grunt-coffeelint.git",
"grunt-coffeelint": "git+https://github.com/atom/grunt-coffeelint.git#cfb99aa99811d52687969532bd5a98011ed95bfe",
"grunt-contrib-coffee": "~0.9.0",
"grunt-contrib-csslint": "~0.1.2",
"grunt-contrib-less": "~0.8.0",
@@ -26,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",
-3
Ver Arquivo
@@ -148,9 +148,6 @@ module.exports = (grunt) ->
grunt.file.copy(sourcePath, path.resolve(appDir, '..', subDirectory, filename))
if process.platform is 'win32'
cp path.join('resources', 'win', 'msvcp100.dll'), path.join(shellAppDir, 'msvcp100.dll')
cp path.join('resources', 'win', 'msvcr100.dll'), path.join(shellAppDir, 'msvcr100.dll')
# Set up chocolatey ignore and gui files
fs.writeFileSync path.join(appDir, 'apm', 'node_modules', 'atom-package-manager', 'bin', 'node.exe.ignore'), ''
fs.writeFileSync path.join(appDir, 'node_modules', 'symbols-view', 'vendor', 'ctags-win32.exe.ignore'), ''
+29 -151
Ver Arquivo
@@ -1,162 +1,40 @@
path = require 'path'
async = require 'async'
fs = require 'fs-plus'
request = require 'request'
_ = require 'underscore-plus'
donna = require 'donna'
tello = require 'tello'
module.exports = (grunt) ->
{rm} = require('./task-helpers')(grunt)
getClassesToInclude = ->
modulesPath = path.resolve(__dirname, '..', '..', 'node_modules')
classes = {}
fs.traverseTreeSync modulesPath, (modulePath) ->
return 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)
cmd = path.join('node_modules', '.bin', 'coffee')
commonArgs = [path.join('build', 'node_modules', '.bin', 'biscotto'), '--']
opts =
stdio: 'inherit'
apiPath = path.join(path.dirname(modulePath), 'api.json')
if fs.isFileSync(apiPath)
_.extend(classes, grunt.file.readJSON(apiPath).classes)
true
classes
sortClasses = (classes) ->
sortedClasses = {}
for className in Object.keys(classes).sort()
sortedClasses[className] = classes[className]
sortedClasses
grunt.registerTask 'build-docs', 'Builds the API docs in src', ->
done = @async()
docsOutputDir = grunt.config.get('docsOutputDir')
downloadIncludes (error, includePaths) ->
if error?
done(error)
else
rm(docsOutputDir)
args = [
commonArgs...
'--title', 'Atom API Documentation'
'-o', docsOutputDir
'-r', 'docs/README.md'
'--stability', '1'
'src/'
includePaths...
]
grunt.util.spawn({cmd, args, opts}, done)
metadata = donna.generateMetadata(['.'])
api = tello.digest(metadata)
_.extend(api.classes, getClassesToInclude())
api.classes = sortClasses(api.classes)
grunt.registerTask 'lint-docs', 'Generate stats about the doc coverage', ->
done = @async()
downloadIncludes (error, includePaths) ->
if error?
done(error)
else
args = [
commonArgs...
'--noOutput'
'src/'
includePaths...
]
grunt.util.spawn({cmd, args, opts}, done)
grunt.registerTask 'missing-docs', 'Generate stats about the doc coverage', ->
done = @async()
downloadIncludes (error, includePaths) ->
if error?
done(error)
else
args = [
commonArgs...
'--noOutput'
'--missing'
'src/'
includePaths...
]
grunt.util.spawn({cmd, args, opts}, done)
grunt.registerTask 'copy-docs', 'Copies over latest API docs to atom-docs', ->
done = @async()
fetchTag = (args..., callback) ->
cmd = 'git'
args = ['describe', '--abbrev=0', '--tags']
grunt.util.spawn {cmd, args}, (error, result) ->
if error?
callback(error)
else
callback(null, String(result).trim())
copyDocs = (tag, callback) ->
cmd = 'cp'
args = ['-r', 'docs/output/', "../atom.io/public/docs/api/#{tag}/"]
fs.exists "../atom.io/public/docs/api/", (exists) ->
if exists
grunt.util.spawn {cmd, args}, (error, result) ->
if error?
callback(error)
else
callback(null, tag)
else
grunt.log.error "../atom.io/public/docs/api/ doesn't exist"
return false
grunt.util.async.waterfall [fetchTag, copyDocs], done
grunt.registerTask 'deploy-docs', 'Publishes latest API docs to atom-docs.githubapp.com', ->
done = @async()
docsRepoArgs = ['--work-tree=../atom-docs/', '--git-dir=../atom-docs/.git/']
fetchTag = (args..., callback) ->
cmd = 'git'
args = ['describe', '--abbrev=0', '--tags']
grunt.util.spawn {cmd, args}, (error, result) ->
if error?
callback(error)
else
callback(null, String(result).trim().split('.')[0..1].join('.'))
stageDocs = (tag, callback) ->
cmd = 'git'
args = [docsRepoArgs..., 'add', "public/#{tag}"]
grunt.util.spawn({cmd, args, opts}, callback)
fetchSha = (args..., callback) ->
cmd = 'git'
args = ['rev-parse', 'HEAD']
grunt.util.spawn {cmd, args}, (error, result) ->
if error?
callback(error)
else
callback(null, String(result).trim())
commitChanges = (sha, callback) ->
cmd = 'git'
args = [docsRepoArgs..., 'commit', "-m Update API docs to #{sha}"]
grunt.util.spawn({cmd, args, opts}, callback)
pushOrigin = (args..., callback) ->
cmd = 'git'
args = [docsRepoArgs..., 'push', 'origin', 'master']
grunt.util.spawn({cmd, args, opts}, callback)
pushHeroku = (args..., callback) ->
cmd = 'git'
args = [docsRepoArgs..., 'push', 'heroku', 'master']
grunt.util.spawn({cmd, args, opts}, callback)
grunt.util.async.waterfall [fetchTag, stageDocs, fetchSha, commitChanges, pushOrigin, pushHeroku], done
downloadFileFromRepo = ({repo, file}, callback) ->
uri = "https://raw.github.com/atom/#{repo}/master/#{file}"
request uri, (error, response, contents) ->
return callback(error) if error?
downloadPath = path.join('docs', 'includes', repo, file)
fs.writeFile downloadPath, contents, (error) ->
callback(error, downloadPath)
downloadIncludes = (callback) ->
includes = [
{repo: 'atom-keymap', file: 'src/keymap-manager.coffee'}
{repo: 'atom-keymap', file: 'src/key-binding.coffee'}
{repo: 'first-mate', file: 'src/grammar.coffee'}
{repo: 'first-mate', file: 'src/grammar-registry.coffee'}
{repo: 'node-pathwatcher', file: 'src/directory.coffee'}
{repo: 'node-pathwatcher', file: 'src/file.coffee'}
{repo: 'space-pen', file: 'src/space-pen.coffee'}
{repo: 'text-buffer', file: 'src/marker.coffee'}
{repo: 'text-buffer', file: 'src/point.coffee'}
{repo: 'text-buffer', file: 'src/range.coffee'}
{repo: 'text-buffer', file: 'src/text-buffer.coffee'}
{repo: 'theorist', file: 'src/model.coffee'}
]
async.map(includes, downloadFileFromRepo, callback)
apiJson = JSON.stringify(api, null, 2)
apiJsonPath = path.join(docsOutputDir, 'api.json')
grunt.file.write(apiJsonPath, apiJson)
+21 -9
Ver Arquivo
@@ -13,8 +13,16 @@ module.exports = (grunt) ->
grunt.file.write(outputPath, filled)
outputPath
getInstalledSize = (buildDir, callback) ->
cmd = 'du'
args = ['-sk', path.join(buildDir, 'Atom')]
spawn {cmd, args}, (error, {stdout}) ->
installedSize = stdout.split(/\s+/)?[0] or '200000' # default to 200MB
callback(null, installedSize)
grunt.registerTask 'mkdeb', 'Create debian package', ->
done = @async()
buildDir = grunt.config.get('atom.buildDir')
if process.arch is 'ia32'
arch = 'i386'
@@ -28,13 +36,17 @@ module.exports = (grunt) ->
maintainer = 'GitHub <atom@github.com>'
installDir = '/usr'
iconName = 'atom'
data = {name, version, description, section, arch, maintainer, installDir, iconName}
getInstalledSize buildDir, (error, installedSize) ->
data = {name, version, description, section, arch, maintainer, installDir, iconName, installedSize}
controlFilePath = fillTemplate(path.join('resources', 'linux', 'debian', 'control'), data)
desktopFilePath = fillTemplate(path.join('resources', 'linux', 'Atom.desktop'), data)
icon = path.join('resources', 'atom.png')
controlFilePath = fillTemplate(path.join('resources', 'linux', 'debian', 'control'), data)
desktopFilePath = fillTemplate(path.join('resources', 'linux', 'Atom.desktop'), data)
icon = path.join('resources', 'atom.png')
buildDir = grunt.config.get('atom.buildDir')
cmd = path.join('script', 'mkdeb')
args = [version, arch, controlFilePath, desktopFilePath, icon, buildDir]
spawn({cmd, args}, done)
cmd = path.join('script', 'mkdeb')
args = [version, arch, controlFilePath, desktopFilePath, icon, buildDir]
spawn {cmd, args}, (error) ->
if error?
done(error)
else
grunt.log.ok "Created #{buildDir}/atom-#{version}-#{arch}.deb"
done()
+33 -13
Ver Arquivo
@@ -17,6 +17,7 @@ defaultHeaders =
module.exports = (gruntObject) ->
grunt = gruntObject
{cp} = require('./task-helpers')(grunt)
grunt.registerTask 'publish-build', 'Publish the built app', ->
return if process.env.JANKY_SHA1 and process.env.JANKY_BRANCH isnt 'master'
@@ -24,8 +25,10 @@ module.exports = (gruntObject) ->
tasks.unshift('build-docs', 'prepare-docs') if process.platform is 'darwin'
grunt.task.run(tasks)
grunt.registerTask 'prepare-docs', 'Move the build docs to the build dir', ->
fs.copySync(grunt.config.get('docsOutputDir'), path.join(grunt.config.get('atom.buildDir'), 'atom-docs'))
grunt.registerTask 'prepare-docs', 'Move api.json to atom-api.json', ->
docsOutputDir = grunt.config.get('docsOutputDir')
buildDir = grunt.config.get('atom.buildDir')
cp path.join(docsOutputDir, 'api.json'), path.join(buildDir, 'atom-api.json')
grunt.registerTask 'upload-assets', 'Upload the assets to a GitHub release', ->
done = @async()
@@ -42,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-docs.zip', sourcePath: 'atom-docs'}
]
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)
@@ -70,7 +90,7 @@ zipAssets = (buildDir, assets, callback) ->
callback(error)
tasks = []
for {assetName, sourcePath} in assets
for {assetName, sourcePath} in assets when path.extname(assetName) is '.zip'
fs.removeSync(path.join(buildDir, assetName))
tasks.push(zip.bind(this, buildDir, sourcePath, assetName))
async.parallel(tasks, callback)
+2 -2
Ver Arquivo
@@ -45,8 +45,8 @@ module.exports = (grunt) ->
strings =
CompanyName: 'GitHub, Inc.'
FileDescription: 'The hackable editor'
LegalCopyright: 'Copyright (C) 2013 GitHub, Inc. All rights reserved'
FileDescription: 'Atom'
LegalCopyright: 'Copyright (C) 2014 GitHub, Inc. All rights reserved'
ProductName: 'Atom'
ProductVersion: version
+19 -16
Ver Arquivo
@@ -2,7 +2,6 @@ fs = require 'fs'
path = require 'path'
_ = require 'underscore-plus'
async = require 'async'
module.exports = (grunt) ->
@@ -10,18 +9,27 @@ module.exports = (grunt) ->
packageSpecQueue = null
getAppPath = ->
contentsDir = grunt.config.get('atom.contentsDir')
switch process.platform
when 'darwin'
path.join(contentsDir, 'MacOS', 'Atom')
when 'linux'
path.join(contentsDir, 'atom')
when 'win32'
path.join(contentsDir, 'atom.exe')
runPackageSpecs = (callback) ->
failedPackages = []
rootDir = grunt.config.get('atom.shellAppDir')
contentsDir = grunt.config.get('atom.contentsDir')
resourcePath = process.cwd()
if process.platform is 'darwin'
appPath = path.join(contentsDir, 'MacOS', 'Atom')
else if process.platform is 'win32'
appPath = path.join(contentsDir, 'atom.exe')
appPath = getAppPath()
# Ensure application is executable on Linux
fs.chmodSync(appPath, '755') if process.platform is 'linux'
packageSpecQueue = async.queue (packagePath, callback) ->
if process.platform is 'darwin'
if process.platform in ['darwin', 'linux']
options =
cmd: appPath
args: ['--test', "--resource-path=#{resourcePath}", "--spec-directory=#{path.join(packagePath, 'spec')}"]
@@ -57,15 +65,11 @@ module.exports = (grunt) ->
packageSpecQueue.drain = -> callback(null, failedPackages)
runCoreSpecs = (callback) ->
contentsDir = grunt.config.get('atom.contentsDir')
if process.platform is 'darwin'
appPath = path.join(contentsDir, 'MacOS', 'Atom')
else if process.platform is 'win32'
appPath = path.join(contentsDir, 'atom.exe')
appPath = getAppPath()
resourcePath = process.cwd()
coreSpecsPath = path.resolve('spec')
if process.platform is 'darwin'
if process.platform in ['darwin', 'linux']
options =
cmd: appPath
args: ['--test', "--resource-path=#{resourcePath}", "--spec-directory=#{coreSpecsPath}"]
@@ -90,7 +94,7 @@ module.exports = (grunt) ->
# TODO: This should really be parallel on both platforms, however our
# fixtures step on each others toes currently.
if process.platform is 'darwin'
if process.platform in ['darwin', 'linux']
method = async.parallel
else if process.platform is 'win32'
method = async.series
@@ -105,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)
+14
Ver Arquivo
@@ -0,0 +1,14 @@
{
"max_line_length": {
"level": "ignore"
},
"no_empty_param_list": {
"level": "error"
},
"arrow_spacing": {
"level": "error"
},
"no_interpolation_in_single_quotes": {
"level": "error"
}
}
+1 -1
Ver Arquivo
@@ -56,7 +56,7 @@ character of the current line:
class EditorView
listenForEvents: ->
@command 'editor:move-to-first-character-of-line', =>
@editor.moveCursorToFirstCharacterOfLine()
@editor.moveToFirstCharacterOfLine()
```
The `::command` method is basically an enhanced version of jQuery's `::on`
-112
Ver Arquivo
@@ -1,112 +0,0 @@
# API Guidelines
__Note__: These are not all in practice yet. We are still sorting this out, and plan to move the entire API this way.
## General Guidelines
We should strive to have only one way to do something, and make it clear what that way is.
__Bad__
* Several ways to get the `Editor` model from the view.
* `EditorView.editor`
* `EditorView.getModel()`
* `EditorView.getEditor()`
* Delegated methods on the views when there is a model counterpart
* `Editor.toggleSoftTabs()`
* `EditorView.toggleSoftTabs()`
__Good__
* One way to get the `Editor` model from the view
* `EditorView.getModel()`
* Use the method on the model
* `Editor.toggleSoftTabs()`
* One clear way to subscribe to events
* `subscription = @subscribe thing, 'event', -> ...`
* One clear way to unsubscribe to events
* `subscription.off()` only; not `thing.off 'event', -> ...`
## Essential vs Extended
There are two groups of classes / methods. We break them up to facilitate a gentle introduction into the API and help authors build a knowledge foundation more quickly.
### Essential
These are classes, methods, and concepts nearly every package author will need to know about. Need to create commands? Subscribe to atom events? Get a reference to all the editors? Highlight a line in the editor? Patterns and methods for these things will be explained in the essential API.
We want to keep the essential API minimal and focused.
### Extended
The extended API contains The Power. Need to move one cursor independent of the others? Want to do some processing on the markers? You can do it with the extended API.
## View / Model
Operations on Views should be limited to DOM manipulation only. A package author should only need access to, say, the `EditorView` when it needs to directly modify the `EditorView`'s DOM.
## Properties
No public properties. Use methods instead.
## Methods
### Naming
We strive to fit the [Objective C][naming] naming conventions for the sake of readability.
* Be descriptive, always write out the whole word. `selection` not `sel`, `cursor` not `cur`.
* Describe the arguments names in the method name eg. `decorationsForMarker(marker)`, `objectAtIndex(index)`
* Use `get` prefix only when there are no arguments `getCursors()`, `getLastCursor()`, `cursorForMarker(marker)`
* Prefix bool methods with `is` eg. `isDefault()`
Array accessor methods would be written as follows
```coffee
getObjects()
addObject(object)
removeObject(object)
removeObjectAtIndex(index)
objectAtIndex(index)
objectsForThing(thing)
objectForThing(thing)
```
## Events
There will be no `off()` method on objects. `on()` will return a subscription object which contains the `off()` method.
* Events should be emitted with one event object as an argument, rather than a bunch of arguments.
* If an event is cancelable, it will provide a `cancel` function in the event object.
### Naming
Past tense. ???
## Documentation
Comment doc strings on methods, events, etc
* how to doc sections?
* events?
* props?
* callback args?
* option hashes?
### Method organization
* All methods in classes should be grouped into sections by usage pattern.
* Methods within a section should be ordered with the most commonly used methods at the top. `Essential` methods always go above `Extended` methods.
* Sections should be ordered in the class with the most commonly used sections at the top.
A section:
```coffee
###
Section: Reading Text
###
# Essential: Returns a {String} representing the entire contents of the editor.
getText: -> @buffer.getText()
```
[naming]:https://developer.apple.com/library/mac/documentation/Cocoa/Conceptual/CodingGuidelines/Articles/NamingMethods.html
+62 -20
Ver Arquivo
@@ -6,23 +6,26 @@ Ubuntu LTS 12.04 64-bit is the recommended platform.
* OS with 64-bit or 32-bit architecture
* C++ toolchain
* git
* [node.js](http://nodejs.org/download/) v0.10.x
* [npm](http://www.npmjs.org/) v1.4.x (bundled with node.js)
* [Git](http://git-scm.com/)
* [Node.js](http://nodejs.org/download/) v0.10.x
* [npm](http://www.npmjs.org/) v1.4.x (bundled with Node.js)
* `npm -v` to check the version.
* `npm config set python /usr/bin/python2 -g` to ensure that gyp uses python2.
* You might need to run this command as `sudo`, depending on how you have set up [npm](https://github.com/joyent/node/wiki/Installing-Node.js-via-package-manager#ubuntu-mint-elementary-os).
* libgnome-keyring-dev
* development headers for [GNOME Keyring](https://wiki.gnome.org/Projects/GnomeKeyring)
### Ubuntu / Debian
* `sudo apt-get install build-essential git libgnome-keyring-dev`
* Instructions for [node.js](https://github.com/joyent/node/wiki/Installing-Node.js-via-package-manager#ubuntu-mint-elementary-os).
* Instructions for [Node.js](https://github.com/joyent/node/wiki/Installing-Node.js-via-package-manager#ubuntu-mint-elementary-os).
### Fedora
* `sudo yum --assumeyes install make gcc gcc-c++ glibc-devel git-core libgnome-keyring-devel`
* Instructions for [node.js](https://github.com/joyent/node/wiki/Installing-Node.js-via-package-manager#fedora).
* Instructions for [Node.js](https://github.com/joyent/node/wiki/Installing-Node.js-via-package-manager#fedora).
### Arch
* `sudo pacman -S base-devel git nodejs libgnome-keyring`
* `export PYTHON=/usr/bin/python2` before building Atom.
@@ -30,26 +33,56 @@ Ubuntu LTS 12.04 64-bit is the recommended platform.
If you have problems with permissions don't forget to prefix with `sudo`
Create the atom application at `$TMPDIR/atom-build/Atom`:
1. Clone the Atom repository:
```sh
git clone https://github.com/atom/atom
cd atom
```
2. Checkout the latest Atom release:
```sh
git fetch
git checkout $(git describe --tags `git rev-list --tags --max-count=1`)
```
3. Build Atom:
```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
### Custom install directory
```sh
script/build
sudo script/grunt install --install-dir /install/atom/here
```
Install the `atom` and `apm` commands to `/usr/local/bin`:
### Custom build directory
```sh
sudo script/grunt install
script/build --build-dir /build/atom/here
```
Generate a `.deb` package at `$TMPDIR/atom-build`: (*optional*)
```sh
script/grunt mkdeb
```
Use the newly installed atom by restarting any running atom instances.
## Troubleshooting
### Exception: "TypeError: Unable to watch path"
@@ -70,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.
@@ -78,10 +111,19 @@ See also https://github.com/atom/atom/issues/2082.
### /usr/bin/env: node: No such file or directory
If you get this notice when attempting to `script/build`, you either do not
have nodejs installed, or node isn't identified as nodejs on your machine.
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.
+13
Ver Arquivo
@@ -66,6 +66,19 @@ If none of this works, do install Github for Windows and use its Git shell. Make
* https://github.com/TooTallNate/node-gyp/issues/297
* https://code.google.com/p/gyp/issues/detail?id=393
* `script/build` stops at installing runas with 'Failed at the runas@0.5.4 install script.'
See the next item.
* `error MSB8020: The build tools for Visual Studio 2010 (Platform Toolset = 'v100') cannot be found.`
* If you're building atom with Visual Studio 2013 try executing the following
command in your Git shell and then re-run `script/build`:
```
$env:GYP_MSVS_VERSION=2013
```
* Other `node-gyp` errors on first build attempt, even though the right node and python versions are installed.
* Do try the build command one more time, as experience shows it often works on second try in many of these cases.
+3 -3
Ver Arquivo
@@ -53,7 +53,7 @@ module.exports =
convert: ->
# This assumes the active pane item is an editor
editor = atom.workspace.activePaneItem
editor = atom.workspace.getActivePaneItem()
editor.insertText('Hello, World!')
```
@@ -131,8 +131,8 @@ inserting 'Hello, World!' convert the selected text to ASCII art.
```coffeescript
convert: ->
# This assumes the active pane item is an editor
editor = atom.workspace.activePaneItem
selection = editor.getSelection()
editor = atom.workspace.getActivePaneItem()
selection = editor.getLastSelection()
figlet = require 'figlet'
figlet selection.getText(), {font: "Larry 3D 2"}, (error, asciiArt) ->
+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
+7 -5
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
@@ -15,10 +20,7 @@ unless process.env.ATOM_SHELL_INTERNAL_RUN_AS_NODE
module.exports.$ = $
module.exports.$$ = $$
module.exports.$$$ = $$$
if atom.config.get('core.useReactMiniEditors')
module.exports.EditorView = require '../src/react-editor-view'
else
module.exports.EditorView = require '../src/editor-view'
module.exports.EditorView = require '../src/editor-view'
module.exports.ScrollView = require '../src/scroll-view'
module.exports.SelectListView = require '../src/select-list-view'
module.exports.Task = require '../src/task'
-2
Ver Arquivo
@@ -12,7 +12,6 @@
# Sublime Parity
'tab': 'editor:indent'
'enter': 'editor:newline'
'num-enter': 'editor:newline'
'shift-tab': 'editor:outdent-selected-rows'
'ctrl-K': 'editor:delete-line'
@@ -27,7 +26,6 @@
'tab': 'core:focus-next'
'shift-tab': 'core:focus-previous'
'enter': 'native!'
'num-enter': 'native!'
'backspace': 'native!'
'shift-backspace': 'native!'
'delete': 'native!'
+3 -2
Ver Arquivo
@@ -21,7 +21,6 @@
'cmd-O': 'application:open-dev'
'cmd-alt-ctrl-s': 'application:run-all-specs'
'enter': 'core:confirm'
'num-enter': 'core:confirm'
'escape': 'core:cancel'
'up': 'core:move-up'
'down': 'core:move-down'
@@ -120,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'
@@ -144,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'
+3 -2
Ver Arquivo
@@ -1,7 +1,6 @@
'body':
# Atom Specific
'enter': 'core:confirm'
'num-enter': 'core:confirm'
'escape': 'core:cancel'
'up': 'core:move-up'
'down': 'core:move-down'
@@ -11,10 +10,12 @@
'ctrl-shift-i': 'window:toggle-dev-tools'
'ctrl-alt-p': 'window:run-package-specs'
'ctrl-alt-s': 'application:run-all-specs'
'ctrl-shift-o': 'application:open-dev'
'ctrl-alt-o': 'application:open-dev'
'ctrl-shift-o': 'application:open-folder'
'F11': 'window:toggle-full-screen'
# Sublime Parity
'ctrl-,': 'application:show-settings'
'ctrl-N': 'application:new-window'
'ctrl-W': 'window:close'
'ctrl-o': 'application:open-file'
+1 -2
Ver Arquivo
@@ -5,7 +5,6 @@
# Atom Specific
'enter': 'core:confirm'
'num-enter': 'core:confirm'
'escape': 'core:cancel'
'up': 'core:move-up'
'down': 'core:move-down'
@@ -26,8 +25,8 @@
'ctrl-n': 'application:new-file'
'ctrl-s': 'core:save'
'ctrl-S': 'core:save-as'
'ctrl-w': 'core:close'
'ctrl-f4': 'core:close'
'ctrl-w': 'core:close'
'ctrl-z': 'core:undo'
'ctrl-shift-z': 'core:redo'
'ctrl-y': 'core:redo'
+12
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' }
@@ -192,3 +194,13 @@
]
}
]
'context-menu':
'.overlayer':
'Undo': 'core:undo'
'Redo': 'core:redo'
'Cut': 'core:cut'
'Copy': 'core:copy'
'Paste': 'core:paste'
'Delete': 'core:delete'
'Select All': 'core:select-all'
+18 -12
Ver Arquivo
@@ -8,8 +8,6 @@
{ label: 'Open Folder...', command: 'application:open-folder' }
{ label: 'Reopen Last &Item', command: 'pane:reopen-closed-item' }
{ type: 'separator' }
{ label: '&Preferences...', command: 'application:show-settings' }
{ type: 'separator' }
{ label: '&Save', command: 'core:save' }
{ label: 'Save &As...', command: 'core:save-as' }
{ label: 'Save A&ll', command: 'window:save-all' }
@@ -80,6 +78,14 @@
{ label: 'Fold Level 9', command: 'editor:fold-at-indent-level-9' }
]
}
{ type: 'separator' }
{ label: '&Preferences', command: 'application:show-settings' }
{ label: 'Open Your Config', command: 'application:open-your-config' }
{ label: 'Open Your Init Script', command: 'application:open-your-init-script' }
{ label: 'Open Your Keymap', command: 'application:open-your-keymap' }
{ label: 'Open Your Snippets', command: 'application:open-your-snippets' }
{ label: 'Open Your Stylesheet', command: 'application:open-your-stylesheet' }
{ type: 'separator' }
]
}
@@ -133,16 +139,6 @@
submenu: []
}
{
label: '&Window'
submenu: [
{ label: 'Mi&nimize', command: 'application:minimize' }
{ label: 'Ma&ximize', command: 'application:zoom' }
{ type: 'separator' }
{ label: 'Bring &All to Front', command: 'application:bring-all-windows-to-front' }
]
}
{
label: '&Help'
submenu: [
@@ -155,3 +151,13 @@
]
}
]
'context-menu':
'.overlayer':
'Undo': 'core:undo'
'Redo': 'core:redo'
'Cut': 'core:cut'
'Copy': 'core:copy'
'Paste': 'core:paste'
'Delete': 'core:delete'
'Select All': 'core:select-all'
+10 -10
Ver Arquivo
@@ -157,16 +157,6 @@
submenu: []
}
{
label: '&Window'
submenu: [
{ label: 'Mi&nimize', command: 'application:minimize' }
{ label: 'Ma&ximize', command: 'application:zoom' }
{ type: 'separator' }
{ label: 'Bring &All to Front', command: 'application:bring-all-windows-to-front' }
]
}
{
label: '&Help'
submenu: [
@@ -179,3 +169,13 @@
]
}
]
'context-menu':
'.overlayer':
'Undo': 'core:undo'
'Redo': 'core:redo'
'Cut': 'core:cut'
'Copy': 'core:copy'
'Paste': 'core:paste'
'Delete': 'core:delete'
'Select All': 'core:select-all'
+70 -69
Ver Arquivo
@@ -1,7 +1,7 @@
{
"name": "atom",
"productName": "Atom",
"version": "0.121.0",
"version": "0.130.0",
"description": "A hackable text editor for the 21st Century.",
"main": "./src/browser/main.js",
"repository": {
@@ -17,128 +17,129 @@
"url": "http://github.com/atom/atom/raw/master/LICENSE.md"
}
],
"atomShellVersion": "0.15.0",
"atomShellVersion": "0.16.2",
"dependencies": {
"async": "0.2.6",
"atom-keymap": "^1.0.0",
"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.2.1",
"first-mate": "^2.0.1",
"emissary": "^1.3.1",
"event-kit": "0.7.2",
"first-mate": "^2.1.2",
"fs-plus": "^2.2.6",
"fstream": "0.1.24",
"fuzzaldrin": "^1.1",
"git-utils": "^2.1.3",
"grim": "0.11.0",
"fuzzaldrin": "^2.1",
"git-utils": "^2.1.4",
"grim": "0.12.0",
"guid": "0.0.10",
"jasmine-tagged": "^1.1.2",
"less-cache": "0.13.0",
"less-cache": "0.15.0",
"mixto": "^1",
"mkdirp": "0.3.5",
"nslog": "^1.0.1",
"oniguruma": "^3.0.3",
"oniguruma": "^3.0.4",
"optimist": "0.4.0",
"pathwatcher": "^2.0.6",
"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.1",
"scrollbar-style": "^1.0.2",
"season": "^1.0.2",
"semver": "1.1.4",
"serializable": "^1",
"space-pen": "3.2.0",
"space-pen": "3.4.7",
"temp": "0.7.0",
"text-buffer": "^3.0.0",
"theorist": "^1",
"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.33.0",
"atom-dark-ui": "0.35.0",
"atom-light-syntax": "0.20.0",
"atom-light-ui": "0.29.0",
"base16-tomorrow-dark-theme": "0.20.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.35.0",
"autocomplete": "0.29.0",
"autoflow": "0.17.0",
"autosave": "0.14.0",
"background-tips": "0.15.0",
"bookmarks": "0.27.0",
"bracket-matcher": "0.51.0",
"command-palette": "0.24.0",
"deprecation-cop": "0.7.0",
"dev-live-reload": "0.33.0",
"exception-reporting": "0.19.0",
"archive-view": "0.37.0",
"autocomplete": "0.32.0",
"autoflow": "0.18.0",
"autosave": "0.17.0",
"background-tips": "0.16.0",
"bookmarks": "0.28.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.127.0",
"fuzzy-finder": "0.57.0",
"git-diff": "0.37.0",
"go-to-line": "0.23.0",
"grammar-selector": "0.27.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.34.0",
"image-view": "0.36.0",
"incompatible-packages": "0.3.0",
"keybinding-resolver": "0.18.0",
"incompatible-packages": "0.9.0",
"keybinding-resolver": "0.20.0",
"link": "0.25.0",
"markdown-preview": "0.94.0",
"metrics": "0.33.0",
"open-on-github": "0.29.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.137.0",
"snippets": "0.50.0",
"spell-check": "0.40.0",
"status-bar": "0.41.0",
"styleguide": "0.29.0",
"symbols-view": "0.63.0",
"tabs": "0.48.0",
"settings-view": "0.145.0",
"snippets": "0.52.0",
"spell-check": "0.42.0",
"status-bar": "0.45.0",
"styleguide": "0.30.0",
"symbols-view": "0.66.0",
"tabs": "0.52.0",
"timecop": "0.22.0",
"tree-view": "0.112.0",
"tree-view": "0.126.0",
"update-package-dependencies": "0.6.0",
"welcome": "0.17.0",
"welcome": "0.18.0",
"whitespace": "0.25.0",
"wrap-guide": "0.21.0",
"language-c": "0.26.0",
"language-coffee-script": "0.28.0",
"wrap-guide": "0.22.0",
"language-c": "0.28.0",
"language-coffee-script": "0.34.0",
"language-css": "0.17.0",
"language-gfm": "0.44.0",
"language-gfm": "0.50.0",
"language-git": "0.9.0",
"language-go": "0.16.0",
"language-html": "0.22.0",
"language-hyperlink": "0.10.0",
"language-go": "0.17.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.13.0",
"language-make": "0.10.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.18.0",
"language-ruby": "0.33.0",
"language-ruby-on-rails": "0.15.0",
"language-sass": "0.14.0",
"language-python": "0.19.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.9.0",
"language-sql": "0.11.0",
"language-text": "0.6.0",
"language-todo": "0.10.0",
"language-todo": "0.11.0",
"language-toml": "0.12.0",
"language-xml": "0.17.0",
"language-yaml": "0.13.0"
"language-xml": "0.21.0",
"language-yaml": "0.17.0"
},
"private": true,
"scripts": {
+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 -1
Ver Arquivo
@@ -3,6 +3,6 @@ Version: <%= version %>
Section: <%= section %>
Priority: optional
Architecture: <%= arch %>
Installed-Size: `du -ks usr|cut -f 1`
Installed-Size: <%= installedSize %>
Maintainer: <%= maintainer %>
Description: <%= description %>
Arquivo binário não exibido.
Arquivo binário não exibido.
+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
+5 -4
Ver Arquivo
@@ -13,21 +13,22 @@ CONTROL_FILE="$3"
DESKTOP_FILE="$4"
ICON_FILE="$5"
DEB_PATH="$6"
FILE_MODE=755
TARGET_ROOT="`mktemp -d`"
chmod 755 "$TARGET_ROOT"
TARGET="$TARGET_ROOT/atom-$VERSION-$ARCH"
mkdir -p "$TARGET/usr"
mkdir -m $FILE_MODE -p "$TARGET/usr"
env INSTALL_PREFIX="$TARGET/usr" script/grunt install
mkdir -p "$TARGET/DEBIAN"
mkdir -m $FILE_MODE -p "$TARGET/DEBIAN"
cp "$CONTROL_FILE" "$TARGET/DEBIAN/control"
mkdir -p "$TARGET/usr/share/applications"
mkdir -m $FILE_MODE -p "$TARGET/usr/share/applications"
cp "$DESKTOP_FILE" "$TARGET/usr/share/applications"
mkdir -p "$TARGET/usr/share/pixmaps"
mkdir -m $FILE_MODE -p "$TARGET/usr/share/pixmaps"
cp "$ICON_FILE" "$TARGET/usr/share/pixmaps"
dpkg-deb -b "$TARGET"
+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 {
+2 -2
Ver Arquivo
@@ -119,14 +119,14 @@ class AtomReporter extends View
grim.clearDeprecations()
handleEvents: ->
$(document).on "click", ".spec-toggle", ({currentTarget}) =>
$(document).on "click", ".spec-toggle", ({currentTarget}) ->
element = $(currentTarget)
specFailures = element.parent().find('.spec-failures')
specFailures.toggle()
element.toggleClass('folded')
false
$(document).on "click", ".deprecation-toggle", ({currentTarget}) =>
$(document).on "click", ".deprecation-toggle", ({currentTarget}) ->
element = $(currentTarget)
deprecationList = $(document).find('.deprecation-list')
deprecationList.toggle()
+48 -16
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')
@@ -493,13 +520,14 @@ describe "the `atom` global", ->
expect(atom.config.get('core.disabledPackages')).toContain packageName
describe "with themes", ->
reloadedHandler = null
beforeEach ->
waitsForPromise ->
atom.themes.activateThemes()
afterEach ->
atom.themes.deactivateThemes()
atom.config.unobserve('core.themes')
it ".enablePackage() and .disablePackage() enables and disables a theme", ->
packageName = 'theme-with-package-file'
@@ -517,13 +545,17 @@ describe "the `atom` global", ->
expect(atom.config.get('core.themes')).toContain packageName
expect(atom.config.get('core.disabledPackages')).not.toContain packageName
# disabling of theme
reloadedHandler = jasmine.createSpy('reloadedHandler')
reloadedHandler.reset()
atom.themes.onDidReloadAll reloadedHandler
pack = atom.packages.disablePackage(packageName)
waitsFor ->
not (pack in atom.packages.getActivePackages())
reloadedHandler.callCount is 1
runs ->
expect(atom.packages.getActivePackages()).not.toContain pack
expect(atom.config.get('core.themes')).not.toContain packageName
expect(atom.config.get('core.themes')).not.toContain packageName
expect(atom.config.get('core.disabledPackages')).not.toContain packageName
+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'}
]
+12
Ver Arquivo
@@ -23,6 +23,18 @@ describe "Config", ->
retrievedValue.array[1].b = 2.1
expect(atom.config.get('value')).toEqual(array: [1, b: 2, 3])
it "merges defaults into the returned value if both the assigned value and the default value are objects", ->
atom.config.setDefaults("foo", a: 1, b: 2)
atom.config.set("foo", a: 3)
expect(atom.config.get("foo")).toEqual {a: 3, b: 2}
atom.config.set("foo", 7)
expect(atom.config.get("foo")).toBe 7
atom.config.set("bar.baz", a: 3)
atom.config.setDefaults("bar", baz: 7)
expect(atom.config.get("bar.baz")).toEqual {a: 3}
describe ".set(keyPath, value)", ->
it "allows a key path's value to be written", ->
expect(atom.config.set("foo.bar.baz", 42)).toBe 42
+2 -1
Ver Arquivo
@@ -6,7 +6,8 @@ describe "ContextMenuManager", ->
[contextMenu] = []
beforeEach ->
contextMenu = new ContextMenuManager
{resourcePath} = atom.getLoadSettings()
contextMenu = new ContextMenuManager({resourcePath})
describe "adding definitions", ->
it 'loads', ->
+148 -136
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()
@@ -67,48 +67,48 @@ describe "DisplayBuffer", ->
it "uses the preferred line length as the soft wrap column when it is less than the configured soft wrap column", ->
atom.config.set('editor.preferredLineLength', 100)
atom.config.set('editor.softWrapAtPreferredLineLength', true)
expect(displayBuffer.lineForRow(10).text).toBe ' return '
expect(displayBuffer.tokenizedLineForScreenRow(10).text).toBe ' return '
atom.config.set('editor.preferredLineLength', 5)
expect(displayBuffer.lineForRow(10).text).toBe 'funct'
expect(displayBuffer.tokenizedLineForScreenRow(10).text).toBe 'funct'
atom.config.set('editor.softWrapAtPreferredLineLength', false)
expect(displayBuffer.lineForRow(10).text).toBe ' return '
expect(displayBuffer.tokenizedLineForScreenRow(10).text).toBe ' return '
describe "when the line is shorter than the max line length", ->
it "renders the line unchanged", ->
expect(displayBuffer.lineForRow(0).text).toBe buffer.lineForRow(0)
expect(displayBuffer.tokenizedLineForScreenRow(0).text).toBe buffer.lineForRow(0)
describe "when the line is empty", ->
it "renders the empty line", ->
expect(displayBuffer.lineForRow(13).text).toBe ''
expect(displayBuffer.tokenizedLineForScreenRow(13).text).toBe ''
describe "when there is a non-whitespace character at the max length boundary", ->
describe "when there is whitespace before the boundary", ->
it "wraps the line at the end of the first whitespace preceding the boundary", ->
expect(displayBuffer.lineForRow(10).text).toBe ' return '
expect(displayBuffer.lineForRow(11).text).toBe 'sort(left).concat(pivot).concat(sort(right));'
expect(displayBuffer.tokenizedLineForScreenRow(10).text).toBe ' return '
expect(displayBuffer.tokenizedLineForScreenRow(11).text).toBe 'sort(left).concat(pivot).concat(sort(right));'
describe "when there is no whitespace before the boundary", ->
it "wraps the line exactly at the boundary since there's no more graceful place to wrap it", ->
buffer.setTextInRange([[0, 0], [1, 0]], 'abcdefghijklmnopqrstuvwxyz\n')
displayBuffer.setEditorWidthInChars(10)
expect(displayBuffer.lineForRow(0).text).toBe 'abcdefghij'
expect(displayBuffer.lineForRow(1).text).toBe 'klmnopqrst'
expect(displayBuffer.lineForRow(2).text).toBe 'uvwxyz'
expect(displayBuffer.tokenizedLineForScreenRow(0).text).toBe 'abcdefghij'
expect(displayBuffer.tokenizedLineForScreenRow(1).text).toBe 'klmnopqrst'
expect(displayBuffer.tokenizedLineForScreenRow(2).text).toBe 'uvwxyz'
describe "when there is a whitespace character at the max length boundary", ->
it "wraps the line at the first non-whitespace character following the boundary", ->
expect(displayBuffer.lineForRow(3).text).toBe ' var pivot = items.shift(), current, left = [], '
expect(displayBuffer.lineForRow(4).text).toBe 'right = [];'
expect(displayBuffer.tokenizedLineForScreenRow(3).text).toBe ' var pivot = items.shift(), current, left = [], '
expect(displayBuffer.tokenizedLineForScreenRow(4).text).toBe 'right = [];'
describe "when there are hard tabs", ->
beforeEach ->
buffer.setText(buffer.getText().replace(new RegExp(' ', 'g'), '\t'))
it "correctly tokenizes the hard tabs", ->
expect(displayBuffer.lineForRow(3).tokens[0].isHardTab).toBeTruthy()
expect(displayBuffer.lineForRow(3).tokens[1].isHardTab).toBeTruthy()
expect(displayBuffer.tokenizedLineForScreenRow(3).tokens[0].isHardTab).toBeTruthy()
expect(displayBuffer.tokenizedLineForScreenRow(3).tokens[1].isHardTab).toBeTruthy()
describe "when the buffer changes", ->
describe "when buffer lines are updated", ->
@@ -121,57 +121,57 @@ describe "DisplayBuffer", ->
describe "when the update makes a soft-wrapped line shorter than the max line length", ->
it "rewraps the line and emits a change event", ->
buffer.delete([[6, 24], [6, 42]])
expect(displayBuffer.lineForRow(7).text).toBe ' current < pivot ? : right.push(current);'
expect(displayBuffer.lineForRow(8).text).toBe ' }'
expect(displayBuffer.tokenizedLineForScreenRow(7).text).toBe ' current < pivot ? : right.push(current);'
expect(displayBuffer.tokenizedLineForScreenRow(8).text).toBe ' }'
expect(changeHandler).toHaveBeenCalled()
[[event]]= changeHandler.argsForCall
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.lineForRow(7).text).toBe ' current < pivot ? '
expect(displayBuffer.lineForRow(8).text).toBe 'left1234567890.push(current) : '
expect(displayBuffer.lineForRow(9).text).toBe 'right.push(current);'
expect(displayBuffer.lineForRow(10).text).toBe ' }'
expect(displayBuffer.tokenizedLineForScreenRow(7).text).toBe ' current < pivot ? '
expect(displayBuffer.tokenizedLineForScreenRow(8).text).toBe 'left1234567890.push(current) : '
expect(displayBuffer.tokenizedLineForScreenRow(9).text).toBe 'right.push(current);'
expect(displayBuffer.tokenizedLineForScreenRow(10).text).toBe ' }'
expect(changeHandler).toHaveBeenCalledWith(start: 7, end: 8, screenDelta: 1, bufferDelta: 0)
describe "when buffer lines are inserted", ->
it "inserts / updates wrapped lines and emits a change event", ->
buffer.insert([6, 21], '1234567890 abcdefghij 1234567890\nabcdefghij')
expect(displayBuffer.lineForRow(7).text).toBe ' current < pivot1234567890 abcdefghij '
expect(displayBuffer.lineForRow(8).text).toBe '1234567890'
expect(displayBuffer.lineForRow(9).text).toBe 'abcdefghij ? left.push(current) : '
expect(displayBuffer.lineForRow(10).text).toBe 'right.push(current);'
expect(displayBuffer.tokenizedLineForScreenRow(7).text).toBe ' current < pivot1234567890 abcdefghij '
expect(displayBuffer.tokenizedLineForScreenRow(8).text).toBe '1234567890'
expect(displayBuffer.tokenizedLineForScreenRow(9).text).toBe 'abcdefghij ? left.push(current) : '
expect(displayBuffer.tokenizedLineForScreenRow(10).text).toBe 'right.push(current);'
expect(changeHandler).toHaveBeenCalledWith(start: 7, end: 8, screenDelta: 2, bufferDelta: 1)
describe "when buffer lines are removed", ->
it "removes lines and emits a change event", ->
buffer.setTextInRange([[3, 21], [7, 5]], ';')
expect(displayBuffer.lineForRow(3).text).toBe ' var pivot = items;'
expect(displayBuffer.lineForRow(4).text).toBe ' return '
expect(displayBuffer.lineForRow(5).text).toBe 'sort(left).concat(pivot).concat(sort(right));'
expect(displayBuffer.lineForRow(6).text).toBe ' };'
expect(displayBuffer.tokenizedLineForScreenRow(3).text).toBe ' var pivot = items;'
expect(displayBuffer.tokenizedLineForScreenRow(4).text).toBe ' return '
expect(displayBuffer.tokenizedLineForScreenRow(5).text).toBe 'sort(left).concat(pivot).concat(sort(right));'
expect(displayBuffer.tokenizedLineForScreenRow(6).text).toBe ' };'
expect(changeHandler).toHaveBeenCalledWith(start: 3, end: 9, screenDelta: -6, bufferDelta: -4)
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')
buffer.delete([[0, Infinity], [1, 0]])
buffer.insert([0, Infinity], '\n')
expect(displayBuffer.lineForRow(0).text).toBe "the quick brown fox jumps over "
expect(displayBuffer.lineForRow(1).text).toBe "the lazy dog."
expect(displayBuffer.lineForRow(2).text).toBe ""
expect(displayBuffer.tokenizedLineForScreenRow(0).text).toBe "the quick brown fox jumps over "
expect(displayBuffer.tokenizedLineForScreenRow(1).text).toBe "the lazy dog."
expect(displayBuffer.tokenizedLineForScreenRow(2).text).toBe ""
describe "position translation", ->
it "translates positions accounting for wrapped lines", ->
@@ -204,9 +204,9 @@ describe "DisplayBuffer", ->
describe ".setEditorWidthInChars(length)", ->
it "changes the length at which lines are wrapped and emits a change event for all screen lines", ->
displayBuffer.setEditorWidthInChars(40)
expect(tokensText displayBuffer.lineForRow(4).tokens).toBe 'left = [], right = [];'
expect(tokensText displayBuffer.lineForRow(5).tokens).toBe ' while(items.length > 0) {'
expect(tokensText displayBuffer.lineForRow(12).tokens).toBe 'sort(left).concat(pivot).concat(sort(rig'
expect(tokensText displayBuffer.tokenizedLineForScreenRow(4).tokens).toBe 'left = [], right = [];'
expect(tokensText displayBuffer.tokenizedLineForScreenRow(5).tokens).toBe ' while(items.length > 0) {'
expect(tokensText displayBuffer.tokenizedLineForScreenRow(12).tokens).toBe 'sort(left).concat(pivot).concat(sort(rig'
expect(changeHandler).toHaveBeenCalledWith(start: 0, end: 15, screenDelta: 3, bufferDelta: 0)
it "only allows positive widths to be assigned", ->
@@ -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", ->
@@ -242,7 +242,7 @@ describe "DisplayBuffer", ->
fold = displayBuffer.createFold(4, 7)
expect(fold).toBeDefined()
[line4, line5] = displayBuffer.linesForRows(4, 5)
[line4, line5] = displayBuffer.tokenizedLinesForScreenRows(4, 5)
expect(line4.fold).toBe fold
expect(line4.text).toMatch /^4-+/
expect(line5.text).toBe '8'
@@ -251,7 +251,7 @@ describe "DisplayBuffer", ->
changeHandler.reset()
fold.destroy()
[line4, line5] = displayBuffer.linesForRows(4, 5)
[line4, line5] = displayBuffer.tokenizedLinesForScreenRows(4, 5)
expect(line4.fold).toBeUndefined()
expect(line4.text).toMatch /^4-+/
expect(line5.text).toBe '5'
@@ -262,7 +262,7 @@ describe "DisplayBuffer", ->
it "renders a fold placeholder for the folded line but does not skip any lines", ->
fold = displayBuffer.createFold(4, 4)
[line4, line5] = displayBuffer.linesForRows(4, 5)
[line4, line5] = displayBuffer.tokenizedLinesForScreenRows(4, 5)
expect(line4.fold).toBe fold
expect(line4.text).toMatch /^4-+/
expect(line5.text).toBe '5'
@@ -275,7 +275,7 @@ describe "DisplayBuffer", ->
fold.destroy()
[line4, line5] = displayBuffer.linesForRows(4, 5)
[line4, line5] = displayBuffer.tokenizedLinesForScreenRows(4, 5)
expect(line4.fold).toBeUndefined()
expect(line4.text).toMatch /^4-+/
expect(line5.text).toBe '5'
@@ -287,13 +287,13 @@ describe "DisplayBuffer", ->
innerFold = displayBuffer.createFold(6, 7)
outerFold = displayBuffer.createFold(4, 8)
[line4, line5] = displayBuffer.linesForRows(4, 5)
[line4, line5] = displayBuffer.tokenizedLinesForScreenRows(4, 5)
expect(line4.fold).toBe outerFold
expect(line4.text).toMatch /4-+/
expect(line5.text).toMatch /9-+/
outerFold.destroy()
[line4, line5, line6, line7] = displayBuffer.linesForRows(4, 7)
[line4, line5, line6, line7] = displayBuffer.tokenizedLinesForScreenRows(4, 7)
expect(line4.fold).toBeUndefined()
expect(line4.text).toMatch /^4-+/
expect(line5.text).toBe '5'
@@ -305,7 +305,7 @@ describe "DisplayBuffer", ->
innerFold = displayBuffer.createFold(4, 6)
outerFold = displayBuffer.createFold(4, 8)
[line4, line5] = displayBuffer.linesForRows(4, 5)
[line4, line5] = displayBuffer.tokenizedLinesForScreenRows(4, 5)
expect(line4.fold).toBe outerFold
expect(line4.text).toMatch /4-+/
expect(line5.text).toMatch /9-+/
@@ -326,14 +326,14 @@ describe "DisplayBuffer", ->
innerFold = displayBuffer.createFold(2, 5)
expect(changeHandler).not.toHaveBeenCalled()
[line0, line1] = displayBuffer.linesForRows(0, 1)
[line0, line1] = displayBuffer.tokenizedLinesForScreenRows(0, 1)
expect(line0.fold).toBe outerFold
expect(line1.fold).toBeUndefined()
changeHandler.reset()
innerFold.destroy()
expect(changeHandler).not.toHaveBeenCalled()
[line0, line1] = displayBuffer.linesForRows(0, 1)
[line0, line1] = displayBuffer.tokenizedLinesForScreenRows(0, 1)
expect(line0.fold).toBe outerFold
expect(line1.fold).toBeUndefined()
@@ -342,8 +342,8 @@ describe "DisplayBuffer", ->
fold2 = displayBuffer.createFold(4, 9)
fold1 = displayBuffer.createFold(0, 4)
expect(displayBuffer.lineForRow(0).text).toMatch /^0/
expect(displayBuffer.lineForRow(1).text).toMatch /^10/
expect(displayBuffer.tokenizedLineForScreenRow(0).text).toMatch /^0/
expect(displayBuffer.tokenizedLineForScreenRow(1).text).toMatch /^10/
describe "when there is another display buffer pointing to the same buffer", ->
it "does not create folds in the other display buffer", ->
@@ -363,19 +363,19 @@ describe "DisplayBuffer", ->
buffer.setTextInRange([[1, 0], [5, 1]], 'party!')
it "removes the fold and replaces the selection with the new text", ->
expect(displayBuffer.lineForRow(0).text).toBe "0"
expect(displayBuffer.lineForRow(1).text).toBe "party!"
expect(displayBuffer.lineForRow(2).fold).toBe fold2
expect(displayBuffer.lineForRow(3).text).toMatch /^9-+/
expect(displayBuffer.tokenizedLineForScreenRow(0).text).toBe "0"
expect(displayBuffer.tokenizedLineForScreenRow(1).text).toBe "party!"
expect(displayBuffer.tokenizedLineForScreenRow(2).fold).toBe fold2
expect(displayBuffer.tokenizedLineForScreenRow(3).text).toMatch /^9-+/
expect(changeHandler).toHaveBeenCalledWith(start: 1, end: 3, screenDelta: -2, bufferDelta: -4)
describe "when the changes is subsequently undone", ->
xit "restores destroyed folds", ->
buffer.undo()
expect(displayBuffer.lineForRow(2).text).toBe '2'
expect(displayBuffer.lineForRow(2).fold).toBe fold1
expect(displayBuffer.lineForRow(3).text).toBe '5'
expect(displayBuffer.tokenizedLineForScreenRow(2).text).toBe '2'
expect(displayBuffer.tokenizedLineForScreenRow(2).fold).toBe fold1
expect(displayBuffer.tokenizedLineForScreenRow(3).text).toBe '5'
describe "when the old range surrounds two nested folds", ->
it "removes both folds and replaces the selection with the new text", ->
@@ -384,9 +384,9 @@ describe "DisplayBuffer", ->
buffer.setTextInRange([[1, 0], [10, 0]], 'goodbye')
expect(displayBuffer.lineForRow(0).text).toBe "0"
expect(displayBuffer.lineForRow(1).text).toBe "goodbye10"
expect(displayBuffer.lineForRow(2).text).toBe "11"
expect(displayBuffer.tokenizedLineForScreenRow(0).text).toBe "0"
expect(displayBuffer.tokenizedLineForScreenRow(1).text).toBe "goodbye10"
expect(displayBuffer.tokenizedLineForScreenRow(2).text).toBe "11"
expect(changeHandler).toHaveBeenCalledWith(start: 1, end: 3, screenDelta: -2, bufferDelta: -9)
@@ -403,42 +403,42 @@ describe "DisplayBuffer", ->
it "updates the buffer and re-positions subsequent folds", ->
buffer.setTextInRange([[0, 0], [1, 1]], 'abc')
expect(displayBuffer.lineForRow(0).text).toBe "abc"
expect(displayBuffer.lineForRow(1).fold).toBe fold1
expect(displayBuffer.lineForRow(2).text).toBe "5"
expect(displayBuffer.lineForRow(3).fold).toBe fold2
expect(displayBuffer.lineForRow(4).text).toMatch /^9-+/
expect(displayBuffer.tokenizedLineForScreenRow(0).text).toBe "abc"
expect(displayBuffer.tokenizedLineForScreenRow(1).fold).toBe fold1
expect(displayBuffer.tokenizedLineForScreenRow(2).text).toBe "5"
expect(displayBuffer.tokenizedLineForScreenRow(3).fold).toBe fold2
expect(displayBuffer.tokenizedLineForScreenRow(4).text).toMatch /^9-+/
expect(changeHandler).toHaveBeenCalledWith(start: 0, end: 1, screenDelta: -1, bufferDelta: -1)
changeHandler.reset()
fold1.destroy()
expect(displayBuffer.lineForRow(0).text).toBe "abc"
expect(displayBuffer.lineForRow(1).text).toBe "2"
expect(displayBuffer.lineForRow(3).text).toMatch /^4-+/
expect(displayBuffer.lineForRow(4).text).toBe "5"
expect(displayBuffer.lineForRow(5).fold).toBe fold2
expect(displayBuffer.lineForRow(6).text).toMatch /^9-+/
expect(displayBuffer.tokenizedLineForScreenRow(0).text).toBe "abc"
expect(displayBuffer.tokenizedLineForScreenRow(1).text).toBe "2"
expect(displayBuffer.tokenizedLineForScreenRow(3).text).toMatch /^4-+/
expect(displayBuffer.tokenizedLineForScreenRow(4).text).toBe "5"
expect(displayBuffer.tokenizedLineForScreenRow(5).fold).toBe fold2
expect(displayBuffer.tokenizedLineForScreenRow(6).text).toMatch /^9-+/
expect(changeHandler).toHaveBeenCalledWith(start: 1, end: 1, screenDelta: 2, bufferDelta: 0)
describe "when the old range straddles the beginning of a fold", ->
it "destroys the fold", ->
buffer.setTextInRange([[1, 1], [3, 0]], "a\nb\nc\nd\n")
expect(displayBuffer.lineForRow(1).text).toBe '1a'
expect(displayBuffer.lineForRow(2).text).toBe 'b'
expect(displayBuffer.lineForRow(2).fold).toBeUndefined()
expect(displayBuffer.lineForRow(3).text).toBe 'c'
expect(displayBuffer.tokenizedLineForScreenRow(1).text).toBe '1a'
expect(displayBuffer.tokenizedLineForScreenRow(2).text).toBe 'b'
expect(displayBuffer.tokenizedLineForScreenRow(2).fold).toBeUndefined()
expect(displayBuffer.tokenizedLineForScreenRow(3).text).toBe 'c'
describe "when the old range follows a fold", ->
it "re-positions the screen ranges for the change event based on the preceding fold", ->
buffer.setTextInRange([[10, 0], [11, 0]], 'abc')
expect(displayBuffer.lineForRow(1).text).toBe "1"
expect(displayBuffer.lineForRow(2).fold).toBe fold1
expect(displayBuffer.lineForRow(3).text).toBe "5"
expect(displayBuffer.lineForRow(4).fold).toBe fold2
expect(displayBuffer.lineForRow(5).text).toMatch /^9-+/
expect(displayBuffer.tokenizedLineForScreenRow(1).text).toBe "1"
expect(displayBuffer.tokenizedLineForScreenRow(2).fold).toBe fold1
expect(displayBuffer.tokenizedLineForScreenRow(3).text).toBe "5"
expect(displayBuffer.tokenizedLineForScreenRow(4).fold).toBe fold2
expect(displayBuffer.tokenizedLineForScreenRow(5).text).toMatch /^9-+/
expect(changeHandler).toHaveBeenCalledWith(start: 6, end: 7, screenDelta: -1, bufferDelta: -1)
@@ -449,12 +449,12 @@ describe "DisplayBuffer", ->
expect(fold1.getStartRow()).toBe 2
expect(fold1.getEndRow()).toBe 5
expect(displayBuffer.lineForRow(1).text).toBe "1"
expect(displayBuffer.lineForRow(2).text).toBe "2"
expect(displayBuffer.lineForRow(2).fold).toBe fold1
expect(displayBuffer.lineForRow(3).text).toMatch "5"
expect(displayBuffer.lineForRow(4).fold).toBe fold2
expect(displayBuffer.lineForRow(5).text).toMatch /^9-+/
expect(displayBuffer.tokenizedLineForScreenRow(1).text).toBe "1"
expect(displayBuffer.tokenizedLineForScreenRow(2).text).toBe "2"
expect(displayBuffer.tokenizedLineForScreenRow(2).fold).toBe fold1
expect(displayBuffer.tokenizedLineForScreenRow(3).text).toMatch "5"
expect(displayBuffer.tokenizedLineForScreenRow(4).fold).toBe fold2
expect(displayBuffer.tokenizedLineForScreenRow(5).text).toMatch /^9-+/
expect(changeHandler).toHaveBeenCalledWith(start: 2, end: 2, screenDelta: 0, bufferDelta: 1)
@@ -464,12 +464,12 @@ describe "DisplayBuffer", ->
expect(fold1.getStartRow()).toBe 2
expect(fold1.getEndRow()).toBe 7
expect(displayBuffer.lineForRow(1).text).toBe "1"
expect(displayBuffer.lineForRow(2).text).toBe "2"
expect(displayBuffer.lineForRow(2).fold).toBe fold1
expect(displayBuffer.lineForRow(3).text).toMatch "5"
expect(displayBuffer.lineForRow(4).fold).toBe fold2
expect(displayBuffer.lineForRow(5).text).toMatch /^9-+/
expect(displayBuffer.tokenizedLineForScreenRow(1).text).toBe "1"
expect(displayBuffer.tokenizedLineForScreenRow(2).text).toBe "2"
expect(displayBuffer.tokenizedLineForScreenRow(2).fold).toBe fold1
expect(displayBuffer.tokenizedLineForScreenRow(3).text).toMatch "5"
expect(displayBuffer.tokenizedLineForScreenRow(4).fold).toBe fold2
expect(displayBuffer.tokenizedLineForScreenRow(5).text).toMatch /^9-+/
expect(changeHandler).toHaveBeenCalledWith(start: 2, end: 2, screenDelta: 0, bufferDelta: 3)
@@ -478,21 +478,21 @@ describe "DisplayBuffer", ->
it "destroys the fold", ->
fold2.destroy()
buffer.setTextInRange([[3, 0], [6, 0]], 'a\n')
expect(displayBuffer.lineForRow(2).text).toBe '2'
expect(displayBuffer.lineForRow(2).fold).toBeUndefined()
expect(displayBuffer.lineForRow(3).text).toBe 'a'
expect(displayBuffer.lineForRow(4).text).toBe '6'
expect(displayBuffer.tokenizedLineForScreenRow(2).text).toBe '2'
expect(displayBuffer.tokenizedLineForScreenRow(2).fold).toBeUndefined()
expect(displayBuffer.tokenizedLineForScreenRow(3).text).toBe 'a'
expect(displayBuffer.tokenizedLineForScreenRow(4).text).toBe '6'
describe "when the old range is contained to a single line in-between two folds", ->
it "re-renders the line with the placeholder and re-positions the second fold", ->
buffer.insert([5, 0], 'abc\n')
expect(displayBuffer.lineForRow(1).text).toBe "1"
expect(displayBuffer.lineForRow(2).fold).toBe fold1
expect(displayBuffer.lineForRow(3).text).toMatch "abc"
expect(displayBuffer.lineForRow(4).text).toBe "5"
expect(displayBuffer.lineForRow(5).fold).toBe fold2
expect(displayBuffer.lineForRow(6).text).toMatch /^9-+/
expect(displayBuffer.tokenizedLineForScreenRow(1).text).toBe "1"
expect(displayBuffer.tokenizedLineForScreenRow(2).fold).toBe fold1
expect(displayBuffer.tokenizedLineForScreenRow(3).text).toMatch "abc"
expect(displayBuffer.tokenizedLineForScreenRow(4).text).toBe "5"
expect(displayBuffer.tokenizedLineForScreenRow(5).fold).toBe fold2
expect(displayBuffer.tokenizedLineForScreenRow(6).text).toMatch /^9-+/
expect(changeHandler).toHaveBeenCalledWith(start: 3, end: 3, screenDelta: 1, bufferDelta: 1)
@@ -545,15 +545,15 @@ describe "DisplayBuffer", ->
displayBuffer.createFold(1, 9)
displayBuffer.createFold(11, 12)
expect(displayBuffer.lineForRow(1).text).toBe '1'
expect(displayBuffer.lineForRow(2).text).toBe '10'
expect(displayBuffer.tokenizedLineForScreenRow(1).text).toBe '1'
expect(displayBuffer.tokenizedLineForScreenRow(2).text).toBe '10'
displayBuffer.unfoldBufferRow(2)
expect(displayBuffer.lineForRow(1).text).toBe '1'
expect(displayBuffer.lineForRow(2).text).toBe '2'
expect(displayBuffer.lineForRow(7).fold).toBeDefined()
expect(displayBuffer.lineForRow(8).text).toMatch /^9-+/
expect(displayBuffer.lineForRow(10).fold).toBeDefined()
expect(displayBuffer.tokenizedLineForScreenRow(1).text).toBe '1'
expect(displayBuffer.tokenizedLineForScreenRow(2).text).toBe '2'
expect(displayBuffer.tokenizedLineForScreenRow(7).fold).toBeDefined()
expect(displayBuffer.tokenizedLineForScreenRow(8).text).toMatch /^9-+/
expect(displayBuffer.tokenizedLineForScreenRow(10).fold).toBeDefined()
describe ".outermostFoldsInBufferRowRange(startRow, endRow)", ->
it "returns the outermost folds entirely contained in the given row range, exclusive of end row", ->
@@ -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]])
@@ -1037,16 +1037,28 @@ describe "DisplayBuffer", ->
expect(start.top).toBe 5 * 20
expect(start.left).toBe (4 * 10) + (6 * 11)
describe 'when there are multiple DisplayBuffers for a buffer', ->
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.onDidCreateMarker markerCreated1 = jasmine.createSpy().andCallFake (marker) -> marker.destroy()
displayBuffer2.onDidCreateMarker markerCreated2 = jasmine.createSpy()
displayBuffer.markBufferRange([[0, 0], [1, 5]], {})
expect(markerCreated1).toHaveBeenCalled()
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
@@ -1061,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 ->
@@ -1159,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)
+170 -55
Ver Arquivo
@@ -1,7 +1,7 @@
_ = require 'underscore-plus'
{extend, flatten, toArray, last} = _
ReactEditorView = require '../src/react-editor-view'
EditorView = require '../src/editor-view'
EditorComponent = require '../src/editor-component'
nbsp = String.fromCharCode(160)
@@ -34,7 +34,7 @@ describe "EditorComponent", ->
contentNode = document.querySelector('#jasmine-content')
contentNode.style.width = '1000px'
wrapperView = new ReactEditorView(editor, {lineOverdrawMargin})
wrapperView = new EditorView(editor, {lineOverdrawMargin})
wrapperView.attachToDom()
wrapperNode = wrapperView.element
@@ -65,9 +65,9 @@ describe "EditorComponent", ->
linesNode = componentNode.querySelector('.lines')
expect(linesNode.style['-webkit-transform']).toBe "translate3d(0px, 0px, 0px)"
expect(componentNode.querySelectorAll('.line').length).toBe 6 + 2 # no margin above
expect(component.lineNodeForScreenRow(0).textContent).toBe editor.lineForScreenRow(0).text
expect(component.lineNodeForScreenRow(0).textContent).toBe editor.tokenizedLineForScreenRow(0).text
expect(component.lineNodeForScreenRow(0).offsetTop).toBe 0
expect(component.lineNodeForScreenRow(5).textContent).toBe editor.lineForScreenRow(5).text
expect(component.lineNodeForScreenRow(5).textContent).toBe editor.tokenizedLineForScreenRow(5).text
expect(component.lineNodeForScreenRow(5).offsetTop).toBe 5 * lineHeightInPixels
verticalScrollbarNode.scrollTop = 4.5 * lineHeightInPixels
@@ -77,9 +77,9 @@ describe "EditorComponent", ->
expect(linesNode.style['-webkit-transform']).toBe "translate3d(0px, #{-4.5 * lineHeightInPixels}px, 0px)"
expect(componentNode.querySelectorAll('.line').length).toBe 6 + 4 # margin above and below
expect(component.lineNodeForScreenRow(2).offsetTop).toBe 2 * lineHeightInPixels
expect(component.lineNodeForScreenRow(2).textContent).toBe editor.lineForScreenRow(2).text
expect(component.lineNodeForScreenRow(2).textContent).toBe editor.tokenizedLineForScreenRow(2).text
expect(component.lineNodeForScreenRow(9).offsetTop).toBe 9 * lineHeightInPixels
expect(component.lineNodeForScreenRow(9).textContent).toBe editor.lineForScreenRow(9).text
expect(component.lineNodeForScreenRow(9).textContent).toBe editor.tokenizedLineForScreenRow(9).text
it "updates the top position of subsequent lines when lines are inserted or removed", ->
editor.getBuffer().deleteRows(0, 1)
@@ -111,11 +111,11 @@ describe "EditorComponent", ->
buffer.insert([0, 0], '\n\n')
nextAnimationFrame()
expect(component.lineNodeForScreenRow(3).textContent).toBe editor.lineForScreenRow(3).text
expect(component.lineNodeForScreenRow(3).textContent).toBe editor.tokenizedLineForScreenRow(3).text
buffer.delete([[0, 0], [3, 0]])
nextAnimationFrame()
expect(component.lineNodeForScreenRow(3).textContent).toBe editor.lineForScreenRow(3).text
expect(component.lineNodeForScreenRow(3).textContent).toBe editor.tokenizedLineForScreenRow(3).text
it "updates the top position of lines when the line height changes", ->
initialLineHeightInPixels = editor.getLineHeightInPixels()
@@ -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
@@ -209,25 +253,32 @@ describe "EditorComponent", ->
atom.config.set("editor.showInvisibles", true)
atom.config.set("editor.invisibles", invisibles)
nextAnimationFrame()
it "re-renders the lines when the showInvisibles config option changes", ->
editor.setText " a line with tabs\tand spaces "
editor.setText " a line with tabs\tand spaces \n"
nextAnimationFrame()
expect(component.lineNodeForScreenRow(0).textContent).toBe "#{invisibles.space}a line with tabs#{invisibles.tab}and spaces#{invisibles.space}#{invisibles.eol}"
atom.config.set("editor.showInvisibles", false)
nextAnimationFrame()
expect(component.lineNodeForScreenRow(0).textContent).toBe " a line with tabs and spaces "
atom.config.set("editor.showInvisibles", true)
expect(component.lineNodeForScreenRow(0).textContent).toBe "#{invisibles.space}a line with tabs#{invisibles.tab}and spaces#{invisibles.space}#{invisibles.eol}"
it "displays spaces, tabs, and newlines as visible characters", ->
editor.setText " a line with tabs\tand spaces "
nextAnimationFrame()
expect(component.lineNodeForScreenRow(0).textContent).toBe "#{invisibles.space}a line with tabs#{invisibles.tab}and spaces#{invisibles.space}#{invisibles.eol}"
it "displays leading/trailing spaces, tabs, and newlines as visible characters", ->
editor.setText " a line with tabs\tand spaces \n"
nextAnimationFrame()
expect(component.lineNodeForScreenRow(0).textContent).toBe "#{invisibles.space}a line with tabs#{invisibles.tab}and spaces#{invisibles.space}#{invisibles.eol}"
leafNodes = getLeafNodes(component.lineNodeForScreenRow(0))
expect(leafNodes[0].classList.contains('invisible-character')).toBe true
expect(leafNodes[leafNodes.length - 1].classList.contains('invisible-character')).toBe true
it "displays newlines as their own token outside of the other tokens' scopes", ->
editor.setText "var"
editor.setText "var\n"
nextAnimationFrame()
expect(component.lineNodeForScreenRow(0).innerHTML).toBe "<span class=\"source js\"><span class=\"storage modifier js\">var</span></span><span class=\"invisible-character\">#{invisibles.eol}</span>"
@@ -241,10 +292,12 @@ describe "EditorComponent", ->
it "renders an nbsp on empty lines when the line-ending character is an empty string", ->
atom.config.set("editor.invisibles", eol: '')
nextAnimationFrame()
expect(component.lineNodeForScreenRow(10).textContent).toBe nbsp
it "renders an nbsp on empty lines when no line-ending character is defined", ->
atom.config.set("editor.invisibles", eol: null)
it "renders an nbsp on empty lines when the line-ending character is false", ->
atom.config.set("editor.invisibles", eol: false)
nextAnimationFrame()
expect(component.lineNodeForScreenRow(10).textContent).toBe nbsp
it "interleaves invisible line-ending characters with indent guides on empty lines", ->
@@ -268,8 +321,8 @@ describe "EditorComponent", ->
describe "when soft wrapping is enabled", ->
beforeEach ->
editor.setText "a line that wraps "
editor.setSoftWrap(true)
editor.setText "a line that wraps \n"
editor.setSoftWrapped(true)
nextAnimationFrame()
componentNode.style.width = 16 * charWidth + editor.getVerticalScrollbarWidth() + 'px'
component.measureHeightAndWidth()
@@ -448,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()
@@ -592,7 +645,7 @@ describe "EditorComponent", ->
describe "cursor rendering", ->
it "renders the currently visible cursors, translated relative to the scroll position", ->
cursor1 = editor.getCursor()
cursor1 = editor.getLastCursor()
cursor1.setScreenPosition([0, 5])
wrapperNode.style.height = 4.5 * lineHeightInPixels + 'px'
@@ -701,7 +754,7 @@ describe "EditorComponent", ->
expect(cursorsNode.classList.contains('blink-off')).toBe false
# Stop blinking after moving the cursor
editor.moveCursorRight()
editor.moveRight()
expect(cursorsNode.classList.contains('blink-off')).toBe false
advanceClock(component.props.cursorBlinkResumeDelay)
@@ -805,8 +858,8 @@ describe "EditorComponent", ->
it "does not render empty selections", ->
editor.addSelectionForBufferRange([[2, 2], [2, 2]])
nextAnimationFrame()
expect(editor.getSelection(0).isEmpty()).toBe true
expect(editor.getSelection(1).isEmpty()).toBe true
expect(editor.getSelections()[0].isEmpty()).toBe true
expect(editor.getSelections()[1].isEmpty()).toBe true
expect(componentNode.querySelectorAll('.selection').length).toBe 0
@@ -884,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()
@@ -1125,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()
@@ -1309,6 +1362,12 @@ describe "EditorComponent", ->
linesNode.dispatchEvent(buildMouseEvent('mousedown', clientCoordinatesForScreenPosition([4, 8]), {target}))
expect(editor.isFoldedAtBufferRow 4).toBe false
describe "when the horizontal scrollbar is interacted with", ->
it "clicking on the scrollbar does not move the cursor", ->
target = horizontalScrollbarNode
linesNode.dispatchEvent(buildMouseEvent('mousedown', clientCoordinatesForScreenPosition([4, 8]), {target}))
expect(editor.getCursorScreenPosition()).toEqual [0, 0]
describe "mouse interactions on the gutter", ->
gutterNode = null
@@ -1316,9 +1375,19 @@ describe "EditorComponent", ->
gutterNode = componentNode.querySelector('.gutter')
describe "when the gutter is clicked", ->
it "moves the cursor to the beginning of the clicked row", ->
it "selects the clicked row", ->
gutterNode.dispatchEvent(buildMouseEvent('mousedown', clientCoordinatesForScreenRowInGutter(4)))
expect(editor.getCursorScreenPosition()).toEqual [4, 0]
expect(editor.getSelectedScreenRange()).toEqual [[4, 0], [5, 0]]
describe "when the gutter is meta-clicked", ->
it "creates a new selection for the clicked row", ->
editor.setSelectedScreenRange([[3, 0], [3, 2]])
gutterNode.dispatchEvent(buildMouseEvent('mousedown', clientCoordinatesForScreenRowInGutter(4), metaKey: true))
expect(editor.getSelectedScreenRanges()).toEqual [[[3, 0], [3, 2]], [[4, 0], [5, 0]]]
gutterNode.dispatchEvent(buildMouseEvent('mousedown', clientCoordinatesForScreenRowInGutter(6), metaKey: true))
expect(editor.getSelectedScreenRanges()).toEqual [[[3, 0], [3, 2]], [[4, 0], [5, 0]], [[6, 0], [7, 0]]]
describe "when the gutter is shift-clicked", ->
beforeEach ->
@@ -1351,6 +1420,40 @@ describe "EditorComponent", ->
gutterNode.dispatchEvent(buildMouseEvent('mouseup', clientCoordinatesForScreenRowInGutter(2)))
expect(editor.getSelectedScreenRange()).toEqual [[2, 0], [7, 0]]
describe "when the gutter is meta-clicked and dragged", ->
beforeEach ->
editor.setSelectedScreenRange([[3, 0], [3, 2]])
describe "when dragging downward", ->
it "selects the rows between the start and end of the drag", ->
gutterNode.dispatchEvent(buildMouseEvent('mousedown', clientCoordinatesForScreenRowInGutter(4), metaKey: true))
gutterNode.dispatchEvent(buildMouseEvent('mousemove', clientCoordinatesForScreenRowInGutter(6), metaKey: true))
nextAnimationFrame()
gutterNode.dispatchEvent(buildMouseEvent('mouseup', clientCoordinatesForScreenRowInGutter(6), metaKey: true))
expect(editor.getSelectedScreenRanges()).toEqual [[[3, 0], [3, 2]], [[4, 0], [7, 0]]]
it "merges overlapping selections", ->
gutterNode.dispatchEvent(buildMouseEvent('mousedown', clientCoordinatesForScreenRowInGutter(2), metaKey: true))
gutterNode.dispatchEvent(buildMouseEvent('mousemove', clientCoordinatesForScreenRowInGutter(6), metaKey: true))
nextAnimationFrame()
gutterNode.dispatchEvent(buildMouseEvent('mouseup', clientCoordinatesForScreenRowInGutter(6), metaKey: true))
expect(editor.getSelectedScreenRanges()).toEqual [[[2, 0], [7, 0]]]
describe "when dragging upward", ->
it "selects the rows between the start and end of the drag", ->
gutterNode.dispatchEvent(buildMouseEvent('mousedown', clientCoordinatesForScreenRowInGutter(6), metaKey: true))
gutterNode.dispatchEvent(buildMouseEvent('mousemove', clientCoordinatesForScreenRowInGutter(4), metaKey: true))
nextAnimationFrame()
gutterNode.dispatchEvent(buildMouseEvent('mouseup', clientCoordinatesForScreenRowInGutter(4), metaKey: true))
expect(editor.getSelectedScreenRanges()).toEqual [[[3, 0], [3, 2]], [[4, 0], [7, 0]]]
it "merges overlapping selections", ->
gutterNode.dispatchEvent(buildMouseEvent('mousedown', clientCoordinatesForScreenRowInGutter(6), metaKey: true))
gutterNode.dispatchEvent(buildMouseEvent('mousemove', clientCoordinatesForScreenRowInGutter(2), metaKey: true))
nextAnimationFrame()
gutterNode.dispatchEvent(buildMouseEvent('mouseup', clientCoordinatesForScreenRowInGutter(2), metaKey: true))
expect(editor.getSelectedScreenRanges()).toEqual [[[2, 0], [7, 0]]]
describe "when the gutter is shift-clicked and dragged", ->
describe "when the shift-click is below the existing selection's tail", ->
describe "when dragging downward", ->
@@ -1422,7 +1525,7 @@ describe "EditorComponent", ->
cursor = null
beforeEach ->
cursor = editor.getCursor()
cursor = editor.getLastCursor()
cursor.setScreenPosition([0, 0])
it "adds the 'has-selection' class to the editor when there is a selection", ->
@@ -1542,6 +1645,7 @@ describe "EditorComponent", ->
height: 8px;
}
"""
nextAnimationFrame()
scrollbarCornerNode = componentNode.querySelector('.scrollbar-corner')
expect(verticalScrollbarNode.offsetWidth).toBe 8
@@ -1767,28 +1871,28 @@ describe "EditorComponent", ->
it "inserts the newest character in the input's value into the buffer", ->
componentNode.dispatchEvent(buildTextInputEvent(data: 'x', target: inputNode))
nextAnimationFrame()
expect(editor.lineForBufferRow(0)).toBe 'xvar quicksort = function () {'
expect(editor.lineTextForBufferRow(0)).toBe 'xvar quicksort = function () {'
componentNode.dispatchEvent(buildTextInputEvent(data: 'y', target: inputNode))
nextAnimationFrame()
expect(editor.lineForBufferRow(0)).toBe 'xyvar quicksort = function () {'
expect(editor.lineTextForBufferRow(0)).toBe 'xyvar quicksort = function () {'
it "replaces the last character if the length of the input's value doesn't increase, as occurs with the accented character menu", ->
componentNode.dispatchEvent(buildTextInputEvent(data: 'u', target: inputNode))
nextAnimationFrame()
expect(editor.lineForBufferRow(0)).toBe 'uvar quicksort = function () {'
expect(editor.lineTextForBufferRow(0)).toBe 'uvar quicksort = function () {'
# simulate the accented character suggestion's selection of the previous character
inputNode.setSelectionRange(0, 1)
componentNode.dispatchEvent(buildTextInputEvent(data: 'ü', target: inputNode))
nextAnimationFrame()
expect(editor.lineForBufferRow(0)).toBe 'üvar quicksort = function () {'
expect(editor.lineTextForBufferRow(0)).toBe 'üvar quicksort = function () {'
it "does not handle input events when input is disabled", ->
component.setInputEnabled(false)
componentNode.dispatchEvent(buildTextInputEvent(data: 'x', target: inputNode))
expect(nextAnimationFrame).toBe noAnimationFrame
expect(editor.lineForBufferRow(0)).toBe 'var quicksort = function () {'
expect(editor.lineTextForBufferRow(0)).toBe 'var quicksort = function () {'
describe "when IME composition is used to insert international characters", ->
inputNode = null
@@ -1806,46 +1910,46 @@ describe "EditorComponent", ->
it "inserts the chosen completion", ->
componentNode.dispatchEvent(buildIMECompositionEvent('compositionstart', target: inputNode))
componentNode.dispatchEvent(buildIMECompositionEvent('compositionupdate', data: 's', target: inputNode))
expect(editor.lineForBufferRow(0)).toBe 'svar quicksort = function () {'
expect(editor.lineTextForBufferRow(0)).toBe 'svar quicksort = function () {'
componentNode.dispatchEvent(buildIMECompositionEvent('compositionupdate', data: 'sd', target: inputNode))
expect(editor.lineForBufferRow(0)).toBe 'sdvar quicksort = function () {'
expect(editor.lineTextForBufferRow(0)).toBe 'sdvar quicksort = function () {'
componentNode.dispatchEvent(buildIMECompositionEvent('compositionend', target: inputNode))
componentNode.dispatchEvent(buildTextInputEvent(data: '速度', target: inputNode))
expect(editor.lineForBufferRow(0)).toBe '速度var quicksort = function () {'
expect(editor.lineTextForBufferRow(0)).toBe '速度var quicksort = function () {'
it "reverts back to the original text when the completion helper is dismissed", ->
componentNode.dispatchEvent(buildIMECompositionEvent('compositionstart', target: inputNode))
componentNode.dispatchEvent(buildIMECompositionEvent('compositionupdate', data: 's', target: inputNode))
expect(editor.lineForBufferRow(0)).toBe 'svar quicksort = function () {'
expect(editor.lineTextForBufferRow(0)).toBe 'svar quicksort = function () {'
componentNode.dispatchEvent(buildIMECompositionEvent('compositionupdate', data: 'sd', target: inputNode))
expect(editor.lineForBufferRow(0)).toBe 'sdvar quicksort = function () {'
expect(editor.lineTextForBufferRow(0)).toBe 'sdvar quicksort = function () {'
componentNode.dispatchEvent(buildIMECompositionEvent('compositionend', target: inputNode))
expect(editor.lineForBufferRow(0)).toBe 'var quicksort = function () {'
expect(editor.lineTextForBufferRow(0)).toBe 'var quicksort = function () {'
it "allows multiple accented character to be inserted with the ' on a US international layout", ->
inputNode.value = "'"
inputNode.setSelectionRange(0, 1)
componentNode.dispatchEvent(buildIMECompositionEvent('compositionstart', target: inputNode))
componentNode.dispatchEvent(buildIMECompositionEvent('compositionupdate', data: "'", target: inputNode))
expect(editor.lineForBufferRow(0)).toBe "'var quicksort = function () {"
expect(editor.lineTextForBufferRow(0)).toBe "'var quicksort = function () {"
componentNode.dispatchEvent(buildIMECompositionEvent('compositionend', target: inputNode))
componentNode.dispatchEvent(buildTextInputEvent(data: 'á', target: inputNode))
expect(editor.lineForBufferRow(0)).toBe "ávar quicksort = function () {"
expect(editor.lineTextForBufferRow(0)).toBe "ávar quicksort = function () {"
inputNode.value = "'"
inputNode.setSelectionRange(0, 1)
componentNode.dispatchEvent(buildIMECompositionEvent('compositionstart', target: inputNode))
componentNode.dispatchEvent(buildIMECompositionEvent('compositionupdate', data: "'", target: inputNode))
expect(editor.lineForBufferRow(0)).toBe "á'var quicksort = function () {"
expect(editor.lineTextForBufferRow(0)).toBe "á'var quicksort = function () {"
componentNode.dispatchEvent(buildIMECompositionEvent('compositionend', target: inputNode))
componentNode.dispatchEvent(buildTextInputEvent(data: 'á', target: inputNode))
expect(editor.lineForBufferRow(0)).toBe "áávar quicksort = function () {"
expect(editor.lineTextForBufferRow(0)).toBe "áávar quicksort = function () {"
describe "when a string is selected", ->
beforeEach ->
@@ -1854,25 +1958,25 @@ describe "EditorComponent", ->
it "inserts the chosen completion", ->
componentNode.dispatchEvent(buildIMECompositionEvent('compositionstart', target: inputNode))
componentNode.dispatchEvent(buildIMECompositionEvent('compositionupdate', data: 's', target: inputNode))
expect(editor.lineForBufferRow(0)).toBe 'var ssort = function () {'
expect(editor.lineTextForBufferRow(0)).toBe 'var ssort = function () {'
componentNode.dispatchEvent(buildIMECompositionEvent('compositionupdate', data: 'sd', target: inputNode))
expect(editor.lineForBufferRow(0)).toBe 'var sdsort = function () {'
expect(editor.lineTextForBufferRow(0)).toBe 'var sdsort = function () {'
componentNode.dispatchEvent(buildIMECompositionEvent('compositionend', target: inputNode))
componentNode.dispatchEvent(buildTextInputEvent(data: '速度', target: inputNode))
expect(editor.lineForBufferRow(0)).toBe 'var 速度sort = function () {'
expect(editor.lineTextForBufferRow(0)).toBe 'var 速度sort = function () {'
it "reverts back to the original text when the completion helper is dismissed", ->
componentNode.dispatchEvent(buildIMECompositionEvent('compositionstart', target: inputNode))
componentNode.dispatchEvent(buildIMECompositionEvent('compositionupdate', data: 's', target: inputNode))
expect(editor.lineForBufferRow(0)).toBe 'var ssort = function () {'
expect(editor.lineTextForBufferRow(0)).toBe 'var ssort = function () {'
componentNode.dispatchEvent(buildIMECompositionEvent('compositionupdate', data: 'sd', target: inputNode))
expect(editor.lineForBufferRow(0)).toBe 'var sdsort = function () {'
expect(editor.lineTextForBufferRow(0)).toBe 'var sdsort = function () {'
componentNode.dispatchEvent(buildIMECompositionEvent('compositionend', target: inputNode))
expect(editor.lineForBufferRow(0)).toBe 'var quicksort = function () {'
expect(editor.lineTextForBufferRow(0)).toBe 'var quicksort = function () {'
describe "commands", ->
describe "editor:consolidate-selections", ->
@@ -1895,7 +1999,7 @@ describe "EditorComponent", ->
hiddenParent.style.display = 'none'
contentNode.appendChild(hiddenParent)
wrapperView = new ReactEditorView(editor, {lineOverdrawMargin})
wrapperView = new EditorView(editor, {lineOverdrawMargin})
wrapperNode = wrapperView.element
wrapperView.appendTo(hiddenParent)
@@ -1937,6 +2041,7 @@ describe "EditorComponent", ->
wrapperView.hide()
component.setFontSize(22)
editor.getBuffer().insert([0, 0], 'a') # regression test against atom/atom#3318
wrapperView.show()
editor.setCursorBufferPosition([0, Infinity])
@@ -2005,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", ->
@@ -2103,9 +2208,13 @@ describe "EditorComponent", ->
it "adds the 'mini' class to the wrapper view", ->
expect(wrapperNode.classList.contains('mini')).toBe true
it "does not have an opaque background on lines", ->
expect(component.refs.lines.getDOMNode().getAttribute('style')).not.toContain 'background-color'
it "does not render invisible characters", ->
component.setInvisibles(eol: 'E')
component.setShowInvisibles(true)
atom.config.set('editor.invisibles', eol: 'E')
atom.config.set('editor.showInvisibles', true)
nextAnimationFrame()
expect(component.lineNodeForScreenRow(0).textContent).toBe 'var quicksort = function () {'
it "does not assign an explicit line-height on the editor contents", ->
@@ -2127,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()
@@ -2144,6 +2253,12 @@ describe "EditorComponent", ->
setEditorWidthInChars(wrapperView, 10)
expect(componentNode.querySelector('.scroll-view').offsetWidth).toBe charWidth * 10
describe "grammar data attributes", ->
it "adds and updates the grammar data attribute based on the current grammar", ->
expect(wrapperNode.dataset.grammar).toBe 'source js'
editor.setGrammar(atom.syntax.nullGrammar)
expect(wrapperNode.dataset.grammar).toBe 'text plain null-grammar'
buildMouseEvent = (type, properties...) ->
properties = extend({bubbles: true, cancelable: true}, properties...)
properties.detail ?= 1
+635 -343
Ver Arquivo
Diferenças do arquivo suprimidas por serem muito extensas Carregar Diff
Diferenças do arquivo suprimidas por serem muito extensas Carregar Diff
@@ -0,0 +1,4 @@
module.exports =
activate: ->
deactivate: -> throw new Error('Top that')
serialize: ->
+63 -31
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,17 +111,49 @@ 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
describe ".checkoutHeadForEditor(editor)", ->
[filePath, editor] = []
beforeEach ->
workingDirPath = copyRepository()
repo = new GitRepository(workingDirPath)
filePath = path.join(workingDirPath, 'a.txt')
fs.writeFileSync(filePath, 'ch ch changes')
waitsForPromise ->
atom.workspace.open(filePath)
runs ->
editor = atom.workspace.getActiveEditor()
it "displays a confirmation dialog by default", ->
spyOn(atom, 'confirm').andCallFake ({buttons}) -> buttons.OK()
atom.config.set('editor.confirmCheckoutHeadRevision', true)
repo.checkoutHeadForEditor(editor)
expect(fs.readFileSync(filePath, 'utf8')).toBe ''
it "does not display a dialog when confirmation is disabled", ->
spyOn(atom, 'confirm')
atom.config.set('editor.confirmCheckoutHeadRevision', false)
repo.checkoutHeadForEditor(editor)
expect(fs.readFileSync(filePath, 'utf8')).toBe ''
expect(atom.confirm).not.toHaveBeenCalled()
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()
@@ -130,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)
@@ -150,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')
@@ -165,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')
@@ -176,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 ->
@@ -200,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
@@ -220,11 +252,11 @@ describe "Git", ->
fs.writeFileSync(editor.getPath(), 'changed')
statusHandler = jasmine.createSpy('statusHandler')
atom.project.getRepo().on 'status-changed', statusHandler
editor.getBuffer().emit 'path-changed'
atom.project.getRepo().onDidChangeStatus statusHandler
editor.getBuffer().emitter.emit 'did-change-path'
expect(statusHandler.callCount).toBe 1
expect(statusHandler).toHaveBeenCalledWith editor.getPath(), 256
editor.getBuffer().emit 'path-changed'
expect(statusHandler).toHaveBeenCalledWith {path: editor.getPath(), pathStatus: 256}
editor.getBuffer().emitter.emit 'did-change-path'
expect(statusHandler.callCount).toBe 1
describe "when a project is deserialized", ->
@@ -251,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
+40 -18
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
@@ -275,46 +297,46 @@ describe "LanguageMode", ->
it "folds every foldable line", ->
languageMode.foldAll()
fold1 = editor.lineForScreenRow(0).fold
fold1 = editor.tokenizedLineForScreenRow(0).fold
expect([fold1.getStartRow(), fold1.getEndRow()]).toEqual [0, 12]
fold1.destroy()
fold2 = editor.lineForScreenRow(1).fold
fold2 = editor.tokenizedLineForScreenRow(1).fold
expect([fold2.getStartRow(), fold2.getEndRow()]).toEqual [1, 9]
fold2.destroy()
fold3 = editor.lineForScreenRow(4).fold
fold3 = editor.tokenizedLineForScreenRow(4).fold
expect([fold3.getStartRow(), fold3.getEndRow()]).toEqual [4, 7]
describe ".foldBufferRow(bufferRow)", ->
describe "when bufferRow can be folded", ->
it "creates a fold based on the syntactic region starting at the given row", ->
languageMode.foldBufferRow(1)
fold = editor.lineForScreenRow(1).fold
fold = editor.tokenizedLineForScreenRow(1).fold
expect(fold.getStartRow()).toBe 1
expect(fold.getEndRow()).toBe 9
describe "when bufferRow can't be folded", ->
it "searches upward for the first row that begins a syntatic region containing the given buffer row (and folds it)", ->
languageMode.foldBufferRow(8)
fold = editor.lineForScreenRow(1).fold
fold = editor.tokenizedLineForScreenRow(1).fold
expect(fold.getStartRow()).toBe 1
expect(fold.getEndRow()).toBe 9
describe "when the bufferRow is already folded", ->
it "searches upward for the first row that begins a syntatic region containing the folded row (and folds it)", ->
languageMode.foldBufferRow(2)
expect(editor.lineForScreenRow(1).fold).toBeDefined()
expect(editor.lineForScreenRow(0).fold).not.toBeDefined()
expect(editor.tokenizedLineForScreenRow(1).fold).toBeDefined()
expect(editor.tokenizedLineForScreenRow(0).fold).not.toBeDefined()
languageMode.foldBufferRow(1)
expect(editor.lineForScreenRow(0).fold).toBeDefined()
expect(editor.tokenizedLineForScreenRow(0).fold).toBeDefined()
describe "when the bufferRow is in a multi-line comment", ->
it "searches upward and downward for surrounding comment lines and folds them as a single fold", ->
buffer.insert([1,0], " //this is a comment\n // and\n //more docs\n\n//second comment")
languageMode.foldBufferRow(1)
fold = editor.lineForScreenRow(1).fold
fold = editor.tokenizedLineForScreenRow(1).fold
expect(fold.getStartRow()).toBe 1
expect(fold.getEndRow()).toBe 3
@@ -322,7 +344,7 @@ describe "LanguageMode", ->
it "searches upward for the first row that begins a syntatic region containing the folded row (and folds it)", ->
buffer.insert([1,0], " //this is a single line comment\n")
languageMode.foldBufferRow(1)
fold = editor.lineForScreenRow(0).fold
fold = editor.tokenizedLineForScreenRow(0).fold
expect(fold.getStartRow()).toBe 0
expect(fold.getEndRow()).toBe 13
@@ -357,38 +379,38 @@ describe "LanguageMode", ->
it "folds every foldable line", ->
languageMode.foldAll()
fold1 = editor.lineForScreenRow(0).fold
fold1 = editor.tokenizedLineForScreenRow(0).fold
expect([fold1.getStartRow(), fold1.getEndRow()]).toEqual [0, 19]
fold1.destroy()
fold2 = editor.lineForScreenRow(1).fold
fold2 = editor.tokenizedLineForScreenRow(1).fold
expect([fold2.getStartRow(), fold2.getEndRow()]).toEqual [1, 4]
fold3 = editor.lineForScreenRow(2).fold.destroy()
fold3 = editor.tokenizedLineForScreenRow(2).fold.destroy()
fold4 = editor.lineForScreenRow(3).fold
fold4 = editor.tokenizedLineForScreenRow(3).fold
expect([fold4.getStartRow(), fold4.getEndRow()]).toEqual [6, 8]
describe ".foldAllAtIndentLevel()", ->
it "folds every foldable range at a given indentLevel", ->
languageMode.foldAllAtIndentLevel(2)
fold1 = editor.lineForScreenRow(6).fold
fold1 = editor.tokenizedLineForScreenRow(6).fold
expect([fold1.getStartRow(), fold1.getEndRow()]).toEqual [6, 8]
fold1.destroy()
fold2 = editor.lineForScreenRow(11).fold
fold2 = editor.tokenizedLineForScreenRow(11).fold
expect([fold2.getStartRow(), fold2.getEndRow()]).toEqual [11, 14]
fold2.destroy()
it "does not fold anything but the indentLevel", ->
languageMode.foldAllAtIndentLevel(0)
fold1 = editor.lineForScreenRow(0).fold
fold1 = editor.tokenizedLineForScreenRow(0).fold
expect([fold1.getStartRow(), fold1.getEndRow()]).toEqual [0, 19]
fold1.destroy()
fold2 = editor.lineForScreenRow(5).fold
fold2 = editor.tokenizedLineForScreenRow(5).fold
expect(fold2).toBeFalsy()
describe ".isFoldableAtBufferRow(bufferRow)", ->
+4 -1
Ver Arquivo
@@ -5,6 +5,9 @@ ThemePackage = require '../src/theme-package'
describe "Package", ->
describe "when the package contains incompatible native modules", ->
beforeEach ->
spyOn(atom, 'inDevMode').andReturn(false)
it "does not activate it", ->
packagePath = atom.project.resolve('packages/package-with-incompatible-native-module')
pack = new Package(packagePath)
@@ -99,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()
+70 -21
Ver Arquivo
@@ -27,42 +27,91 @@ describe "PaneContainer", ->
it "preserves the active pane across serialization, independent of focus", ->
pane3A.activate()
expect(containerA.activePane).toBe pane3A
expect(containerA.getActivePane()).toBe pane3A
containerB = containerA.testSerialization()
[pane1B, pane2B, pane3B] = containerB.getPanes()
expect(containerB.activePane).toBe pane3B
expect(containerB.getActivePane()).toBe pane3B
describe "::activePane", ->
it "does not allow the root pane to be destroyed", ->
container = new PaneContainer
container.getRoot().destroy()
expect(container.getRoot()).toBeDefined()
expect(container.getRoot().isDestroyed()).toBe false
describe "::getActivePane()", ->
[container, pane1, pane2] = []
beforeEach ->
container = new PaneContainer
pane1 = container.root
pane1 = container.getRoot()
it "references the first pane if no pane has been made active", ->
expect(container.activePane).toBe pane1
expect(pane1.active).toBe true
it "returns the first pane if no pane has been made active", ->
expect(container.getActivePane()).toBe pane1
expect(pane1.isActive()).toBe true
it "references the most pane on which ::activate was most recently called", ->
it "returns the most pane on which ::activate() was most recently called", ->
pane2 = pane1.splitRight()
pane2.activate()
expect(container.activePane).toBe pane2
expect(pane1.active).toBe false
expect(pane2.active).toBe true
expect(container.getActivePane()).toBe pane2
expect(pane1.isActive()).toBe false
expect(pane2.isActive()).toBe true
pane1.activate()
expect(container.activePane).toBe pane1
expect(pane1.active).toBe true
expect(pane2.active).toBe false
expect(container.getActivePane()).toBe pane1
expect(pane1.isActive()).toBe true
expect(pane2.isActive()).toBe false
it "is reassigned to the next pane if the current active pane is destroyed", ->
it "returns the next pane if the current active pane is destroyed", ->
pane2 = pane1.splitRight()
pane2.activate()
pane2.destroy()
expect(container.activePane).toBe pane1
expect(pane1.active).toBe true
expect(container.getActivePane()).toBe pane1
expect(pane1.isActive()).toBe true
it "does not allow the root pane to be destroyed", ->
pane1.destroy()
expect(container.root).toBe pane1
expect(pane1.isDestroyed()).toBe false
describe "::onDidChangeActivePaneItem()", ->
[container, pane1, pane2, observed] = []
beforeEach ->
container = new PaneContainer(root: new Pane(items: [new Object, new Object]))
container.getRoot().splitRight(items: [new Object, new Object])
[pane1, pane2] = container.getPanes()
observed = []
container.onDidChangeActivePaneItem (item) -> observed.push(item)
it "invokes observers when the active item of the active pane changes", ->
pane2.activateNextItem()
pane2.activateNextItem()
expect(observed).toEqual [pane2.itemAtIndex(1), pane2.itemAtIndex(0)]
it "invokes observers when the active pane changes", ->
pane1.activate()
pane2.activate()
expect(observed).toEqual [pane1.itemAtIndex(0), pane2.itemAtIndex(0)]
describe "::observePanes()", ->
it "invokes observers with all current and future panes", ->
container = new PaneContainer
container.getRoot().splitRight()
[pane1, pane2] = container.getPanes()
observed = []
container.observePanes (pane) -> observed.push(pane)
pane3 = pane2.splitDown()
pane4 = pane2.splitRight()
expect(observed).toEqual [pane1, pane2, pane3, pane4]
describe "::observePaneItems()", ->
it "invokes observers with all current and future pane items", ->
container = new PaneContainer(root: new Pane(items: [new Object, new Object]))
container.getRoot().splitRight(items: [new Object])
[pane1, pane2] = container.getPanes()
observed = []
container.observePaneItems (pane) -> observed.push(pane)
pane3 = pane2.splitDown(items: [new Object])
pane3.addItems([new Object, new Object])
expect(observed).toEqual container.getPaneItems()
+218 -107
Ver Arquivo
@@ -21,39 +21,83 @@ describe "Pane", ->
describe "construction", ->
it "sets the active item to the first item", ->
pane = new Pane(items: [new Item("A"), new Item("B")])
expect(pane.activeItem).toBe pane.items[0]
expect(pane.getActiveItem()).toBe pane.itemAtIndex(0)
it "compacts the items array", ->
pane = new Pane(items: [undefined, new Item("A"), null, new Item("B")])
expect(pane.items.length).toBe 2
expect(pane.activeItem).toBe pane.items[0]
expect(pane.getItems().length).toBe 2
expect(pane.getActiveItem()).toBe pane.itemAtIndex(0)
describe "::activate()", ->
[container, pane1, pane2] = []
beforeEach ->
container = new PaneContainer(root: new Pane)
container.getRoot().splitRight()
[pane1, pane2] = container.getPanes()
it "changes the active pane on the container", ->
expect(container.getActivePane()).toBe pane2
pane1.activate()
expect(container.getActivePane()).toBe pane1
pane2.activate()
expect(container.getActivePane()).toBe pane2
it "invokes ::onDidChangeActivePane observers on the container", ->
observed = []
container.onDidChangeActivePane (activePane) -> observed.push(activePane)
pane1.activate()
pane1.activate()
pane2.activate()
pane1.activate()
expect(observed).toEqual [pane1, pane2, pane1]
it "invokes ::onDidChangeActive observers on the relevant panes", ->
observed = []
pane1.onDidChangeActive (active) -> observed.push(active)
pane1.activate()
pane2.activate()
expect(observed).toEqual [true, false]
it "invokes ::onDidActivate() observers", ->
eventCount = 0
pane1.onDidActivate -> eventCount++
pane1.activate()
pane1.activate()
pane2.activate()
expect(eventCount).toBe 2
describe "::addItem(item, index)", ->
it "adds the item at the given index", ->
pane = new Pane(items: [new Item("A"), new Item("B")])
[item1, item2] = pane.items
[item1, item2] = pane.getItems()
item3 = new Item("C")
pane.addItem(item3, 1)
expect(pane.items).toEqual [item1, item3, item2]
expect(pane.getItems()).toEqual [item1, item3, item2]
it "adds the item after the active item ", ->
it "adds the item after the active item if no index is provided", ->
pane = new Pane(items: [new Item("A"), new Item("B"), new Item("C")])
[item1, item2, item3] = pane.items
[item1, item2, item3] = pane.getItems()
pane.activateItem(item2)
item4 = new Item("D")
pane.addItem(item4)
expect(pane.items).toEqual [item1, item2, item4, item3]
expect(pane.getItems()).toEqual [item1, item2, item4, item3]
it "sets the active item after adding the first item", ->
pane = new Pane
item = new Item("A")
events = []
pane.on 'item-added', -> events.push('item-added')
pane.$activeItem.changes.onValue -> events.push('active-item-changed')
pane.addItem(item)
expect(pane.activeItem).toBe item
expect(events).toEqual ['item-added', 'active-item-changed']
expect(pane.getActiveItem()).toBe item
it "invokes ::onDidAddItem() observers", ->
pane = new Pane(items: [new Item("A"), new Item("B")])
events = []
pane.onDidAddItem (event) -> events.push(event)
item = new Item("C")
pane.addItem(item, 1)
expect(events).toEqual [{item, index: 1}]
describe "::activateItem(item)", ->
pane = null
@@ -62,83 +106,102 @@ describe "Pane", ->
pane = new Pane(items: [new Item("A"), new Item("B")])
it "changes the active item to the current item", ->
expect(pane.activeItem).toBe pane.items[0]
pane.activateItem(pane.items[1])
expect(pane.activeItem).toBe pane.items[1]
expect(pane.getActiveItem()).toBe pane.itemAtIndex(0)
pane.activateItem(pane.itemAtIndex(1))
expect(pane.getActiveItem()).toBe pane.itemAtIndex(1)
it "adds the given item if it isn't present in ::items", ->
item = new Item("C")
pane.activateItem(item)
expect(item in pane.items).toBe true
expect(pane.activeItem).toBe item
expect(item in pane.getItems()).toBe true
expect(pane.getActiveItem()).toBe item
it "invokes ::onDidChangeActiveItem() observers", ->
observed = []
pane.onDidChangeActiveItem (item) -> observed.push(item)
pane.activateItem(pane.itemAtIndex(1))
expect(observed).toEqual [pane.itemAtIndex(1)]
describe "::activateNextItem() and ::activatePreviousItem()", ->
it "sets the active item to the next/previous item, looping around at either end", ->
pane = new Pane(items: [new Item("A"), new Item("B"), new Item("C")])
[item1, item2, item3] = pane.items
[item1, item2, item3] = pane.getItems()
expect(pane.activeItem).toBe item1
expect(pane.getActiveItem()).toBe item1
pane.activatePreviousItem()
expect(pane.activeItem).toBe item3
expect(pane.getActiveItem()).toBe item3
pane.activatePreviousItem()
expect(pane.activeItem).toBe item2
expect(pane.getActiveItem()).toBe item2
pane.activateNextItem()
expect(pane.activeItem).toBe item3
expect(pane.getActiveItem()).toBe item3
pane.activateNextItem()
expect(pane.activeItem).toBe item1
expect(pane.getActiveItem()).toBe item1
describe "::activateItemAtIndex(index)", ->
it "activates the item at the given index", ->
pane = new Pane(items: [new Item("A"), new Item("B"), new Item("C")])
[item1, item2, item3] = pane.items
[item1, item2, item3] = pane.getItems()
pane.activateItemAtIndex(2)
expect(pane.activeItem).toBe item3
expect(pane.getActiveItem()).toBe item3
pane.activateItemAtIndex(1)
expect(pane.activeItem).toBe item2
expect(pane.getActiveItem()).toBe item2
pane.activateItemAtIndex(0)
expect(pane.activeItem).toBe item1
expect(pane.getActiveItem()).toBe item1
# Doesn't fail with out-of-bounds indices
pane.activateItemAtIndex(100)
expect(pane.activeItem).toBe item1
expect(pane.getActiveItem()).toBe item1
pane.activateItemAtIndex(-1)
expect(pane.activeItem).toBe item1
expect(pane.getActiveItem()).toBe item1
describe "::destroyItem(item)", ->
[pane, item1, item2, item3] = []
beforeEach ->
pane = new Pane(items: [new Item("A"), new Item("B"), new Item("C")])
[item1, item2, item3] = pane.items
[item1, item2, item3] = pane.getItems()
it "removes the item from the items list", ->
expect(pane.activeItem).toBe item1
it "removes the item from the items list and destroyes it", ->
expect(pane.getActiveItem()).toBe item1
pane.destroyItem(item2)
expect(item2 in pane.items).toBe false
expect(pane.activeItem).toBe item1
expect(item2 in pane.getItems()).toBe false
expect(item2.isDestroyed()).toBe true
expect(pane.getActiveItem()).toBe item1
pane.destroyItem(item1)
expect(item1 in pane.items).toBe false
expect(item1 in pane.getItems()).toBe false
expect(item1.isDestroyed()).toBe true
it "invokes ::onWillDestroyItem() observers before destroying the item", ->
events = []
pane.onWillDestroyItem (event) ->
expect(item2.isDestroyed()).toBe false
events.push(event)
pane.destroyItem(item2)
expect(item2.isDestroyed()).toBe true
expect(events).toEqual [{item: item2, index: 1}]
it "invokes ::onDidRemoveItem() observers", ->
events = []
pane.onDidRemoveItem (event) -> events.push(event)
pane.destroyItem(item2)
expect(events).toEqual [{item: item2, index: 1, destroyed: true}]
describe "when the destroyed item is the active item and is the first item", ->
it "activates the next item", ->
expect(pane.activeItem).toBe item1
expect(pane.getActiveItem()).toBe item1
pane.destroyItem(item1)
expect(pane.activeItem).toBe item2
expect(pane.getActiveItem()).toBe item2
describe "when the destroyed item is the active item and is not the first item", ->
beforeEach ->
pane.activateItem(item2)
it "activates the previous item", ->
expect(pane.activeItem).toBe item2
expect(pane.getActiveItem()).toBe item2
pane.destroyItem(item2)
expect(pane.activeItem).toBe item1
it "emits 'item-removed' with the item, its index, and true indicating the item is being destroyed", ->
pane.on 'item-removed', itemRemovedHandler = jasmine.createSpy("itemRemovedHandler")
pane.destroyItem(item2)
expect(itemRemovedHandler).toHaveBeenCalledWith(item2, 1, true)
expect(pane.getActiveItem()).toBe item1
describe "if the item is modified", ->
itemUri = null
@@ -157,7 +220,7 @@ describe "Pane", ->
pane.destroyItem(item1)
expect(item1.save).toHaveBeenCalled()
expect(item1 in pane.items).toBe false
expect(item1 in pane.getItems()).toBe false
expect(item1.isDestroyed()).toBe true
describe "when the item has no uri", ->
@@ -170,7 +233,7 @@ describe "Pane", ->
expect(atom.showSaveDialogSync).toHaveBeenCalled()
expect(item1.saveAs).toHaveBeenCalledWith("/selected/path")
expect(item1 in pane.items).toBe false
expect(item1 in pane.getItems()).toBe false
expect(item1.isDestroyed()).toBe true
describe "if the [Don't Save] option is selected", ->
@@ -179,7 +242,7 @@ describe "Pane", ->
pane.destroyItem(item1)
expect(item1.save).not.toHaveBeenCalled()
expect(item1 in pane.items).toBe false
expect(item1 in pane.getItems()).toBe false
expect(item1.isDestroyed()).toBe true
describe "if the [Cancel] option is selected", ->
@@ -188,7 +251,7 @@ describe "Pane", ->
pane.destroyItem(item1)
expect(item1.save).not.toHaveBeenCalled()
expect(item1 in pane.items).toBe true
expect(item1 in pane.getItems()).toBe true
expect(item1.isDestroyed()).toBe false
describe "when the last item is destroyed", ->
@@ -197,7 +260,7 @@ describe "Pane", ->
expect(atom.config.get('core.destroyEmptyPanes')).toBe false
pane.destroyItem(item) for item in pane.getItems()
expect(pane.isDestroyed()).toBe false
expect(pane.activeItem).toBeUndefined()
expect(pane.getActiveItem()).toBeUndefined()
expect(-> pane.saveActiveItem()).not.toThrow()
expect(-> pane.saveActiveItemAs()).not.toThrow()
@@ -210,10 +273,10 @@ describe "Pane", ->
describe "::destroyActiveItem()", ->
it "destroys the active item", ->
pane = new Pane(items: [new Item("A"), new Item("B")])
activeItem = pane.activeItem
activeItem = pane.getActiveItem()
pane.destroyActiveItem()
expect(activeItem.isDestroyed()).toBe true
expect(activeItem in pane.items).toBe false
expect(activeItem in pane.getItems()).toBe false
it "does not throw an exception if there are no more items", ->
pane = new Pane
@@ -222,27 +285,40 @@ describe "Pane", ->
describe "::destroyItems()", ->
it "destroys all items", ->
pane = new Pane(items: [new Item("A"), new Item("B"), new Item("C")])
[item1, item2, item3] = pane.items
[item1, item2, item3] = pane.getItems()
pane.destroyItems()
expect(item1.isDestroyed()).toBe true
expect(item2.isDestroyed()).toBe true
expect(item3.isDestroyed()).toBe true
expect(pane.items).toEqual []
expect(pane.getItems()).toEqual []
describe "::observeItems()", ->
it "invokes the observer with all current and future items", ->
pane = new Pane(items: [new Item, new Item])
[item1, item2] = pane.getItems()
observed = []
pane.observeItems (item) -> observed.push(item)
item3 = new Item
pane.addItem(item3)
expect(observed).toEqual [item1, item2, item3]
describe "when an item emits a destroyed event", ->
it "removes it from the list of items", ->
pane = new Pane(items: [new Item("A"), new Item("B"), new Item("C")])
[item1, item2, item3] = pane.items
pane.items[1].destroy()
expect(pane.items).toEqual [item1, item3]
[item1, item2, item3] = pane.getItems()
pane.itemAtIndex(1).destroy()
expect(pane.getItems()).toEqual [item1, item3]
describe "::destroyInactiveItems()", ->
it "destroys all items but the active item", ->
pane = new Pane(items: [new Item("A"), new Item("B"), new Item("C")])
[item1, item2, item3] = pane.items
[item1, item2, item3] = pane.getItems()
pane.activateItem(item2)
pane.destroyInactiveItems()
expect(pane.items).toEqual [item2]
expect(pane.getItems()).toEqual [item2]
describe "::saveActiveItem()", ->
pane = null
@@ -253,30 +329,30 @@ describe "Pane", ->
describe "when the active item has a uri", ->
beforeEach ->
pane.activeItem.uri = "test"
pane.getActiveItem().uri = "test"
describe "when the active item has a save method", ->
it "saves the current item", ->
pane.activeItem.save = jasmine.createSpy("save")
pane.getActiveItem().save = jasmine.createSpy("save")
pane.saveActiveItem()
expect(pane.activeItem.save).toHaveBeenCalled()
expect(pane.getActiveItem().save).toHaveBeenCalled()
describe "when the current item has no save method", ->
it "does nothing", ->
expect(pane.activeItem.save).toBeUndefined()
expect(pane.getActiveItem().save).toBeUndefined()
pane.saveActiveItem()
describe "when the current item has no uri", ->
describe "when the current item has a saveAs method", ->
it "opens a save dialog and saves the current item as the selected path", ->
pane.activeItem.saveAs = jasmine.createSpy("saveAs")
pane.getActiveItem().saveAs = jasmine.createSpy("saveAs")
pane.saveActiveItem()
expect(atom.showSaveDialogSync).toHaveBeenCalled()
expect(pane.activeItem.saveAs).toHaveBeenCalledWith('/selected/path')
expect(pane.getActiveItem().saveAs).toHaveBeenCalledWith('/selected/path')
describe "when the current item has no saveAs method", ->
it "does nothing", ->
expect(pane.activeItem.saveAs).toBeUndefined()
expect(pane.getActiveItem().saveAs).toBeUndefined()
pane.saveActiveItem()
expect(atom.showSaveDialogSync).not.toHaveBeenCalled()
@@ -289,22 +365,22 @@ describe "Pane", ->
describe "when the current item has a saveAs method", ->
it "opens the save dialog and calls saveAs on the item with the selected path", ->
pane.activeItem.path = __filename
pane.activeItem.saveAs = jasmine.createSpy("saveAs")
pane.getActiveItem().path = __filename
pane.getActiveItem().saveAs = jasmine.createSpy("saveAs")
pane.saveActiveItemAs()
expect(atom.showSaveDialogSync).toHaveBeenCalledWith(__filename)
expect(pane.activeItem.saveAs).toHaveBeenCalledWith('/selected/path')
expect(pane.getActiveItem().saveAs).toHaveBeenCalledWith('/selected/path')
describe "when the current item does not have a saveAs method", ->
it "does nothing", ->
expect(pane.activeItem.saveAs).toBeUndefined()
expect(pane.getActiveItem().saveAs).toBeUndefined()
pane.saveActiveItemAs()
expect(atom.showSaveDialogSync).not.toHaveBeenCalled()
describe "::itemForUri(uri)", ->
it "returns the item for which a call to .getUri() returns the given uri", ->
pane = new Pane(items: [new Item("A"), new Item("B"), new Item("C"), new Item("D")])
[item1, item2, item3] = pane.items
[item1, item2, item3] = pane.getItems()
item1.uri = "a"
item2.uri = "b"
expect(pane.itemForUri("a")).toBe item1
@@ -312,24 +388,32 @@ describe "Pane", ->
expect(pane.itemForUri("bogus")).toBeUndefined()
describe "::moveItem(item, index)", ->
it "moves the item to the given index and emits an 'item-moved' event with the item and its new index", ->
pane = new Pane(items: [new Item("A"), new Item("B"), new Item("C"), new Item("D")])
[item1, item2, item3, item4] = pane.items
pane.on 'item-moved', itemMovedHandler = jasmine.createSpy("itemMovedHandler")
[pane, item1, item2, item3, item4] = []
beforeEach ->
pane = new Pane(items: [new Item("A"), new Item("B"), new Item("C"), new Item("D")])
[item1, item2, item3, item4] = pane.getItems()
it "moves the item to the given index and invokes ::onDidMoveItem observers", ->
pane.moveItem(item1, 2)
expect(pane.getItems()).toEqual [item2, item3, item1, item4]
expect(itemMovedHandler).toHaveBeenCalledWith(item1, 2)
itemMovedHandler.reset()
pane.moveItem(item2, 3)
expect(pane.getItems()).toEqual [item3, item1, item4, item2]
expect(itemMovedHandler).toHaveBeenCalledWith(item2, 3)
itemMovedHandler.reset()
pane.moveItem(item2, 1)
expect(pane.getItems()).toEqual [item3, item2, item1, item4]
expect(itemMovedHandler).toHaveBeenCalledWith(item2, 1)
it "invokes ::onDidMoveItem() observers", ->
events = []
pane.onDidMoveItem (event) -> events.push(event)
pane.moveItem(item1, 2)
pane.moveItem(item2, 3)
expect(events).toEqual [
{item: item1, oldIndex: 0, newIndex: 2}
{item: item2, oldIndex: 0, newIndex: 3}
]
describe "::moveItemToPane(item, pane, index)", ->
[container, pane1, pane2] = []
@@ -339,13 +423,20 @@ describe "Pane", ->
pane1 = new Pane(items: [new Item("A"), new Item("B"), new Item("C")])
container = new PaneContainer(root: pane1)
pane2 = pane1.splitRight(items: [new Item("D"), new Item("E")])
[item1, item2, item3] = pane1.items
[item4, item5] = pane2.items
[item1, item2, item3] = pane1.getItems()
[item4, item5] = pane2.getItems()
it "moves the item to the given pane at the given index", ->
pane1.moveItemToPane(item2, pane2, 1)
expect(pane1.items).toEqual [item1, item3]
expect(pane2.items).toEqual [item4, item2, item5]
expect(pane1.getItems()).toEqual [item1, item3]
expect(pane2.getItems()).toEqual [item4, item2, item5]
it "invokes ::onDidRemoveItem() observers", ->
events = []
pane1.onDidRemoveItem (event) -> events.push(event)
pane1.moveItemToPane(item2, pane2, 1)
expect(events).toEqual [{item: item2, index: 1, destroyed: false}]
describe "when the moved item the last item in the source pane", ->
beforeEach ->
@@ -368,22 +459,27 @@ describe "Pane", ->
[pane1, container] = []
beforeEach ->
pane1 = new Pane(items: ["A"])
pane1 = new Pane(items: [new Item("A")])
container = new PaneContainer(root: pane1)
describe "::splitLeft(params)", ->
describe "when the parent is the container root", ->
it "replaces itself with a row and inserts a new pane to the left of itself", ->
pane2 = pane1.splitLeft(items: ["B"])
pane3 = pane1.splitLeft(items: ["C"])
pane2 = pane1.splitLeft(items: [new Item("B")])
pane3 = pane1.splitLeft(items: [new Item("C")])
expect(container.root.orientation).toBe 'horizontal'
expect(container.root.children).toEqual [pane2, pane3, pane1]
describe "when `copyActiveItem: true` is passed in the params", ->
it "duplicates the active item", ->
pane2 = pane1.splitLeft(copyActiveItem: true)
expect(pane2.getActiveItem()).toEqual pane1.getActiveItem()
describe "when the parent is a column", ->
it "replaces itself with a row and inserts a new pane to the left of itself", ->
pane1.splitDown()
pane2 = pane1.splitLeft(items: ["B"])
pane3 = pane1.splitLeft(items: ["C"])
pane2 = pane1.splitLeft(items: [new Item("B")])
pane3 = pane1.splitLeft(items: [new Item("C")])
row = container.root.children[0]
expect(row.orientation).toBe 'horizontal'
expect(row.children).toEqual [pane2, pane3, pane1]
@@ -391,16 +487,21 @@ describe "Pane", ->
describe "::splitRight(params)", ->
describe "when the parent is the container root", ->
it "replaces itself with a row and inserts a new pane to the right of itself", ->
pane2 = pane1.splitRight(items: ["B"])
pane3 = pane1.splitRight(items: ["C"])
pane2 = pane1.splitRight(items: [new Item("B")])
pane3 = pane1.splitRight(items: [new Item("C")])
expect(container.root.orientation).toBe 'horizontal'
expect(container.root.children).toEqual [pane1, pane3, pane2]
describe "when `copyActiveItem: true` is passed in the params", ->
it "duplicates the active item", ->
pane2 = pane1.splitRight(copyActiveItem: true)
expect(pane2.getActiveItem()).toEqual pane1.getActiveItem()
describe "when the parent is a column", ->
it "replaces itself with a row and inserts a new pane to the right of itself", ->
pane1.splitDown()
pane2 = pane1.splitRight(items: ["B"])
pane3 = pane1.splitRight(items: ["C"])
pane2 = pane1.splitRight(items: [new Item("B")])
pane3 = pane1.splitRight(items: [new Item("C")])
row = container.root.children[0]
expect(row.orientation).toBe 'horizontal'
expect(row.children).toEqual [pane1, pane3, pane2]
@@ -408,16 +509,21 @@ describe "Pane", ->
describe "::splitUp(params)", ->
describe "when the parent is the container root", ->
it "replaces itself with a column and inserts a new pane above itself", ->
pane2 = pane1.splitUp(items: ["B"])
pane3 = pane1.splitUp(items: ["C"])
pane2 = pane1.splitUp(items: [new Item("B")])
pane3 = pane1.splitUp(items: [new Item("C")])
expect(container.root.orientation).toBe 'vertical'
expect(container.root.children).toEqual [pane2, pane3, pane1]
describe "when `copyActiveItem: true` is passed in the params", ->
it "duplicates the active item", ->
pane2 = pane1.splitUp(copyActiveItem: true)
expect(pane2.getActiveItem()).toEqual pane1.getActiveItem()
describe "when the parent is a row", ->
it "replaces itself with a column and inserts a new pane above itself", ->
pane1.splitRight()
pane2 = pane1.splitUp(items: ["B"])
pane3 = pane1.splitUp(items: ["C"])
pane2 = pane1.splitUp(items: [new Item("B")])
pane3 = pane1.splitUp(items: [new Item("C")])
column = container.root.children[0]
expect(column.orientation).toBe 'vertical'
expect(column.children).toEqual [pane2, pane3, pane1]
@@ -425,16 +531,21 @@ describe "Pane", ->
describe "::splitDown(params)", ->
describe "when the parent is the container root", ->
it "replaces itself with a column and inserts a new pane below itself", ->
pane2 = pane1.splitDown(items: ["B"])
pane3 = pane1.splitDown(items: ["C"])
pane2 = pane1.splitDown(items: [new Item("B")])
pane3 = pane1.splitDown(items: [new Item("C")])
expect(container.root.orientation).toBe 'vertical'
expect(container.root.children).toEqual [pane1, pane3, pane2]
describe "when `copyActiveItem: true` is passed in the params", ->
it "duplicates the active item", ->
pane2 = pane1.splitDown(copyActiveItem: true)
expect(pane2.getActiveItem()).toEqual pane1.getActiveItem()
describe "when the parent is a row", ->
it "replaces itself with a column and inserts a new pane below itself", ->
pane1.splitRight()
pane2 = pane1.splitDown(items: ["B"])
pane3 = pane1.splitDown(items: ["C"])
pane2 = pane1.splitDown(items: [new Item("B")])
pane3 = pane1.splitDown(items: [new Item("C")])
column = container.root.children[0]
expect(column.orientation).toBe 'vertical'
expect(column.children).toEqual [pane1, pane3, pane2]
@@ -455,7 +566,7 @@ describe "Pane", ->
pane2 = pane1.splitRight()
it "destroys the pane's destroyable items", ->
[item1, item2] = pane1.items
[item1, item2] = pane1.getItems()
pane1.destroy()
expect(item1.isDestroyed()).toBe true
expect(item2.isDestroyed()).toBe true
@@ -493,12 +604,12 @@ describe "Pane", ->
it "can serialize and deserialize the pane and all its items", ->
newPane = pane.testSerialization()
expect(newPane.items).toEqual pane.items
expect(newPane.getItems()).toEqual pane.getItems()
it "restores the active item on deserialization", ->
pane.activateItemAtIndex(1)
newPane = pane.testSerialization()
expect(newPane.activeItem).toEqual newPane.items[1]
expect(newPane.getActiveItem()).toEqual newPane.itemAtIndex(1)
it "does not include items that cannot be deserialized", ->
spyOn(console, 'warn')
@@ -506,8 +617,8 @@ describe "Pane", ->
pane.activateItem(unserializable)
newPane = pane.testSerialization()
expect(newPane.activeItem).toEqual pane.items[0]
expect(newPane.items.length).toBe pane.items.length - 1
expect(newPane.getActiveItem()).toEqual pane.itemAtIndex(0)
expect(newPane.getItems().length).toBe pane.getItems().length - 1
it "includes the pane's focus state in the serialized state", ->
pane.focus()
+48 -17
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)
@@ -29,7 +35,7 @@ describe "PaneView", ->
runs ->
pane = container.getRoot()
paneModel = pane.model
paneModel = pane.getModel()
paneModel.addItems([view1, editor1, view2, editor2])
afterEach ->
@@ -37,7 +43,7 @@ describe "PaneView", ->
describe "when the active pane item changes", ->
it "hides all item views except the active one", ->
expect(pane.activeItem).toBe view1
expect(pane.getActiveItem()).toBe view1
expect(view1.css('display')).not.toBe 'none'
pane.activateItem(view2)
@@ -48,7 +54,7 @@ describe "PaneView", ->
itemChangedHandler = jasmine.createSpy("itemChangedHandler")
container.on 'pane:active-item-changed', itemChangedHandler
expect(pane.activeItem).toBe view1
expect(pane.getActiveItem()).toBe view1
paneModel.activateItem(view2)
paneModel.activateItem(view2)
@@ -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.activeItem).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", ->
@@ -246,7 +277,7 @@ describe "PaneView", ->
it "transfers focus to the active view", ->
focusHandler = jasmine.createSpy("focusHandler")
pane.activeItem.on 'focus', focusHandler
pane.getActiveItem().on 'focus', focusHandler
pane.focus()
expect(focusHandler).toHaveBeenCalled()
@@ -259,7 +290,7 @@ describe "PaneView", ->
describe "when a pane is split", ->
it "builds the appropriate pane-row and pane-column views", ->
pane1 = pane
pane1Model = pane.model
pane1Model = pane.getModel()
pane.activateItem(editor1)
pane2Model = pane1Model.splitRight(items: [pane1Model.copyActiveItem()])
+5
Ver Arquivo
@@ -190,6 +190,11 @@ describe "Project", ->
expect(atom.project.getPath()?).toBeFalsy()
expect(atom.project.getRootDirectory()?).toBeFalsy()
it "normalizes the path to remove consecutive slashes, ., and .. segments", ->
atom.project.setPath("#{require.resolve('./fixtures/dir/a')}#{path.sep}b#{path.sep}#{path.sep}..")
expect(atom.project.getPath()).toEqual path.dirname(require.resolve('./fixtures/dir/a'))
expect(atom.project.getRootDirectory().path).toEqual path.dirname(require.resolve('./fixtures/dir/a'))
describe ".replace()", ->
[filePath, commentFilePath, sampleContent, sampleCommentContent] = []
+6 -6
Ver Arquivo
@@ -35,7 +35,7 @@ describe "Editor", ->
logLines()
throw new Error("Invalid buffer row #{actualBufferRow} for screen row #{screenRow}", )
actualScreenLine = editor.lineForScreenRow(screenRow)
actualScreenLine = editor.tokenizedLineForScreenRow(screenRow)
unless actualScreenLine.text is referenceScreenLine.text
logLines()
throw new Error("Invalid line text at screen row #{screenRow}")
@@ -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,11 +79,11 @@ describe "Editor", ->
text
getReferenceScreenLines = ->
if editor.getSoftWrap()
if editor.isSoftWrapped()
screenLines = []
bufferRows = []
for bufferRow in [0..tokenizedBuffer.getLastRow()]
for screenLine in softWrapLine(tokenizedBuffer.lineForScreenRow(bufferRow))
for screenLine in softWrapLine(tokenizedBuffer.tokenizedLineForRow(bufferRow))
screenLines.push(screenLine)
bufferRows.push(bufferRow)
else
+3 -3
Ver Arquivo
@@ -6,7 +6,7 @@ describe "Selection", ->
beforeEach ->
buffer = atom.project.bufferForPathSync('sample.js')
editor = new Editor(buffer: buffer, tabLength: 2)
selection = editor.getSelection()
selection = editor.getLastSelection()
afterEach ->
buffer.destroy()
@@ -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()
+13 -4
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)
@@ -28,7 +29,7 @@ atom.keymaps.loadBundledKeymaps()
keyBindingsToRestore = atom.keymaps.getKeyBindings()
$(window).on 'core:close', -> window.close()
$(window).on 'unload', ->
$(window).on 'beforeunload', ->
atom.storeWindowDimensions()
atom.saveSync()
$('html,body').css('overflow', 'auto')
@@ -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 = {}
@@ -95,7 +97,6 @@ beforeEach ->
config.set "editor.autoIndent", false
config.set "core.disabledPackages", ["package-that-throws-an-exception",
"package-with-broken-package-json", "package-with-broken-keymap"]
config.set "core.useReactEditor", true
config.save.reset()
atom.config = config
@@ -120,6 +121,8 @@ beforeEach ->
addCustomMatchers(this)
afterEach ->
atom.commands.clear()
atom.packages.deactivatePackages()
atom.menu.template = []
@@ -138,8 +141,7 @@ afterEach ->
jasmine.unspy(atom, 'saveSync')
ensureNoPathSubscriptions()
atom.syntax.off()
ensureNoDeprecatedFunctionsCalled() if isCoreSpec
atom.syntax.clearObservers()
waits(0) # yield to ui thread to make screen update more frequently
ensureNoPathSubscriptions = ->
@@ -211,6 +213,13 @@ addCustomMatchers = (spec) ->
element = element.get(0) if element.jquery
element.webkitMatchesSelector(":focus") or element.querySelector(":focus")
toShow: ->
notText = if @isNot then " not" else ""
element = @actual
element = element.get(0) if element.jquery
@message = -> return "Expected element '#{element}' or its descendants #{notText} to show."
element.style.display in ['block', 'inline-block', 'static', 'fixed']
window.keyIdentifierForKey = (key) ->
if key.length > 1 # named key
key
+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
+84 -11
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 ->
@@ -247,6 +247,21 @@ describe "ThemeManager", ->
# from within the theme itself
expect($(".editor").css("background-color")).toBe "rgb(0, 152, 255)"
describe "theme classes on the workspace", ->
it 'adds theme-* classes to the workspace for each active theme', ->
expect(atom.workspaceView).toHaveClass 'theme-atom-dark-ui'
themeManager.onDidReloadAll reloadHandler = jasmine.createSpy()
atom.config.set('core.themes', ['theme-with-ui-variables'])
waitsFor ->
reloadHandler.callCount > 0
runs ->
# `theme-` twice as it prefixes the name with `theme-`
expect(atom.workspaceView).toHaveClass 'theme-theme-with-ui-variables'
expect(atom.workspaceView).not.toHaveClass 'theme-atom-dark-ui'
describe "when the user stylesheet changes", ->
it "reloads it", ->
[stylesheetRemovedHandler, stylesheetAddedHandler, stylesheetsChangedHandler] = []
@@ -258,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'
@@ -301,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()
@@ -310,3 +327,59 @@ describe "ThemeManager", ->
runs ->
expect(console.warn.callCount).toBe 1
expect(console.warn.argsForCall[0][0].length).toBeGreaterThan 0
describe "when in safe mode", ->
beforeEach ->
themeManager = new ThemeManager({packageManager: atom.packages, resourcePath, configDirPath, safeMode: true})
describe 'when the enabled UI and syntax themes are bundled with Atom', ->
beforeEach ->
atom.config.set('core.themes', ['atom-light-ui', 'atom-dark-syntax'])
waitsForPromise ->
themeManager.activateThemes()
it 'uses the enabled themes', ->
activeThemeNames = themeManager.getActiveNames()
expect(activeThemeNames.length).toBe(2)
expect(activeThemeNames).toContain('atom-light-ui')
expect(activeThemeNames).toContain('atom-dark-syntax')
describe 'when the enabled UI and syntax themes are not bundled with Atom', ->
beforeEach ->
atom.config.set('core.themes', ['installed-dark-ui', 'installed-dark-syntax'])
waitsForPromise ->
themeManager.activateThemes()
it 'uses the default dark UI and syntax themes', ->
activeThemeNames = themeManager.getActiveNames()
expect(activeThemeNames.length).toBe(2)
expect(activeThemeNames).toContain('atom-dark-ui')
expect(activeThemeNames).toContain('atom-dark-syntax')
describe 'when the enabled UI theme is not bundled with Atom', ->
beforeEach ->
atom.config.set('core.themes', ['installed-dark-ui', 'atom-light-syntax'])
waitsForPromise ->
themeManager.activateThemes()
it 'uses the default dark UI theme', ->
activeThemeNames = themeManager.getActiveNames()
expect(activeThemeNames.length).toBe(2)
expect(activeThemeNames).toContain('atom-dark-ui')
expect(activeThemeNames).toContain('atom-light-syntax')
describe 'when the enabled syntax theme is not bundled with Atom', ->
beforeEach ->
atom.config.set('core.themes', ['atom-light-ui', 'installed-dark-syntax'])
waitsForPromise ->
themeManager.activateThemes()
it 'uses the default dark syntax theme', ->
activeThemeNames = themeManager.getActiveNames()
expect(activeThemeNames.length).toBe(2)
expect(activeThemeNames).toContain('atom-light-ui')
expect(activeThemeNames).toContain('atom-dark-syntax')
+1 -1
Ver Arquivo
@@ -18,7 +18,7 @@ class TimeReporter extends jasmine.Reporter
log ?= (line) -> console.log(line)
log "Longest running suites:"
suites = _.map(window.timedSuites, (key, value) -> [value, key])
for suite in _.sortBy(suites, (suite) => -suite[1])[0...number]
for suite in _.sortBy(suites, (suite) -> -suite[1])[0...number]
time = Math.round(suite[1] / 100) / 10
log " #{suite[0]} (#{time}s)"
undefined
+221 -156
Ver Arquivo
@@ -1,4 +1,5 @@
TokenizedBuffer = require '../src/tokenized-buffer'
TextBuffer = require 'text-buffer'
_ = require 'underscore-plus'
describe "TokenizedBuffer", ->
@@ -12,6 +13,9 @@ describe "TokenizedBuffer", ->
waitsForPromise ->
atom.packages.activatePackage('language-javascript')
afterEach ->
tokenizedBuffer?.destroy()
startTokenizing = (tokenizedBuffer) ->
tokenizedBuffer.setVisible(true)
@@ -37,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()
@@ -45,38 +49,38 @@ describe "TokenizedBuffer", ->
describe "on construction", ->
it "initially creates un-tokenized screen lines, then tokenizes lines chunk at a time in the background", ->
line0 = tokenizedBuffer.lineForScreenRow(0)
line0 = tokenizedBuffer.tokenizedLineForRow(0)
expect(line0.tokens.length).toBe 1
expect(line0.tokens[0]).toEqual(value: line0.text, scopes: ['source.js'])
line11 = tokenizedBuffer.lineForScreenRow(11)
line11 = tokenizedBuffer.tokenizedLineForRow(11)
expect(line11.tokens.length).toBe 2
expect(line11.tokens[0]).toEqual(value: " ", scopes: ['source.js'], isAtomic: true)
expect(line11.tokens[1]).toEqual(value: "return sort(Array.apply(this, arguments));", scopes: ['source.js'])
# background tokenization has not begun
expect(tokenizedBuffer.lineForScreenRow(0).ruleStack).toBeUndefined()
expect(tokenizedBuffer.tokenizedLineForRow(0).ruleStack).toBeUndefined()
# tokenize chunk 1
advanceClock()
expect(tokenizedBuffer.lineForScreenRow(0).ruleStack?).toBeTruthy()
expect(tokenizedBuffer.lineForScreenRow(4).ruleStack?).toBeTruthy()
expect(tokenizedBuffer.lineForScreenRow(5).ruleStack?).toBeFalsy()
expect(tokenizedBuffer.tokenizedLineForRow(0).ruleStack?).toBeTruthy()
expect(tokenizedBuffer.tokenizedLineForRow(4).ruleStack?).toBeTruthy()
expect(tokenizedBuffer.tokenizedLineForRow(5).ruleStack?).toBeFalsy()
expect(changeHandler).toHaveBeenCalledWith(start: 0, end: 4, delta: 0)
changeHandler.reset()
# tokenize chunk 2
advanceClock()
expect(tokenizedBuffer.lineForScreenRow(5).ruleStack?).toBeTruthy()
expect(tokenizedBuffer.lineForScreenRow(9).ruleStack?).toBeTruthy()
expect(tokenizedBuffer.lineForScreenRow(10).ruleStack?).toBeFalsy()
expect(tokenizedBuffer.tokenizedLineForRow(5).ruleStack?).toBeTruthy()
expect(tokenizedBuffer.tokenizedLineForRow(9).ruleStack?).toBeTruthy()
expect(tokenizedBuffer.tokenizedLineForRow(10).ruleStack?).toBeFalsy()
expect(changeHandler).toHaveBeenCalledWith(start: 5, end: 9, delta: 0)
changeHandler.reset()
# tokenize last chunk
advanceClock()
expect(tokenizedBuffer.lineForScreenRow(10).ruleStack?).toBeTruthy()
expect(tokenizedBuffer.lineForScreenRow(12).ruleStack?).toBeTruthy()
expect(tokenizedBuffer.tokenizedLineForRow(10).ruleStack?).toBeTruthy()
expect(tokenizedBuffer.tokenizedLineForRow(12).ruleStack?).toBeTruthy()
expect(changeHandler).toHaveBeenCalledWith(start: 10, end: 12, delta: 0)
describe "when the buffer is partially tokenized", ->
@@ -130,8 +134,8 @@ describe "TokenizedBuffer", ->
expect(tokenizedBuffer.firstInvalidRow()).toBe 5
buffer.setTextInRange([[6, 0], [7, 0]], "\n\n\n")
expect(tokenizedBuffer.lineForScreenRow(6).ruleStack?).toBeFalsy()
expect(tokenizedBuffer.lineForScreenRow(7).ruleStack?).toBeFalsy()
expect(tokenizedBuffer.tokenizedLineForRow(6).ruleStack?).toBeFalsy()
expect(tokenizedBuffer.tokenizedLineForRow(7).ruleStack?).toBeFalsy()
changeHandler.reset()
expect(tokenizedBuffer.firstInvalidRow()).toBe 5
@@ -145,10 +149,10 @@ describe "TokenizedBuffer", ->
it "updates tokens to reflect the change", ->
buffer.setTextInRange([[0, 0], [2, 0]], "foo()\n7\n")
expect(tokenizedBuffer.lineForScreenRow(0).tokens[1]).toEqual(value: '(', scopes: ['source.js', 'meta.brace.round.js'])
expect(tokenizedBuffer.lineForScreenRow(1).tokens[0]).toEqual(value: '7', scopes: ['source.js', 'constant.numeric.js'])
expect(tokenizedBuffer.tokenizedLineForRow(0).tokens[1]).toEqual(value: '(', scopes: ['source.js', 'meta.brace.round.js'])
expect(tokenizedBuffer.tokenizedLineForRow(1).tokens[0]).toEqual(value: '7', scopes: ['source.js', 'constant.numeric.js'])
# line 2 is unchanged
expect(tokenizedBuffer.lineForScreenRow(2).tokens[2]).toEqual(value: 'if', scopes: ['source.js', 'keyword.control.js'])
expect(tokenizedBuffer.tokenizedLineForRow(2).tokens[2]).toEqual(value: 'if', scopes: ['source.js', 'keyword.control.js'])
expect(changeHandler).toHaveBeenCalled()
[event] = changeHandler.argsForCall[0]
@@ -160,7 +164,7 @@ describe "TokenizedBuffer", ->
buffer.insert([5, 30], '/* */')
changeHandler.reset()
buffer.insert([2, 0], '/*')
expect(tokenizedBuffer.lineForScreenRow(3).tokens[0].scopes).toEqual ['source.js']
expect(tokenizedBuffer.tokenizedLineForRow(3).tokens[0].scopes).toEqual ['source.js']
expect(changeHandler).toHaveBeenCalled()
[event] = changeHandler.argsForCall[0]
delete event.bufferChange
@@ -168,9 +172,9 @@ describe "TokenizedBuffer", ->
changeHandler.reset()
advanceClock()
expect(tokenizedBuffer.lineForScreenRow(3).tokens[0].scopes).toEqual ['source.js', 'comment.block.js']
expect(tokenizedBuffer.lineForScreenRow(4).tokens[0].scopes).toEqual ['source.js', 'comment.block.js']
expect(tokenizedBuffer.lineForScreenRow(5).tokens[0].scopes).toEqual ['source.js', 'comment.block.js']
expect(tokenizedBuffer.tokenizedLineForRow(3).tokens[0].scopes).toEqual ['source.js', 'comment.block.js']
expect(tokenizedBuffer.tokenizedLineForRow(4).tokens[0].scopes).toEqual ['source.js', 'comment.block.js']
expect(tokenizedBuffer.tokenizedLineForRow(5).tokens[0].scopes).toEqual ['source.js', 'comment.block.js']
expect(changeHandler).toHaveBeenCalled()
[event] = changeHandler.argsForCall[0]
delete event.bufferChange
@@ -181,23 +185,23 @@ describe "TokenizedBuffer", ->
buffer.insert([5, 0], '*/')
buffer.insert([1, 0], 'var ')
expect(tokenizedBuffer.lineForScreenRow(1).tokens[0].scopes).toEqual ['source.js', 'comment.block.js']
expect(tokenizedBuffer.tokenizedLineForRow(1).tokens[0].scopes).toEqual ['source.js', 'comment.block.js']
describe "when lines are both updated and removed", ->
it "updates tokens to reflect the change", ->
buffer.setTextInRange([[1, 0], [3, 0]], "foo()")
# previous line 0 remains
expect(tokenizedBuffer.lineForScreenRow(0).tokens[0]).toEqual(value: 'var', scopes: ['source.js', 'storage.modifier.js'])
expect(tokenizedBuffer.tokenizedLineForRow(0).tokens[0]).toEqual(value: 'var', scopes: ['source.js', 'storage.modifier.js'])
# previous line 3 should be combined with input to form line 1
expect(tokenizedBuffer.lineForScreenRow(1).tokens[0]).toEqual(value: 'foo', scopes: ['source.js'])
expect(tokenizedBuffer.lineForScreenRow(1).tokens[6]).toEqual(value: '=', scopes: ['source.js', 'keyword.operator.js'])
expect(tokenizedBuffer.tokenizedLineForRow(1).tokens[0]).toEqual(value: 'foo', scopes: ['source.js'])
expect(tokenizedBuffer.tokenizedLineForRow(1).tokens[6]).toEqual(value: '=', scopes: ['source.js', 'keyword.operator.js'])
# lines below deleted regions should be shifted upward
expect(tokenizedBuffer.lineForScreenRow(2).tokens[2]).toEqual(value: 'while', scopes: ['source.js', 'keyword.control.js'])
expect(tokenizedBuffer.lineForScreenRow(3).tokens[4]).toEqual(value: '=', scopes: ['source.js', 'keyword.operator.js'])
expect(tokenizedBuffer.lineForScreenRow(4).tokens[4]).toEqual(value: '<', scopes: ['source.js', 'keyword.operator.js'])
expect(tokenizedBuffer.tokenizedLineForRow(2).tokens[2]).toEqual(value: 'while', scopes: ['source.js', 'keyword.control.js'])
expect(tokenizedBuffer.tokenizedLineForRow(3).tokens[4]).toEqual(value: '=', scopes: ['source.js', 'keyword.operator.js'])
expect(tokenizedBuffer.tokenizedLineForRow(4).tokens[4]).toEqual(value: '<', scopes: ['source.js', 'keyword.operator.js'])
expect(changeHandler).toHaveBeenCalled()
[event] = changeHandler.argsForCall[0]
@@ -210,8 +214,8 @@ describe "TokenizedBuffer", ->
changeHandler.reset()
buffer.setTextInRange([[2, 0], [3, 0]], '/*')
expect(tokenizedBuffer.lineForScreenRow(2).tokens[0].scopes).toEqual ['source.js', 'comment.block.js', 'punctuation.definition.comment.js']
expect(tokenizedBuffer.lineForScreenRow(3).tokens[0].scopes).toEqual ['source.js']
expect(tokenizedBuffer.tokenizedLineForRow(2).tokens[0].scopes).toEqual ['source.js', 'comment.block.js', 'punctuation.definition.comment.js']
expect(tokenizedBuffer.tokenizedLineForRow(3).tokens[0].scopes).toEqual ['source.js']
expect(changeHandler).toHaveBeenCalled()
[event] = changeHandler.argsForCall[0]
delete event.bufferChange
@@ -219,8 +223,8 @@ describe "TokenizedBuffer", ->
changeHandler.reset()
advanceClock()
expect(tokenizedBuffer.lineForScreenRow(3).tokens[0].scopes).toEqual ['source.js', 'comment.block.js']
expect(tokenizedBuffer.lineForScreenRow(4).tokens[0].scopes).toEqual ['source.js', 'comment.block.js']
expect(tokenizedBuffer.tokenizedLineForRow(3).tokens[0].scopes).toEqual ['source.js', 'comment.block.js']
expect(tokenizedBuffer.tokenizedLineForRow(4).tokens[0].scopes).toEqual ['source.js', 'comment.block.js']
expect(changeHandler).toHaveBeenCalled()
[event] = changeHandler.argsForCall[0]
delete event.bufferChange
@@ -231,19 +235,19 @@ describe "TokenizedBuffer", ->
buffer.setTextInRange([[1, 0], [2, 0]], "foo()\nbar()\nbaz()\nquux()")
# previous line 0 remains
expect(tokenizedBuffer.lineForScreenRow(0).tokens[0]).toEqual( value: 'var', scopes: ['source.js', 'storage.modifier.js'])
expect(tokenizedBuffer.tokenizedLineForRow(0).tokens[0]).toEqual( value: 'var', scopes: ['source.js', 'storage.modifier.js'])
# 3 new lines inserted
expect(tokenizedBuffer.lineForScreenRow(1).tokens[0]).toEqual(value: 'foo', scopes: ['source.js'])
expect(tokenizedBuffer.lineForScreenRow(2).tokens[0]).toEqual(value: 'bar', scopes: ['source.js'])
expect(tokenizedBuffer.lineForScreenRow(3).tokens[0]).toEqual(value: 'baz', scopes: ['source.js'])
expect(tokenizedBuffer.tokenizedLineForRow(1).tokens[0]).toEqual(value: 'foo', scopes: ['source.js'])
expect(tokenizedBuffer.tokenizedLineForRow(2).tokens[0]).toEqual(value: 'bar', scopes: ['source.js'])
expect(tokenizedBuffer.tokenizedLineForRow(3).tokens[0]).toEqual(value: 'baz', scopes: ['source.js'])
# previous line 2 is joined with quux() on line 4
expect(tokenizedBuffer.lineForScreenRow(4).tokens[0]).toEqual(value: 'quux', scopes: ['source.js'])
expect(tokenizedBuffer.lineForScreenRow(4).tokens[4]).toEqual(value: 'if', scopes: ['source.js', 'keyword.control.js'])
expect(tokenizedBuffer.tokenizedLineForRow(4).tokens[0]).toEqual(value: 'quux', scopes: ['source.js'])
expect(tokenizedBuffer.tokenizedLineForRow(4).tokens[4]).toEqual(value: 'if', scopes: ['source.js', 'keyword.control.js'])
# previous line 3 is pushed down to become line 5
expect(tokenizedBuffer.lineForScreenRow(5).tokens[4]).toEqual(value: '=', scopes: ['source.js', 'keyword.operator.js'])
expect(tokenizedBuffer.tokenizedLineForRow(5).tokens[4]).toEqual(value: '=', scopes: ['source.js', 'keyword.operator.js'])
expect(changeHandler).toHaveBeenCalled()
[event] = changeHandler.argsForCall[0]
@@ -260,17 +264,17 @@ describe "TokenizedBuffer", ->
[event] = changeHandler.argsForCall[0]
delete event.bufferChange
expect(event).toEqual(start: 2, end: 2, delta: 2)
expect(tokenizedBuffer.lineForScreenRow(2).tokens[0].scopes).toEqual ['source.js', 'comment.block.js', 'punctuation.definition.comment.js']
expect(tokenizedBuffer.lineForScreenRow(3).tokens[0].scopes).toEqual ['source.js', 'comment.block.js']
expect(tokenizedBuffer.lineForScreenRow(4).tokens[0].scopes).toEqual ['source.js', 'comment.block.js']
expect(tokenizedBuffer.lineForScreenRow(5).tokens[0].scopes).toEqual ['source.js']
expect(tokenizedBuffer.tokenizedLineForRow(2).tokens[0].scopes).toEqual ['source.js', 'comment.block.js', 'punctuation.definition.comment.js']
expect(tokenizedBuffer.tokenizedLineForRow(3).tokens[0].scopes).toEqual ['source.js', 'comment.block.js']
expect(tokenizedBuffer.tokenizedLineForRow(4).tokens[0].scopes).toEqual ['source.js', 'comment.block.js']
expect(tokenizedBuffer.tokenizedLineForRow(5).tokens[0].scopes).toEqual ['source.js']
changeHandler.reset()
advanceClock() # tokenize invalidated lines in background
expect(tokenizedBuffer.lineForScreenRow(5).tokens[0].scopes).toEqual ['source.js', 'comment.block.js']
expect(tokenizedBuffer.lineForScreenRow(6).tokens[0].scopes).toEqual ['source.js', 'comment.block.js']
expect(tokenizedBuffer.lineForScreenRow(7).tokens[0].scopes).toEqual ['source.js', 'comment.block.js']
expect(tokenizedBuffer.lineForScreenRow(8).tokens[0].scopes).not.toBe ['source.js', 'comment.block.js']
expect(tokenizedBuffer.tokenizedLineForRow(5).tokens[0].scopes).toEqual ['source.js', 'comment.block.js']
expect(tokenizedBuffer.tokenizedLineForRow(6).tokens[0].scopes).toEqual ['source.js', 'comment.block.js']
expect(tokenizedBuffer.tokenizedLineForRow(7).tokens[0].scopes).toEqual ['source.js', 'comment.block.js']
expect(tokenizedBuffer.tokenizedLineForRow(8).tokens[0].scopes).not.toBe ['source.js', 'comment.block.js']
expect(changeHandler).toHaveBeenCalled()
[event] = changeHandler.argsForCall[0]
@@ -281,13 +285,13 @@ describe "TokenizedBuffer", ->
it "tokenizes the initial chunk synchronously, then tokenizes the remaining lines in the background", ->
commentBlock = _.multiplyString("// a comment\n", tokenizedBuffer.chunkSize + 2)
buffer.insert([0,0], commentBlock)
expect(tokenizedBuffer.lineForScreenRow(0).ruleStack?).toBeTruthy()
expect(tokenizedBuffer.lineForScreenRow(4).ruleStack?).toBeTruthy()
expect(tokenizedBuffer.lineForScreenRow(5).ruleStack?).toBeFalsy()
expect(tokenizedBuffer.tokenizedLineForRow(0).ruleStack?).toBeTruthy()
expect(tokenizedBuffer.tokenizedLineForRow(4).ruleStack?).toBeTruthy()
expect(tokenizedBuffer.tokenizedLineForRow(5).ruleStack?).toBeFalsy()
advanceClock()
expect(tokenizedBuffer.lineForScreenRow(5).ruleStack?).toBeTruthy()
expect(tokenizedBuffer.lineForScreenRow(6).ruleStack?).toBeTruthy()
expect(tokenizedBuffer.tokenizedLineForRow(5).ruleStack?).toBeTruthy()
expect(tokenizedBuffer.tokenizedLineForRow(6).ruleStack?).toBeTruthy()
describe ".findOpeningBracket(closingBufferPosition)", ->
it "returns the position of the matching bracket, skipping any nested brackets", ->
@@ -298,18 +302,18 @@ describe "TokenizedBuffer", ->
expect(tokenizedBuffer.findClosingBracket([1, 29])).toEqual [9, 2]
it "tokenizes leading whitespace based on the new tab length", ->
expect(tokenizedBuffer.lineForScreenRow(5).tokens[0].isAtomic).toBeTruthy()
expect(tokenizedBuffer.lineForScreenRow(5).tokens[0].value).toBe " "
expect(tokenizedBuffer.lineForScreenRow(5).tokens[1].isAtomic).toBeTruthy()
expect(tokenizedBuffer.lineForScreenRow(5).tokens[1].value).toBe " "
expect(tokenizedBuffer.tokenizedLineForRow(5).tokens[0].isAtomic).toBeTruthy()
expect(tokenizedBuffer.tokenizedLineForRow(5).tokens[0].value).toBe " "
expect(tokenizedBuffer.tokenizedLineForRow(5).tokens[1].isAtomic).toBeTruthy()
expect(tokenizedBuffer.tokenizedLineForRow(5).tokens[1].value).toBe " "
tokenizedBuffer.setTabLength(4)
fullyTokenize(tokenizedBuffer)
expect(tokenizedBuffer.lineForScreenRow(5).tokens[0].isAtomic).toBeTruthy()
expect(tokenizedBuffer.lineForScreenRow(5).tokens[0].value).toBe " "
expect(tokenizedBuffer.lineForScreenRow(5).tokens[1].isAtomic).toBeFalsy()
expect(tokenizedBuffer.lineForScreenRow(5).tokens[1].value).toBe " current "
expect(tokenizedBuffer.tokenizedLineForRow(5).tokens[0].isAtomic).toBeTruthy()
expect(tokenizedBuffer.tokenizedLineForRow(5).tokens[0].value).toBe " "
expect(tokenizedBuffer.tokenizedLineForRow(5).tokens[1].isAtomic).toBeFalsy()
expect(tokenizedBuffer.tokenizedLineForRow(5).tokens[1].value).toBe " current "
describe "when the buffer contains hard-tabs", ->
beforeEach ->
@@ -331,7 +335,7 @@ describe "TokenizedBuffer", ->
it "renders each tab as its own atomic token with a value of size tabLength", ->
tabAsSpaces = _.multiplyString(' ', tokenizedBuffer.getTabLength())
screenLine0 = tokenizedBuffer.lineForScreenRow(0)
screenLine0 = tokenizedBuffer.tokenizedLineForRow(0)
expect(screenLine0.text).toBe "# Econ 101#{tabAsSpaces}"
{ tokens } = screenLine0
@@ -343,7 +347,7 @@ describe "TokenizedBuffer", ->
expect(tokens[2].isAtomic).toBeTruthy()
expect(tokens[3].value).toBe ""
expect(tokenizedBuffer.lineForScreenRow(2).text).toBe "#{tabAsSpaces} buy()#{tabAsSpaces}while supply > demand"
expect(tokenizedBuffer.tokenizedLineForRow(2).text).toBe "#{tabAsSpaces} buy()#{tabAsSpaces}while supply > demand"
it "aligns the hard tabs to the correct tab stop column", ->
buffer.setText """
@@ -355,62 +359,62 @@ describe "TokenizedBuffer", ->
tokenizedBuffer.setTabLength(4)
fullyTokenize(tokenizedBuffer)
expect(tokenizedBuffer.lineForScreenRow(0).text).toBe "1 2 3 4"
expect(tokenizedBuffer.lineForScreenRow(0).tokens[1].bufferDelta).toBe 1
expect(tokenizedBuffer.lineForScreenRow(0).tokens[1].screenDelta).toBe 3
expect(tokenizedBuffer.tokenizedLineForRow(0).text).toBe "1 2 3 4"
expect(tokenizedBuffer.tokenizedLineForRow(0).tokens[1].bufferDelta).toBe 1
expect(tokenizedBuffer.tokenizedLineForRow(0).tokens[1].screenDelta).toBe 3
expect(tokenizedBuffer.lineForScreenRow(1).text).toBe "12 3 4 5"
expect(tokenizedBuffer.lineForScreenRow(1).tokens[1].bufferDelta).toBe 1
expect(tokenizedBuffer.lineForScreenRow(1).tokens[1].screenDelta).toBe 2
expect(tokenizedBuffer.tokenizedLineForRow(1).text).toBe "12 3 4 5"
expect(tokenizedBuffer.tokenizedLineForRow(1).tokens[1].bufferDelta).toBe 1
expect(tokenizedBuffer.tokenizedLineForRow(1).tokens[1].screenDelta).toBe 2
expect(tokenizedBuffer.lineForScreenRow(2).text).toBe "123 4 5 6"
expect(tokenizedBuffer.lineForScreenRow(2).tokens[1].bufferDelta).toBe 1
expect(tokenizedBuffer.lineForScreenRow(2).tokens[1].screenDelta).toBe 1
expect(tokenizedBuffer.tokenizedLineForRow(2).text).toBe "123 4 5 6"
expect(tokenizedBuffer.tokenizedLineForRow(2).tokens[1].bufferDelta).toBe 1
expect(tokenizedBuffer.tokenizedLineForRow(2).tokens[1].screenDelta).toBe 1
tokenizedBuffer.setTabLength(3)
fullyTokenize(tokenizedBuffer)
expect(tokenizedBuffer.lineForScreenRow(0).text).toBe "1 2 3 4"
expect(tokenizedBuffer.lineForScreenRow(0).tokens[1].bufferDelta).toBe 1
expect(tokenizedBuffer.lineForScreenRow(0).tokens[1].screenDelta).toBe 2
expect(tokenizedBuffer.tokenizedLineForRow(0).text).toBe "1 2 3 4"
expect(tokenizedBuffer.tokenizedLineForRow(0).tokens[1].bufferDelta).toBe 1
expect(tokenizedBuffer.tokenizedLineForRow(0).tokens[1].screenDelta).toBe 2
expect(tokenizedBuffer.lineForScreenRow(1).text).toBe "12 3 4 5"
expect(tokenizedBuffer.lineForScreenRow(1).tokens[1].bufferDelta).toBe 1
expect(tokenizedBuffer.lineForScreenRow(1).tokens[1].screenDelta).toBe 1
expect(tokenizedBuffer.tokenizedLineForRow(1).text).toBe "12 3 4 5"
expect(tokenizedBuffer.tokenizedLineForRow(1).tokens[1].bufferDelta).toBe 1
expect(tokenizedBuffer.tokenizedLineForRow(1).tokens[1].screenDelta).toBe 1
expect(tokenizedBuffer.lineForScreenRow(2).text).toBe "123 4 5 6"
expect(tokenizedBuffer.lineForScreenRow(2).tokens[1].bufferDelta).toBe 1
expect(tokenizedBuffer.lineForScreenRow(2).tokens[1].screenDelta).toBe 3
expect(tokenizedBuffer.tokenizedLineForRow(2).text).toBe "123 4 5 6"
expect(tokenizedBuffer.tokenizedLineForRow(2).tokens[1].bufferDelta).toBe 1
expect(tokenizedBuffer.tokenizedLineForRow(2).tokens[1].screenDelta).toBe 3
tokenizedBuffer.setTabLength(2)
fullyTokenize(tokenizedBuffer)
expect(tokenizedBuffer.lineForScreenRow(0).text).toBe "1 2 3 4"
expect(tokenizedBuffer.lineForScreenRow(0).tokens[1].bufferDelta).toBe 1
expect(tokenizedBuffer.lineForScreenRow(0).tokens[1].screenDelta).toBe 1
expect(tokenizedBuffer.tokenizedLineForRow(0).text).toBe "1 2 3 4"
expect(tokenizedBuffer.tokenizedLineForRow(0).tokens[1].bufferDelta).toBe 1
expect(tokenizedBuffer.tokenizedLineForRow(0).tokens[1].screenDelta).toBe 1
expect(tokenizedBuffer.lineForScreenRow(1).text).toBe "12 3 4 5"
expect(tokenizedBuffer.lineForScreenRow(1).tokens[1].bufferDelta).toBe 1
expect(tokenizedBuffer.lineForScreenRow(1).tokens[1].screenDelta).toBe 2
expect(tokenizedBuffer.tokenizedLineForRow(1).text).toBe "12 3 4 5"
expect(tokenizedBuffer.tokenizedLineForRow(1).tokens[1].bufferDelta).toBe 1
expect(tokenizedBuffer.tokenizedLineForRow(1).tokens[1].screenDelta).toBe 2
expect(tokenizedBuffer.lineForScreenRow(2).text).toBe "123 4 5 6"
expect(tokenizedBuffer.lineForScreenRow(2).tokens[1].bufferDelta).toBe 1
expect(tokenizedBuffer.lineForScreenRow(2).tokens[1].screenDelta).toBe 1
expect(tokenizedBuffer.tokenizedLineForRow(2).text).toBe "123 4 5 6"
expect(tokenizedBuffer.tokenizedLineForRow(2).tokens[1].bufferDelta).toBe 1
expect(tokenizedBuffer.tokenizedLineForRow(2).tokens[1].screenDelta).toBe 1
tokenizedBuffer.setTabLength(1)
fullyTokenize(tokenizedBuffer)
expect(tokenizedBuffer.lineForScreenRow(0).text).toBe "1 2 3 4"
expect(tokenizedBuffer.lineForScreenRow(0).tokens[1].bufferDelta).toBe 1
expect(tokenizedBuffer.lineForScreenRow(0).tokens[1].screenDelta).toBe 1
expect(tokenizedBuffer.tokenizedLineForRow(0).text).toBe "1 2 3 4"
expect(tokenizedBuffer.tokenizedLineForRow(0).tokens[1].bufferDelta).toBe 1
expect(tokenizedBuffer.tokenizedLineForRow(0).tokens[1].screenDelta).toBe 1
expect(tokenizedBuffer.lineForScreenRow(1).text).toBe "12 3 4 5"
expect(tokenizedBuffer.lineForScreenRow(1).tokens[1].bufferDelta).toBe 1
expect(tokenizedBuffer.lineForScreenRow(1).tokens[1].screenDelta).toBe 1
expect(tokenizedBuffer.tokenizedLineForRow(1).text).toBe "12 3 4 5"
expect(tokenizedBuffer.tokenizedLineForRow(1).tokens[1].bufferDelta).toBe 1
expect(tokenizedBuffer.tokenizedLineForRow(1).tokens[1].screenDelta).toBe 1
expect(tokenizedBuffer.lineForScreenRow(2).text).toBe "123 4 5 6"
expect(tokenizedBuffer.lineForScreenRow(2).tokens[1].bufferDelta).toBe 1
expect(tokenizedBuffer.lineForScreenRow(2).tokens[1].screenDelta).toBe 1
expect(tokenizedBuffer.tokenizedLineForRow(2).text).toBe "123 4 5 6"
expect(tokenizedBuffer.tokenizedLineForRow(2).tokens[1].bufferDelta).toBe 1
expect(tokenizedBuffer.tokenizedLineForRow(2).tokens[1].screenDelta).toBe 1
describe "when the buffer contains UTF-8 surrogate pairs", ->
beforeEach ->
@@ -431,7 +435,7 @@ describe "TokenizedBuffer", ->
buffer.release()
it "renders each UTF-8 surrogate pair as its own atomic token", ->
screenLine0 = tokenizedBuffer.lineForScreenRow(0)
screenLine0 = tokenizedBuffer.tokenizedLineForRow(0)
expect(screenLine0.text).toBe "'abc\uD835\uDF97def'"
{ tokens } = screenLine0
@@ -443,7 +447,7 @@ describe "TokenizedBuffer", ->
expect(tokens[3].value).toBe "def"
expect(tokens[4].value).toBe "'"
screenLine1 = tokenizedBuffer.lineForScreenRow(1)
screenLine1 = tokenizedBuffer.tokenizedLineForRow(1)
expect(screenLine1.text).toBe "//\uD835\uDF97xyz"
{ tokens } = screenLine1
@@ -464,7 +468,7 @@ describe "TokenizedBuffer", ->
runs ->
tokenizedBuffer = editor.displayBuffer.tokenizedBuffer
tokenizedBuffer.on 'tokenized', tokenizedHandler
tokenizedBuffer.onDidTokenize tokenizedHandler
fullyTokenize(tokenizedBuffer)
expect(tokenizedHandler.callCount).toBe(1)
@@ -479,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()
@@ -495,7 +499,7 @@ describe "TokenizedBuffer", ->
runs ->
tokenizedBuffer = editor.displayBuffer.tokenizedBuffer
tokenizedBuffer.on 'tokenized', tokenizedHandler
tokenizedBuffer.onDidTokenize tokenizedHandler
fullyTokenize(tokenizedBuffer)
tokenizedHandler.reset()
@@ -521,7 +525,7 @@ describe "TokenizedBuffer", ->
tokenizedBuffer.setGrammar(atom.syntax.selectGrammar('test.erb'))
fullyTokenize(tokenizedBuffer)
{tokens} = tokenizedBuffer.lineForScreenRow(0)
{tokens} = tokenizedBuffer.tokenizedLineForRow(0)
expect(tokens[0]).toEqual value: "<div class='name'>", scopes: ["text.html.ruby"]
waitsForPromise ->
@@ -529,7 +533,7 @@ describe "TokenizedBuffer", ->
runs ->
fullyTokenize(tokenizedBuffer)
{tokens} = tokenizedBuffer.lineForScreenRow(0)
{tokens} = tokenizedBuffer.tokenizedLineForRow(0)
expect(tokens[0]).toEqual value: '<', scopes: ["text.html.ruby","meta.tag.block.any.html","punctuation.definition.tag.begin.html"]
describe ".tokenForPosition(position)", ->
@@ -584,51 +588,112 @@ describe "TokenizedBuffer", ->
atom.config.set('editor.tabLength', 0)
expect(tokenizedBuffer.tokenForPosition([0,0]).value).toBe ' '
describe "when the invisibles value changes", ->
beforeEach ->
it "updates the tokens with the appropriate invisible characters", ->
buffer = new TextBuffer(text: " \t a line with tabs\tand \tspaces \t ")
tokenizedBuffer = new TokenizedBuffer({buffer})
fullyTokenize(tokenizedBuffer)
tokenizedBuffer.setInvisibles(space: 'S', tab: 'T')
fullyTokenize(tokenizedBuffer)
expect(tokenizedBuffer.tokenizedLineForRow(0).text).toBe "SST Sa line with tabsTand T spacesSTS"
# Also needs to work for copies
expect(tokenizedBuffer.tokenizedLineForRow(0).copy().text).toBe "SST Sa line with tabsTand T spacesSTS"
it "assigns endOfLineInvisibles to tokenized lines", ->
buffer = new TextBuffer(text: "a line that ends in a carriage-return-line-feed \r\na line that ends in just a line-feed\na line with no ending")
tokenizedBuffer = new TokenizedBuffer({buffer})
atom.config.set('editor.showInvisibles', true)
tokenizedBuffer.setInvisibles(cr: 'R', eol: 'N')
fullyTokenize(tokenizedBuffer)
expect(tokenizedBuffer.tokenizedLineForRow(0).endOfLineInvisibles).toEqual ['R', 'N']
expect(tokenizedBuffer.tokenizedLineForRow(1).endOfLineInvisibles).toEqual ['N']
# Lines ending in soft wraps get no invisibles
[left, right] = tokenizedBuffer.tokenizedLineForRow(0).softWrapAt(20)
expect(left.endOfLineInvisibles).toBe null
expect(right.endOfLineInvisibles).toEqual ['R', 'N']
tokenizedBuffer.setInvisibles(cr: 'R', eol: false)
expect(tokenizedBuffer.tokenizedLineForRow(0).endOfLineInvisibles).toEqual ['R']
expect(tokenizedBuffer.tokenizedLineForRow(1).endOfLineInvisibles).toEqual []
describe "leading and trailing whitespace", ->
beforeEach ->
buffer = atom.project.bufferForPathSync('sample.js')
tokenizedBuffer = new TokenizedBuffer({buffer})
fullyTokenize(tokenizedBuffer)
it "sets ::hasLeadingWhitespace to true on tokens that have leading whitespace", ->
expect(tokenizedBuffer.lineForScreenRow(0).tokens[0].hasLeadingWhitespace).toBe false
expect(tokenizedBuffer.lineForScreenRow(1).tokens[0].hasLeadingWhitespace).toBe true
expect(tokenizedBuffer.lineForScreenRow(1).tokens[1].hasLeadingWhitespace).toBe false
expect(tokenizedBuffer.lineForScreenRow(2).tokens[0].hasLeadingWhitespace).toBe true
expect(tokenizedBuffer.lineForScreenRow(2).tokens[1].hasLeadingWhitespace).toBe true
expect(tokenizedBuffer.lineForScreenRow(2).tokens[2].hasLeadingWhitespace).toBe false
it "assigns ::firstNonWhitespaceIndex on tokens that have leading whitespace", ->
expect(tokenizedBuffer.tokenizedLineForRow(0).tokens[0].firstNonWhitespaceIndex).toBe null
expect(tokenizedBuffer.tokenizedLineForRow(1).tokens[0].firstNonWhitespaceIndex).toBe 2
expect(tokenizedBuffer.tokenizedLineForRow(1).tokens[1].firstNonWhitespaceIndex).toBe null
expect(tokenizedBuffer.tokenizedLineForRow(2).tokens[0].firstNonWhitespaceIndex).toBe 2
expect(tokenizedBuffer.tokenizedLineForRow(2).tokens[1].firstNonWhitespaceIndex).toBe 2
expect(tokenizedBuffer.tokenizedLineForRow(2).tokens[2].firstNonWhitespaceIndex).toBe null
# The 4th token *has* leading whitespace, but isn't entirely whitespace
buffer.insert([5, 0], ' ')
expect(tokenizedBuffer.lineForScreenRow(5).tokens[3].hasLeadingWhitespace).toBe true
expect(tokenizedBuffer.lineForScreenRow(5).tokens[4].hasLeadingWhitespace).toBe false
expect(tokenizedBuffer.tokenizedLineForRow(5).tokens[3].firstNonWhitespaceIndex).toBe 1
expect(tokenizedBuffer.tokenizedLineForRow(5).tokens[4].firstNonWhitespaceIndex).toBe null
# Lines that are *only* whitespace are not considered to have leading whitespace
buffer.insert([10, 0], ' ')
expect(tokenizedBuffer.lineForScreenRow(10).tokens[0].hasLeadingWhitespace).toBe false
expect(tokenizedBuffer.tokenizedLineForRow(10).tokens[0].firstNonWhitespaceIndex).toBe null
it "sets ::hasTrailingWhitespace to true on tokens that have trailing whitespace", ->
it "assigns ::firstTrailingWhitespaceIndex on tokens that have trailing whitespace", ->
buffer.insert([0, Infinity], ' ')
expect(tokenizedBuffer.lineForScreenRow(0).tokens[11].hasTrailingWhitespace).toBe false
expect(tokenizedBuffer.lineForScreenRow(0).tokens[12].hasTrailingWhitespace).toBe true
expect(tokenizedBuffer.tokenizedLineForRow(0).tokens[11].firstTrailingWhitespaceIndex).toBe null
expect(tokenizedBuffer.tokenizedLineForRow(0).tokens[12].firstTrailingWhitespaceIndex).toBe 0
# The last token *has* trailing whitespace, but isn't entirely whitespace
buffer.setTextInRange([[2, 39], [2, 40]], ' ')
expect(tokenizedBuffer.lineForScreenRow(2).tokens[14].hasTrailingWhitespace).toBe false
expect(tokenizedBuffer.lineForScreenRow(2).tokens[15].hasTrailingWhitespace).toBe true
expect(tokenizedBuffer.tokenizedLineForRow(2).tokens[14].firstTrailingWhitespaceIndex).toBe null
expect(tokenizedBuffer.tokenizedLineForRow(2).tokens[15].firstTrailingWhitespaceIndex).toBe 6
# Lines that are *only* whitespace are considered to have trailing whitespace
buffer.insert([10, 0], ' ')
expect(tokenizedBuffer.lineForScreenRow(10).tokens[0].hasTrailingWhitespace).toBe true
expect(tokenizedBuffer.tokenizedLineForRow(10).tokens[0].firstTrailingWhitespaceIndex).toBe 0
it "only marks trailing whitespace on the last segment of a soft-wrapped line", ->
buffer.insert([0, Infinity], ' ')
tokenizedLine = tokenizedBuffer.lineForScreenRow(0)
tokenizedLine = tokenizedBuffer.tokenizedLineForRow(0)
[segment1, segment2] = tokenizedLine.softWrapAt(16)
expect(segment1.tokens[5].value).toBe ' '
expect(segment1.tokens[5].hasTrailingWhitespace).toBe false
expect(segment1.tokens[5].firstTrailingWhitespaceIndex).toBe null
expect(segment2.tokens[6].value).toBe ' '
expect(segment2.tokens[6].hasTrailingWhitespace).toBe true
expect(segment2.tokens[6].firstTrailingWhitespaceIndex).toBe 0
it "sets leading and trailing whitespace correctly on a line with invisible characters that is copied", ->
buffer.setText(" \t a line with tabs\tand \tspaces \t ")
tokenizedBuffer.setInvisibles(space: 'S', tab: 'T')
fullyTokenize(tokenizedBuffer)
line = tokenizedBuffer.tokenizedLineForRow(0).copy()
expect(line.tokens[0].firstNonWhitespaceIndex).toBe 2
expect(line.tokens[line.tokens.length - 1].firstTrailingWhitespaceIndex).toBe 0
it "sets the ::firstNonWhitespaceIndex and ::firstTrailingWhitespaceIndex correctly when tokens are split for soft-wrapping", ->
tokenizedBuffer.setInvisibles(space: 'S')
buffer.setText(" token ")
fullyTokenize(tokenizedBuffer)
token = tokenizedBuffer.tokenizedLines[0].tokens[0]
[leftToken, rightToken] = token.splitAt(1)
expect(leftToken.hasInvisibleCharacters).toBe true
expect(leftToken.firstNonWhitespaceIndex).toBe 1
expect(leftToken.firstTrailingWhitespaceIndex).toBe null
expect(leftToken.hasInvisibleCharacters).toBe true
expect(rightToken.firstNonWhitespaceIndex).toBe null
expect(rightToken.firstTrailingWhitespaceIndex).toBe 5
describe "indent level", ->
beforeEach ->
@@ -638,84 +703,84 @@ describe "TokenizedBuffer", ->
describe "when the line is non-empty", ->
it "has an indent level based on the leading whitespace on the line", ->
expect(tokenizedBuffer.lineForScreenRow(0).indentLevel).toBe 0
expect(tokenizedBuffer.lineForScreenRow(1).indentLevel).toBe 1
expect(tokenizedBuffer.lineForScreenRow(2).indentLevel).toBe 2
expect(tokenizedBuffer.tokenizedLineForRow(0).indentLevel).toBe 0
expect(tokenizedBuffer.tokenizedLineForRow(1).indentLevel).toBe 1
expect(tokenizedBuffer.tokenizedLineForRow(2).indentLevel).toBe 2
buffer.insert([2, 0], ' ')
expect(tokenizedBuffer.lineForScreenRow(2).indentLevel).toBe 2.5
expect(tokenizedBuffer.tokenizedLineForRow(2).indentLevel).toBe 2.5
describe "when the line is empty", ->
it "assumes the indentation level of the first non-empty line below or above if one exists", ->
buffer.insert([12, 0], ' ')
buffer.insert([12, Infinity], '\n\n')
expect(tokenizedBuffer.lineForScreenRow(13).indentLevel).toBe 2
expect(tokenizedBuffer.lineForScreenRow(14).indentLevel).toBe 2
expect(tokenizedBuffer.tokenizedLineForRow(13).indentLevel).toBe 2
expect(tokenizedBuffer.tokenizedLineForRow(14).indentLevel).toBe 2
buffer.insert([1, Infinity], '\n\n')
expect(tokenizedBuffer.lineForScreenRow(2).indentLevel).toBe 2
expect(tokenizedBuffer.lineForScreenRow(3).indentLevel).toBe 2
expect(tokenizedBuffer.tokenizedLineForRow(2).indentLevel).toBe 2
expect(tokenizedBuffer.tokenizedLineForRow(3).indentLevel).toBe 2
buffer.setText('\n\n\n')
expect(tokenizedBuffer.lineForScreenRow(1).indentLevel).toBe 0
expect(tokenizedBuffer.tokenizedLineForRow(1).indentLevel).toBe 0
describe "when the changed lines are surrounded by whitespace-only lines", ->
it "updates the indentLevel of empty lines that precede the change", ->
expect(tokenizedBuffer.lineForScreenRow(12).indentLevel).toBe 0
expect(tokenizedBuffer.tokenizedLineForRow(12).indentLevel).toBe 0
buffer.insert([12, 0], '\n')
buffer.insert([13, 0], ' ')
expect(tokenizedBuffer.lineForScreenRow(12).indentLevel).toBe 1
expect(tokenizedBuffer.tokenizedLineForRow(12).indentLevel).toBe 1
it "updates empty line indent guides when the empty line is the last line", ->
buffer.insert([12, 2], '\n')
# The newline and he tab need to be in two different operations to surface the bug
buffer.insert([12, 0], ' ')
expect(tokenizedBuffer.lineForScreenRow(13).indentLevel).toBe 1
expect(tokenizedBuffer.tokenizedLineForRow(13).indentLevel).toBe 1
buffer.insert([12, 0], ' ')
expect(tokenizedBuffer.lineForScreenRow(13).indentLevel).toBe 2
expect(tokenizedBuffer.lineForScreenRow(14)).not.toBeDefined()
expect(tokenizedBuffer.tokenizedLineForRow(13).indentLevel).toBe 2
expect(tokenizedBuffer.tokenizedLineForRow(14)).not.toBeDefined()
it "updates the indentLevel of empty lines surrounding a change that inserts lines", ->
# create some new lines
buffer.insert([7, 0], '\n\n')
buffer.insert([5, 0], '\n\n')
expect(tokenizedBuffer.lineForScreenRow(5).indentLevel).toBe 3
expect(tokenizedBuffer.lineForScreenRow(6).indentLevel).toBe 3
expect(tokenizedBuffer.lineForScreenRow(9).indentLevel).toBe 3
expect(tokenizedBuffer.lineForScreenRow(10).indentLevel).toBe 3
expect(tokenizedBuffer.lineForScreenRow(11).indentLevel).toBe 2
expect(tokenizedBuffer.tokenizedLineForRow(5).indentLevel).toBe 3
expect(tokenizedBuffer.tokenizedLineForRow(6).indentLevel).toBe 3
expect(tokenizedBuffer.tokenizedLineForRow(9).indentLevel).toBe 3
expect(tokenizedBuffer.tokenizedLineForRow(10).indentLevel).toBe 3
expect(tokenizedBuffer.tokenizedLineForRow(11).indentLevel).toBe 2
tokenizedBuffer.on "changed", changeHandler = jasmine.createSpy('changeHandler')
tokenizedBuffer.onDidChange changeHandler = jasmine.createSpy('changeHandler')
buffer.setTextInRange([[7, 0], [8, 65]], ' one\n two\n three\n four')
delete changeHandler.argsForCall[0][0].bufferChange
expect(changeHandler).toHaveBeenCalledWith(start: 5, end: 10, delta: 2)
expect(tokenizedBuffer.lineForScreenRow(5).indentLevel).toBe 4
expect(tokenizedBuffer.lineForScreenRow(6).indentLevel).toBe 4
expect(tokenizedBuffer.lineForScreenRow(11).indentLevel).toBe 4
expect(tokenizedBuffer.lineForScreenRow(12).indentLevel).toBe 4
expect(tokenizedBuffer.lineForScreenRow(13).indentLevel).toBe 2
expect(tokenizedBuffer.tokenizedLineForRow(5).indentLevel).toBe 4
expect(tokenizedBuffer.tokenizedLineForRow(6).indentLevel).toBe 4
expect(tokenizedBuffer.tokenizedLineForRow(11).indentLevel).toBe 4
expect(tokenizedBuffer.tokenizedLineForRow(12).indentLevel).toBe 4
expect(tokenizedBuffer.tokenizedLineForRow(13).indentLevel).toBe 2
it "updates the indentLevel of empty lines surrounding a change that removes lines", ->
# create some new lines
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')
delete changeHandler.argsForCall[0][0].bufferChange
expect(changeHandler).toHaveBeenCalledWith(start: 5, end: 10, delta: -1)
expect(tokenizedBuffer.lineForScreenRow(5).indentLevel).toBe 2
expect(tokenizedBuffer.lineForScreenRow(6).indentLevel).toBe 2
expect(tokenizedBuffer.lineForScreenRow(7).indentLevel).toBe 2 # new text
expect(tokenizedBuffer.lineForScreenRow(8).indentLevel).toBe 2
expect(tokenizedBuffer.lineForScreenRow(9).indentLevel).toBe 2
expect(tokenizedBuffer.lineForScreenRow(10).indentLevel).toBe 2 # }
expect(tokenizedBuffer.tokenizedLineForRow(5).indentLevel).toBe 2
expect(tokenizedBuffer.tokenizedLineForRow(6).indentLevel).toBe 2
expect(tokenizedBuffer.tokenizedLineForRow(7).indentLevel).toBe 2 # new text
expect(tokenizedBuffer.tokenizedLineForRow(8).indentLevel).toBe 2
expect(tokenizedBuffer.tokenizedLineForRow(9).indentLevel).toBe 2
expect(tokenizedBuffer.tokenizedLineForRow(10).indentLevel).toBe 2 # }
+7 -7
Ver Arquivo
@@ -10,13 +10,13 @@ describe "TokenizedLine", ->
atom.project.open('coffee.coffee').then (o) -> editor = o
it "returns true when the line is only whitespace", ->
expect(editor.lineForScreenRow(3).isOnlyWhitespace()).toBe true
expect(editor.lineForScreenRow(7).isOnlyWhitespace()).toBe true
expect(editor.lineForScreenRow(23).isOnlyWhitespace()).toBe true
expect(editor.tokenizedLineForScreenRow(3).isOnlyWhitespace()).toBe true
expect(editor.tokenizedLineForScreenRow(7).isOnlyWhitespace()).toBe true
expect(editor.tokenizedLineForScreenRow(23).isOnlyWhitespace()).toBe true
it "returns false when the line is not only whitespace", ->
expect(editor.lineForScreenRow(0).isOnlyWhitespace()).toBe false
expect(editor.lineForScreenRow(2).isOnlyWhitespace()).toBe false
expect(editor.tokenizedLineForScreenRow(0).isOnlyWhitespace()).toBe false
expect(editor.tokenizedLineForScreenRow(2).isOnlyWhitespace()).toBe false
describe "::getScopeTree()", ->
it "returns a tree whose inner nodes are scopes and whose leaf nodes are tokens in those scopes", ->
@@ -35,6 +35,6 @@ describe "TokenizedLine", ->
runs ->
tokenIndex = 0
tokens = editor.lineForScreenRow(1).tokens
scopeTree = editor.lineForScreenRow(1).getScopeTree()
tokens = editor.tokenizedLineForScreenRow(1).tokens
scopeTree = editor.tokenizedLineForScreenRow(1).getScopeTree()
ensureValidScopeTree(scopeTree)
+34 -1
Ver Arquivo
@@ -113,6 +113,7 @@ describe "Window", ->
expect(atom.state.project).toEqual projectState
expect(atom.saveSync).toHaveBeenCalled()
describe ".removeEditorWindow()", ->
it "unsubscribes from all buffers", ->
waitsForPromise ->
atom.workspace.open("sample.js")
@@ -123,7 +124,7 @@ describe "Window", ->
pane.splitRight(pane.copyActiveItem())
expect(atom.workspaceView.find('.editor').length).toBe 2
atom.unloadEditorWindow()
atom.removeEditorWindow()
expect(buffer.getSubscriptionCount()).toBe 0
@@ -255,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
+95 -61
Ver Arquivo
@@ -8,8 +8,12 @@ describe "Workspace", ->
atom.workspace = workspace = new Workspace
describe "::open(uri, options)", ->
openEvents = null
beforeEach ->
spyOn(workspace.activePane, 'activate').andCallThrough()
openEvents = []
workspace.onDidOpen (event) -> openEvents.push(event)
spyOn(workspace.getActivePane(), 'activate').andCallThrough()
describe "when the 'searchAllPanes' option is false (default)", ->
describe "when called without a uri", ->
@@ -21,18 +25,21 @@ describe "Workspace", ->
runs ->
expect(editor1.getPath()).toBeUndefined()
expect(workspace.activePane.items).toEqual [editor1]
expect(workspace.activePaneItem).toBe editor1
expect(workspace.activePane.activate).toHaveBeenCalled()
expect(workspace.getActivePane().items).toEqual [editor1]
expect(workspace.getActivePaneItem()).toBe editor1
expect(workspace.getActivePane().activate).toHaveBeenCalled()
expect(openEvents).toEqual [{uri: undefined, pane: workspace.getActivePane(), item: editor1, index: 0}]
openEvents = []
waitsForPromise ->
workspace.open().then (editor) -> editor2 = editor
runs ->
expect(editor2.getPath()).toBeUndefined()
expect(workspace.activePane.items).toEqual [editor1, editor2]
expect(workspace.activePaneItem).toBe editor2
expect(workspace.activePane.activate).toHaveBeenCalled()
expect(workspace.getActivePane().items).toEqual [editor1, editor2]
expect(workspace.getActivePaneItem()).toBe editor2
expect(workspace.getActivePane().activate).toHaveBeenCalled()
expect(openEvents).toEqual [{uri: undefined, pane: workspace.getActivePane(), item: editor2, index: 1}]
describe "when called with a uri", ->
describe "when the active pane already has an editor for the given uri", ->
@@ -51,8 +58,29 @@ describe "Workspace", ->
runs ->
expect(editor).toBe editor1
expect(workspace.activePaneItem).toBe editor
expect(workspace.activePane.activate).toHaveBeenCalled()
expect(workspace.getActivePaneItem()).toBe editor
expect(workspace.getActivePane().activate).toHaveBeenCalled()
expect(openEvents).toEqual [
{
uri: atom.project.resolve('a')
item: editor1
pane: atom.workspace.getActivePane()
index: 0
}
{
uri: atom.project.resolve('b')
item: editor2
pane: atom.workspace.getActivePane()
index: 1
}
{
uri: atom.project.resolve('a')
item: editor1
pane: atom.workspace.getActivePane()
index: 0
}
]
describe "when the active pane does not have an editor for the given uri", ->
it "adds and activates a new editor for the given path on the active pane", ->
@@ -62,9 +90,9 @@ describe "Workspace", ->
runs ->
expect(editor.getUri()).toBe atom.project.resolve('a')
expect(workspace.activePaneItem).toBe editor
expect(workspace.activePane.items).toEqual [editor]
expect(workspace.activePane.activate).toHaveBeenCalled()
expect(workspace.getActivePaneItem()).toBe editor
expect(workspace.getActivePane().items).toEqual [editor]
expect(workspace.getActivePane().activate).toHaveBeenCalled()
describe "when the 'searchAllPanes' option is true", ->
describe "when an editor for the given uri is already open on an inactive pane", ->
@@ -83,14 +111,14 @@ describe "Workspace", ->
workspace.open('b').then (o) -> editor2 = o
runs ->
expect(workspace.activePaneItem).toBe editor2
expect(workspace.getActivePaneItem()).toBe editor2
waitsForPromise ->
workspace.open('a', searchAllPanes: true)
runs ->
expect(workspace.activePane).toBe pane1
expect(workspace.activePaneItem).toBe editor1
expect(workspace.getActivePane()).toBe pane1
expect(workspace.getActivePaneItem()).toBe editor1
describe "when no editor for the given uri is open in any pane", ->
it "opens an editor for the given uri in the active pane", ->
@@ -99,21 +127,21 @@ describe "Workspace", ->
workspace.open('a', searchAllPanes: true).then (o) -> editor = o
runs ->
expect(workspace.activePaneItem).toBe editor
expect(workspace.getActivePaneItem()).toBe editor
describe "when the 'split' option is set", ->
describe "when the 'split' option is 'left'", ->
it "opens the editor in the leftmost pane of the current pane axis", ->
pane1 = workspace.activePane
pane1 = workspace.getActivePane()
pane2 = pane1.splitRight()
expect(workspace.activePane).toBe pane2
expect(workspace.getActivePane()).toBe pane2
editor = null
waitsForPromise ->
workspace.open('a', split: 'left').then (o) -> editor = o
runs ->
expect(workspace.activePane).toBe pane1
expect(workspace.getActivePane()).toBe pane1
expect(pane1.items).toEqual [editor]
expect(pane2.items).toEqual []
@@ -123,37 +151,37 @@ describe "Workspace", ->
workspace.open('a', split: 'left').then (o) -> editor = o
runs ->
expect(workspace.activePane).toBe pane1
expect(workspace.getActivePane()).toBe pane1
expect(pane1.items).toEqual [editor]
expect(pane2.items).toEqual []
describe "when a pane axis is the leftmost sibling of the current pane", ->
it "opens the new item in the current pane", ->
editor = null
pane1 = workspace.activePane
pane1 = workspace.getActivePane()
pane2 = pane1.splitLeft()
pane3 = pane2.splitDown()
pane1.activate()
expect(workspace.activePane).toBe pane1
expect(workspace.getActivePane()).toBe pane1
waitsForPromise ->
workspace.open('a', split: 'left').then (o) -> editor = o
runs ->
expect(workspace.activePane).toBe pane1
expect(workspace.getActivePane()).toBe pane1
expect(pane1.items).toEqual [editor]
describe "when the 'split' option is 'right'", ->
it "opens the editor in the rightmost pane of the current pane axis", ->
editor = null
pane1 = workspace.activePane
pane1 = workspace.getActivePane()
pane2 = null
waitsForPromise ->
workspace.open('a', split: 'right').then (o) -> editor = o
runs ->
pane2 = workspace.getPanes().filter((p) -> p != pane1)[0]
expect(workspace.activePane).toBe pane2
expect(workspace.getActivePane()).toBe pane2
expect(pane1.items).toEqual []
expect(pane2.items).toEqual [editor]
@@ -163,18 +191,18 @@ describe "Workspace", ->
workspace.open('a', split: 'right').then (o) -> editor = o
runs ->
expect(workspace.activePane).toBe pane2
expect(workspace.getActivePane()).toBe pane2
expect(pane1.items).toEqual []
expect(pane2.items).toEqual [editor]
describe "when a pane axis is the rightmost sibling of the current pane", ->
it "opens the new item in a new pane split to the right of the current pane", ->
editor = null
pane1 = workspace.activePane
pane1 = workspace.getActivePane()
pane2 = pane1.splitRight()
pane3 = pane2.splitDown()
pane1.activate()
expect(workspace.activePane).toBe pane1
expect(workspace.getActivePane()).toBe pane1
pane4 = null
waitsForPromise ->
@@ -182,7 +210,7 @@ describe "Workspace", ->
runs ->
pane4 = workspace.getPanes().filter((p) -> p != pane1)[0]
expect(workspace.activePane).toBe pane4
expect(workspace.getActivePane()).toBe pane4
expect(pane4.items).toEqual [editor]
expect(workspace.paneContainer.root.children[0]).toBe pane1
expect(workspace.paneContainer.root.children[1]).toBe pane4
@@ -203,21 +231,21 @@ describe "Workspace", ->
workspace.open("bar://baz").then (item) ->
expect(item).toEqual { bar: "bar://baz" }
it "emits an 'editor-created' event", ->
it "notifies ::onDidAddTextEditor observers", ->
absolutePath = require.resolve('./fixtures/dir/a')
newEditorHandler = jasmine.createSpy('newEditorHandler')
workspace.on 'editor-created', newEditorHandler
workspace.onDidAddTextEditor newEditorHandler
editor = null
waitsForPromise ->
workspace.open(absolutePath).then (e) -> editor = e
runs ->
expect(newEditorHandler).toHaveBeenCalledWith editor
expect(newEditorHandler.argsForCall[0][0].textEditor).toBe editor
describe "::reopenItem()", ->
it "opens the uri associated with the last closed pane that isn't currently open", ->
pane = workspace.activePane
pane = workspace.getActivePane()
waitsForPromise ->
workspace.open('a').then ->
workspace.open('b').then ->
@@ -226,44 +254,44 @@ describe "Workspace", ->
runs ->
# does not reopen items with no uri
expect(workspace.activePaneItem.getUri()).toBeUndefined()
expect(workspace.getActivePaneItem().getUri()).toBeUndefined()
pane.destroyActiveItem()
waitsForPromise ->
workspace.reopenItem()
runs ->
expect(workspace.activePaneItem.getUri()).not.toBeUndefined()
expect(workspace.getActivePaneItem().getUri()).not.toBeUndefined()
# destroy all items
expect(workspace.activePaneItem.getUri()).toBe atom.project.resolve('file1')
expect(workspace.getActivePaneItem().getUri()).toBe atom.project.resolve('file1')
pane.destroyActiveItem()
expect(workspace.activePaneItem.getUri()).toBe atom.project.resolve('b')
expect(workspace.getActivePaneItem().getUri()).toBe atom.project.resolve('b')
pane.destroyActiveItem()
expect(workspace.activePaneItem.getUri()).toBe atom.project.resolve('a')
expect(workspace.getActivePaneItem().getUri()).toBe atom.project.resolve('a')
pane.destroyActiveItem()
# reopens items with uris
expect(workspace.activePaneItem).toBeUndefined()
expect(workspace.getActivePaneItem()).toBeUndefined()
waitsForPromise ->
workspace.reopenItem()
runs ->
expect(workspace.activePaneItem.getUri()).toBe atom.project.resolve('a')
expect(workspace.getActivePaneItem().getUri()).toBe atom.project.resolve('a')
# does not reopen items that are already open
waitsForPromise ->
workspace.open('b')
runs ->
expect(workspace.activePaneItem.getUri()).toBe atom.project.resolve('b')
expect(workspace.getActivePaneItem().getUri()).toBe atom.project.resolve('b')
waitsForPromise ->
workspace.reopenItem()
runs ->
expect(workspace.activePaneItem.getUri()).toBe atom.project.resolve('file1')
expect(workspace.getActivePaneItem().getUri()).toBe atom.project.resolve('file1')
describe "::increase/decreaseFontSize()", ->
it "increases/decreases the font size without going below 1", ->
@@ -282,7 +310,22 @@ describe "Workspace", ->
describe "::openLicense()", ->
it "opens the license as plain-text in a buffer", ->
waitsForPromise -> workspace.openLicense()
runs -> expect(workspace.activePaneItem.getText()).toMatch /Copyright/
runs -> expect(workspace.getActivePaneItem().getText()).toMatch /Copyright/
describe "::observeTextEditors()", ->
it "invokes the observer with current and future text editors", ->
observed = []
waitsForPromise -> workspace.open()
waitsForPromise -> workspace.open()
waitsForPromise -> workspace.openLicense()
runs ->
workspace.observeTextEditors (editor) -> observed.push(editor)
waitsForPromise -> workspace.open()
expect(observed).toEqual workspace.getTextEditors()
describe "when an editor is destroyed", ->
it "removes the editor", ->
@@ -292,23 +335,9 @@ describe "Workspace", ->
workspace.open("a").then (e) -> editor = e
runs ->
expect(workspace.getEditors()).toHaveLength 1
expect(workspace.getTextEditors()).toHaveLength 1
editor.destroy()
expect(workspace.getEditors()).toHaveLength 0
describe "when an editor is copied", ->
it "emits an 'editor-created' event", ->
editor = null
handler = jasmine.createSpy('editorCreatedHandler')
workspace.on 'editor-created', handler
waitsForPromise ->
workspace.open("a").then (o) -> editor = o
runs ->
expect(handler.callCount).toBe 1
editorCopy = editor.copy()
expect(handler.callCount).toBe 2
expect(workspace.getTextEditors()).toHaveLength 0
it "stores the active grammars used by all the open editors", ->
waitsForPromise ->
@@ -317,14 +346,19 @@ describe "Workspace", ->
waitsForPromise ->
atom.packages.activatePackage('language-coffee-script')
waitsForPromise ->
atom.packages.activatePackage('language-todo')
waitsForPromise ->
atom.workspace.open('sample.coffee')
runs ->
atom.workspace.getActiveEditor().setText('i = /test/;')
atom.workspace.getActiveEditor().setText """
i = /test/; #FIXME
"""
state = atom.workspace.serialize()
expect(state.packagesWithActiveGrammars).toEqual ['language-coffee-script', 'language-javascript']
expect(state.packagesWithActiveGrammars).toEqual ['language-coffee-script', 'language-javascript', 'language-todo']
jsPackage = atom.packages.getLoadedPackage('language-javascript')
coffeePackage = atom.packages.getLoadedPackage('language-coffee-script')
+13 -11
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()
@@ -195,27 +195,29 @@ describe "WorkspaceView", ->
atom.workspaceView.height(200)
atom.workspaceView.attachToDom()
rightEditorView = atom.workspaceView.getActiveView()
rightEditorView.getEditor().setText("\t ")
leftEditorView = rightEditorView.splitLeft()
rightEditorView.getEditor().setText("\t \n")
rightEditorView.getPaneView().getModel().splitLeft(copyActiveItem: true)
leftEditorView = atom.workspaceView.getActiveView()
expect(rightEditorView.find(".line:first").text()).toBe " "
expect(leftEditorView.find(".line:first").text()).toBe " "
{invisibles} = rightEditorView.component.state
{space, tab, eol} = invisibles
{space, tab, eol} = atom.config.get('editor.invisibles')
withInvisiblesShowing = "#{tab} #{space}#{space}#{eol}"
atom.workspaceView.trigger "window:toggle-invisibles"
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)", ->
@@ -242,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()
@@ -260,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", ->
@@ -272,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
+386 -262
Ver Arquivo
@@ -7,39 +7,25 @@ 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.
#
# ## Useful properties available:
#
# * `atom.clipboard` - A {Clipboard} instance
# * `atom.config` - A {Config} instance
# * `atom.contextMenu` - A {ContextMenuManager} instance
# * `atom.deserializers` - A {DeserializerManager} instance
# * `atom.keymaps` - A {KeymapManager} instance
# * `atom.menu` - A {MenuManager} instance
# * `atom.packages` - A {PackageManager} instance
# * `atom.project` - A {Project} instance
# * `atom.syntax` - A {Syntax} instance
# * `atom.themes` - A {ThemeManager} instance
# * `atom.workspace` - A {Workspace} instance
# * `atom.workspaceView` - A {WorkspaceView} instance
module.exports =
class Atom extends Model
@version: 1 # Increment this when the serialization format changes
# Public: Load or create the Atom environment in the given mode.
# Load or create the Atom environment in the given mode.
#
# mode - Pass 'editor' or 'spec' depending on the kind of environment you
# want to build.
# * `mode` A {String} mode that is either 'editor' or 'spec' depending on the
# kind of environment you want to build.
#
# Returns an Atom instance, fully initialized
@loadOrCreate: (mode) ->
@@ -111,20 +97,71 @@ class Atom extends Model
remote.getCurrentWindow()
workspaceViewParentSelector: 'body'
lastUncaughtError: 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 {MenuManager} instance
menu: null
# Public: A {KeymapManager} instance
keymaps: null
# Public: A {Project} instance
project: null
# 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
# (both spec and application). Call after this instance has been assigned to
# the `atom` global.
# 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.
initialize: ->
window.onerror = =>
@openDevTools()
@executeJavaScriptInDevTools('InspectorFrontendAPI.showConsole()')
@lastUncaughtError = Array::slice.call(arguments)
@emit 'uncaught-error', arguments...
@unsubscribe()
@@ -134,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'
@@ -155,15 +193,16 @@ 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})
@contextMenu = new ContextMenuManager(devMode)
@themes = new ThemeManager({packageManager: @packages, configDirPath, resourcePath, safeMode})
@contextMenu = new ContextMenuManager({resourcePath, devMode})
@menu = new MenuManager({resourcePath})
@clipboard = new Clipboard()
@syntax = @deserializers.deserialize(@state.syntax) ? new Syntax()
@subscribe @packages, 'activated', => @watchThemes()
@subscribe @packages.onDidActivateAll => @watchThemes()
Project = require './project'
TextBuffer = require 'text-buffer'
@@ -174,41 +213,196 @@ 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.
#
# Returns an object with x, y, width, and height keys.
# 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}.
# * `y` The window's y-position {Number}.
# * `width` The window's width {Number}.
# * `height` The window's height {Number}.
getWindowDimensions: ->
browserWindow = @getCurrentWindow()
[x, y] = browserWindow.getPosition()
[width, height] = browserWindow.getSize()
{x, y, width, height}
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
# centered. If height or width are omitted only the position will be changed.
#
# dimensions - An {Object} with the following keys:
# :x - The new x coordinate.
# :y - The new y coordinate.
# :width - The new width.
# :height - The new height.
# * `dimensions` An {Object} with the following keys:
# * `x` The new x coordinate.
# * `y` The new y coordinate.
# * `width` The new width.
# * `height` The new height.
setWindowDimensions: ({x, y, width, height}) ->
if width? and height?
@setSize(width, height)
@@ -249,16 +443,131 @@ class Atom extends Model
unless @isValidDimensions(dimensions)
dimensions = @getDefaultWindowDimensions()
@setWindowDimensions(dimensions)
dimensions
storeWindowDimensions: ->
dimensions = @getWindowDimensions()
@state.windowDimensions = dimensions if @isValidDimensions(dimensions)
# Public: Get the load settings for the current window.
# Call this method when establishing a real application window.
startEditorWindow: ->
{resourcePath, safeMode} = @getLoadSettings()
CommandInstaller = require './command-installer'
CommandInstaller.installAtomCommand resourcePath, false, (error) ->
console.warn error.message if error?
CommandInstaller.installApmCommand resourcePath, false, (error) ->
console.warn error.message if error?
dimensions = @restoreWindowDimensions()
@config.load()
@config.setDefaults('core', require('./workspace-view').configDefaults)
@config.setDefaults('editor', require('./editor-view').configDefaults)
@keymaps.loadBundledKeymaps()
@themes.loadBaseStylesheets()
@packages.loadPackages()
@deserializeEditorWindow()
@watchProjectPath()
@packages.activate()
@keymaps.loadUserKeymap()
@requireUserInitScript() unless safeMode
@menu.update()
maximize = dimensions?.maximized and process.platform isnt 'darwin'
@displayWindow({maximize})
unloadEditorWindow: ->
return if not @project and not @workspaceView
@state.syntax = @syntax.serialize()
@state.project = @project.serialize()
@state.workspace = @workspace.serialize()
@packages.deactivatePackages()
@state.packageStates = @packages.packageStates
@saveSync()
@windowState = null
removeEditorWindow: ->
return if not @project and not @workspaceView
@workspaceView?.remove()
@workspaceView = null
@project?.destroy()
@project = null
@windowEventHandler?.unsubscribe()
###
Section: Messaging the User
###
# Essential: Visually and audibly trigger a beep.
beep: ->
shell.beep() if @config.get('core.audioBeep')
@workspaceView.trigger 'beep'
@emitter.emit 'did-beep'
# Essential: A flexible way to open a dialog akin to an alert dialog.
#
# Returns an object containing all the load setting key/value pairs.
getLoadSettings: ->
@constructor.getLoadSettings()
# ## Examples
#
# ```coffee
# 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` (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}={}) ->
buttons ?= {}
if _.isArray(buttons)
buttonLabels = buttons
else
buttonLabels = Object.keys(buttons)
dialog = remote.require('dialog')
chosen = dialog.showMessageBox @getCurrentWindow(),
type: 'info'
message: message
detail: detailedMessage
buttons: buttonLabels
if _.isArray(buttons)
chosen
else
callback = buttons[buttonLabels[chosen]]
callback?()
###
Section: Managing the Dev Tools
###
# Extended: Open the dev tools for the current window.
openDevTools: ->
ipc.send('call-window-method', 'openDevTools')
# Extended: Toggle the visibility of the dev tools for the current window.
toggleDevTools: ->
ipc.send('call-window-method', 'toggleDevTools')
# Extended: Execute code in dev tools.
executeJavaScriptInDevTools: (code) ->
ipc.send('call-window-method', 'executeJavaScriptInDevTools', code)
###
Section: Private
###
deserializeProject: ->
Project = require './project'
@@ -289,111 +598,33 @@ class Atom extends Model
@deserializeProject()
@deserializeWorkspaceView()
# Call this method when establishing a real application window.
startEditorWindow: ->
CommandInstaller = require './command-installer'
resourcePath = atom.getLoadSettings().resourcePath
CommandInstaller.installAtomCommand resourcePath, false, (error) ->
console.warn error.message if error?
CommandInstaller.installApmCommand resourcePath, false, (error) ->
console.warn error.message if error?
@restoreWindowDimensions()
@config.load()
@config.setDefaults('core', require('./workspace-view').configDefaults)
@config.setDefaults('editor', require('./editor-view').configDefaults)
@keymaps.loadBundledKeymaps()
@themes.loadBaseStylesheets()
@packages.loadPackages()
@deserializeEditorWindow()
@packages.activate()
@keymaps.loadUserKeymap()
@requireUserInitScript()
@menu.update()
$(window).on 'unload', =>
$(document.body).css('visibility', 'hidden')
@unloadEditorWindow()
false
@displayWindow()
unloadEditorWindow: ->
return if not @project and not @workspaceView
@state.syntax = @syntax.serialize()
@state.project = @project.serialize()
@state.workspace = @workspace.serialize()
@packages.deactivatePackages()
@state.packageStates = @packages.packageStates
@saveSync()
@workspaceView.remove()
@workspaceView = null
@project.destroy()
@windowEventHandler?.unsubscribe()
@keymaps.destroy()
@windowState = null
loadThemes: ->
@themes.load()
watchThemes: ->
@themes.on 'reloaded', =>
@themes.onDidReloadAll =>
# Only reload stylesheets from non-theme packages
for pack in @packages.getActivePackages() when pack.getType() isnt 'theme'
pack.reloadStylesheets?()
null
# 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.
open: (options) ->
ipc.send('open', options)
# 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 confirm dialog.
#
# ## Example
#
# ```coffee
# 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.
#
# Returns the chosen button index {Number} if the buttons option was an array.
confirm: ({message, detailedMessage, buttons}={}) ->
buttons ?= {}
if _.isArray(buttons)
buttonLabels = buttons
else
buttonLabels = Object.keys(buttons)
exit: (status) ->
app = remote.require('app')
app.emit('will-exit')
remote.process.exit(status)
dialog = remote.require('dialog')
chosen = dialog.showMessageBox @getCurrentWindow(),
type: 'info'
message: message
detail: detailedMessage
buttons: buttonLabels
setDocumentEdited: (edited) ->
ipc.send('call-window-method', 'setDocumentEdited', edited)
if _.isArray(buttons)
chosen
else
callback = buttons[buttonLabels[chosen]]
callback?()
setRepresentedFilename: (filename) ->
ipc.send('call-window-method', 'setRepresentedFilename', filename)
showSaveDialog: (callback) ->
callback(showSaveDialogSync())
@@ -404,109 +635,6 @@ class Atom extends Model
dialog = remote.require('dialog')
dialog.showSaveDialog currentWindow, {title: 'Save File', defaultPath}
# Public: 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.
toggleDevTools: ->
ipc.send('call-window-method', 'toggleDevTools')
# Public: 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')
# Public: Focus the current window.
focus: ->
ipc.send('call-window-method', 'focus')
$(window).focus()
# Public: Show the current window.
show: ->
ipc.send('call-window-method', 'show')
# Public: Hide the current window.
hide: ->
ipc.send('call-window-method', 'hide')
# Public: Set the size of current window.
#
# width - The {Number} of pixels.
# height - The {Number} of pixels.
setSize: (width, height) ->
@getCurrentWindow().setSize(width, height)
# Public: Set the position of current window.
#
# x - The {Number} of pixels.
# y - The {Number} of pixels.
setPosition: (x, y) ->
ipc.send('call-window-method', 'setPosition', x, y)
# Public: Move current window to the center of the screen.
center: ->
ipc.send('call-window-method', 'center')
# 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: ->
setImmediate =>
@show()
@focus()
@setFullScreen(true) if @workspaceView.fullScreen
# Public: Close the current window.
close: ->
@getCurrentWindow().close()
exit: (status) ->
app = remote.require('app')
app.emit('will-exit')
remote.process.exit(status)
# Public: Is the current window in development mode?
inDevMode: ->
@getLoadSettings().devMode
# 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()
# 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()
saveSync: ->
stateString = JSON.stringify(@state)
if statePath = @constructor.getStatePath(@mode)
@@ -514,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')
@@ -546,13 +659,13 @@ 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.
#
# id - The {String} module name or path.
# globals - An {Object} to set as globals during require (default: {})
# * `id` The {String} module name or path.
# * `globals` An optinal {Object} to set as globals during require.
requireWithGlobals: (id, globals={}) ->
existingGlobals = {}
for key, value of globals
@@ -566,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}")
+1 -1
Ver Arquivo
@@ -116,7 +116,7 @@ class ApplicationMenu
item.metadata ?= {}
if item.command
item.accelerator = @acceleratorForCommand(item.command, keystrokesByCommand)
item.click = => global.atomApplication.sendCommand(item.command)
item.click = -> global.atomApplication.sendCommand(item.command)
item.metadata['windowSpecific'] = true unless /^application:/.test(item.command)
@translateTemplate(item.submenu, keystrokesByCommand) if item.submenu
template
+71 -24
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,6 +101,13 @@ class AtomApplication
window.once 'window:loaded', =>
@autoUpdateManager.emitUpdateAvailableEvent(window)
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.
#
# You can run the atom command multiple times, but after the first launch
@@ -135,7 +140,7 @@ class AtomApplication
# Registers basic application commands, non-idempotent.
handleEvents: ->
@on 'application:run-all-specs', -> @runSpecs(exitWhenDone: false, resourcePath: global.devResourcePath)
@on 'application:run-all-specs', -> @runSpecs(exitWhenDone: false, resourcePath: global.devResourcePath, safeMode: @focusedWindow()?.safeMode)
@on 'application:run-benchmarks', -> @runBenchmarks()
@on 'application:quit', -> app.quit()
@on 'application:new-window', -> @openPath(windowDimensions: @focusedWindow()?.getDimensions())
@@ -149,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()
@@ -199,13 +204,15 @@ class AtomApplication
# A request from the associated render process to open a new render process.
ipc.on 'open', (event, options) =>
window = @windowForEvent(event)
if options?
if options.pathsToOpen?.length > 0
options.window = window
@openPaths(options)
else
new AtomWindow(options)
else
@promptForPath()
@promptForPath({window})
ipc.on 'update-application-menu', (event, template, keystrokesByCommand) =>
@applicationMenu.update(template, keystrokesByCommand)
@@ -281,8 +288,12 @@ class AtomApplication
# Returns the {AtomWindow} for the given path.
windowForPath: (pathToOpen) ->
for atomWindow in @windows
return atomWindow if atomWindow.containsPath(pathToOpen)
_.find @windows, (atomWindow) -> atomWindow.containsPath(pathToOpen)
# Returns the {AtomWindow} for the given ipc event.
windowForEvent: ({sender}) ->
window = BrowserWindow.fromWebContents(sender)
_.find @windows, ({browserWindow}) -> window is browserWindow
# Public: Returns the currently focused {AtomWindow} or undefined if none.
focusedWindow: ->
@@ -296,9 +307,10 @@ class AtomApplication
# :newWindow - Boolean of whether this should be opened in a new window.
# :devMode - Boolean to control the opened window's dev mode.
# :safeMode - Boolean to control the opened window's safe mode.
openPaths: ({pathsToOpen, pidToKillWhenClosed, newWindow, devMode, safeMode}) ->
# :window - {AtomWindow} to open file paths in.
openPaths: ({pathsToOpen, pidToKillWhenClosed, newWindow, devMode, safeMode, window}) ->
for pathToOpen in pathsToOpen ? []
@openPath({pathToOpen, pidToKillWhenClosed, newWindow, devMode, safeMode})
@openPath({pathToOpen, pidToKillWhenClosed, newWindow, devMode, safeMode, window})
# Public: Opens a single path, in an existing window if possible.
#
@@ -309,15 +321,33 @@ class AtomApplication
# :devMode - Boolean to control the opened window's dev mode.
# :safeMode - Boolean to control the opened window's safe mode.
# :windowDimensions - Object with height and width keys.
openPath: ({pathToOpen, pidToKillWhenClosed, newWindow, devMode, safeMode, windowDimensions}={}) ->
# :window - {AtomWindow} to open file paths in.
openPath: ({pathToOpen, pidToKillWhenClosed, newWindow, devMode, safeMode, windowDimensions, window}={}) ->
{pathToOpen, initialLine, initialColumn} = @locationForPathToOpen(pathToOpen)
unless devMode
existingWindow = @windowForPath(pathToOpen) unless pidToKillWhenClosed or newWindow
if existingWindow
unless pidToKillWhenClosed or newWindow
pathToOpenStat = fs.statSyncNoException(pathToOpen)
# Default to using the specified window or the last focused window
currentWindow = window ? @lastFocusedWindow
if pathToOpenStat.isFile?()
# Open the file in the current window
existingWindow = currentWindow
else if pathToOpenStat.isDirectory?()
# Open the folder in the current window if it doesn't have a path
existingWindow = currentWindow unless currentWindow?.hasProjectPath()
# Don't reuse windows in dev mode
existingWindow ?= @windowForPath(pathToOpen) unless devMode
if existingWindow?
openedWindow = existingWindow
openedWindow.openPath(pathToOpen, initialLine)
openedWindow.restore()
if openedWindow.isMinimized()
openedWindow.restore()
else
openedWindow.focus()
else
if devMode
try
@@ -331,7 +361,7 @@ class AtomApplication
if pidToKillWhenClosed?
@pidsToOpenWindows[pidToKillWhenClosed] = openedWindow
openedWindow.browserWindow.on 'closed', =>
openedWindow.browserWindow.once 'closed', =>
@killProcessForWindow(openedWindow)
# Kill all processes associated with opened windows.
@@ -387,11 +417,13 @@ class AtomApplication
# Opens up a new {AtomWindow} to run specs within.
#
# options -
# :exitWhenDone - A Boolean that if true, will close the window upon
# :exitWhenDone - A Boolean that, if true, will close the window upon
# completion.
# :resourcePath - The path to include specs from.
# :specPath - The directory to load specs from.
runSpecs: ({exitWhenDone, resourcePath, specDirectory, logFile}) ->
# :safeMode - A Boolean that, if true, won't run specs from ~/.atom/packages
# and ~/.atom/dev/packages, defaults to false.
runSpecs: ({exitWhenDone, resourcePath, specDirectory, logFile, safeMode}) ->
if resourcePath isnt @resourcePath and not fs.existsSync(resourcePath)
resourcePath = @resourcePath
@@ -402,16 +434,20 @@ class AtomApplication
isSpec = true
devMode = true
new AtomWindow({bootstrapScript, resourcePath, exitWhenDone, isSpec, devMode, specDirectory, logFile})
safeMode ?= false
new AtomWindow({bootstrapScript, resourcePath, exitWhenDone, isSpec, devMode, specDirectory, logFile, safeMode})
runBenchmarks: ->
runBenchmarks: ({exitWhenDone, specDirectory}={}) ->
try
bootstrapScript = require.resolve(path.resolve(global.devResourcePath, 'benchmark', 'benchmark-bootstrap'))
catch error
bootstrapScript = require.resolve(path.resolve(__dirname, '..', '..', 'benchmark', 'benchmark-bootstrap'))
specDirectory ?= path.dirname(bootstrapScript)
isSpec = true
new AtomWindow({bootstrapScript, @resourcePath, isSpec})
devMode = true
new AtomWindow({bootstrapScript, @resourcePath, exitWhenDone, isSpec, specDirectory, devMode})
locationForPathToOpen: (pathToOpen) ->
return {pathToOpen} unless pathToOpen
@@ -438,7 +474,8 @@ class AtomApplication
# should be in dev mode or not.
# :safeMode - A Boolean which controls whether any newly opened windows
# should be in safe mode or not.
promptForPath: ({type, devMode, safeMode}={}) ->
# :window - An {AtomWindow} to use for opening a selected file path.
promptForPath: ({type, devMode, safeMode, window}={}) ->
type ?= 'all'
properties =
switch type
@@ -446,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) =>
@openPaths({pathsToOpen, devMode, safeMode})
# 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)
+23 -6
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'
@@ -20,14 +18,19 @@ class AtomWindow
isSpec: null
constructor: (settings={}) ->
{@resourcePath, pathToOpen, initialLine, initialColumn, @isSpec, @exitWhenDone} = settings
{@resourcePath, pathToOpen, initialLine, initialColumn, @isSpec, @exitWhenDone, @safeMode} = settings
# 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
'web-preferences':
'subpixel-font-scaling': false
global.atomApplication.addWindow(this)
@browserWindow = new BrowserWindow show: false, title: 'Atom', icon: @constructor.iconPath
@handleEvents()
loadSettings = _.extend({}, settings)
@@ -49,6 +52,8 @@ class AtomWindow
@emit 'window:loaded'
@loaded = true
@browserWindow.on 'project-path-changed', (@projectPath) =>
@browserWindow.loadUrl @getUrl(loadSettings)
@browserWindow.focusOnWebView() if @isSpec
@@ -66,9 +71,18 @@ class AtomWindow
slashes: true
query: {loadSettings: JSON.stringify(loadSettings)}
hasProjectPath: -> @projectPath?.length > 0
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
@@ -91,6 +105,7 @@ class AtomWindow
@browserWindow.on 'unresponsive', =>
return if @isSpec
dialog = require 'dialog'
chosen = dialog.showMessageBox @browserWindow,
type: 'warning'
buttons: ['Close', 'Keep Waiting']
@@ -101,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']
@@ -110,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
@@ -169,6 +184,8 @@ class AtomWindow
isFocused: -> @browserWindow.isFocused()
isMinimized: -> @browserWindow.isMinimized()
isWebViewFocused: -> @browserWindow.isWebViewFocused()
isSpecWindow: -> @isSpec
+24 -17
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,14 +72,14 @@ 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
getState: ->
@state
check: ({hidePopups}={})->
check: ({hidePopups}={}) ->
unless hidePopups
autoUpdater.once 'update-not-available', @onUpdateNotAvailable
autoUpdater.once 'error', @onUpdateError
@@ -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: ->
+20 -8
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,13 +55,29 @@ 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..])
options.usage """
Atom Editor v#{version}
Usage: atom [options] [file ...]
Usage: atom [options] [path ...]
One or more paths to files or folders to open may be specified.
File paths will open in the current window.
Folder paths will open in an existing window if that folder has already been
opened or a new window if it hasn't.
"""
options.alias('d', 'dev').boolean('d').describe('d', 'Run in development mode.')
options.alias('f', 'foreground').boolean('f').describe('f', 'Keep the browser process in the foreground.')
@@ -102,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}
+23 -22
Ver Arquivo
@@ -1,39 +1,40 @@
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.
#
# ## Requiring in packages
# ## Examples
#
# ```coffee
# {BufferedNodeProcess} = require 'atom'
# {BufferedNodeProcess} = require 'atom'
# ```
module.exports =
class BufferedNodeProcess extends BufferedProcess
# Public: Runs the given Node script by spawning a new child process.
#
# options - An {Object} with the following keys:
# :command - The {String} path to the JavaScript script to execute.
# :args - The {Array} of arguments to pass to the script (optional).
# :options - The options {Object} to pass to Node's `ChildProcess.spawn`
# method (optional).
# :stdout - The callback {Function} that receives a single argument which
# contains the standard output from the command. The callback is
# called as data is received but it's buffered to ensure only
# complete lines are passed until the source stream closes. After
# the source stream has closed all remaining data is sent in a
# final call (optional).
# :stderr - The callback {Function} that receives a single argument which
# contains the standard error output from the command. The
# callback is called as data is received but it's buffered to
# ensure only complete lines are passed until the source stream
# closes. After the source stream has closed all remaining data
# is sent in a final call (optional).
# :exit - The callback {Function} which receives a single argument
# containing the exit status (optional).
# * `options` An {Object} with the following keys:
# * `command` The {String} path to the JavaScript script to execute.
# * `args` The {Array} of arguments to pass to the script (optional).
# * `options` The options {Object} to pass to Node's `ChildProcess.spawn`
# method (optional).
# * `stdout` The callback {Function} that receives a single argument which
# contains the standard output from the command. The callback is
# called as data is received but it's buffered to ensure only
# complete lines are passed until the source stream closes. After
# the source stream has closed all remaining data is sent in a
# final call (optional).
# * `stderr` The callback {Function} that receives a single argument which
# contains the standard error output from the command. The
# callback is called as data is received but it's buffered to
# ensure only complete lines are passed until the source stream
# closes. After the source stream has closed all remaining data
# is sent in a final call (optional).
# * `exit` The callback {Function} which receives a single argument
# containing the exit status (optional).
constructor: ({command, args, options, stdout, stderr, exit}) ->
node =
if process.platform is 'darwin'
+73 -31
Ver Arquivo
@@ -1,10 +1,10 @@
_ = 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.
#
# ## Requiring in packages
# ## Examples
#
# ```coffee
# {BufferedProcess} = require 'atom'
@@ -19,43 +19,45 @@ module.exports =
class BufferedProcess
# Public: Runs the given command by spawning a new child process.
#
# options - An {Object} with the following keys:
# :command - The {String} command to execute.
# :args - The {Array} of arguments to pass to the command (optional).
# :options - The options {Object} to pass to Node's `ChildProcess.spawn`
# method (optional).
# :stdout - The callback {Function} that receives a single argument which
# contains the standard output from the command. The callback is
# called as data is received but it's buffered to ensure only
# complete lines are passed until the source stream closes. After
# the source stream has closed all remaining data is sent in a
# final call (optional).
# :stderr - The callback {Function} that receives a single argument which
# contains the standard error output from the command. The
# callback is called as data is received but it's buffered to
# ensure only complete lines are passed until the source stream
# closes. After the source stream has closed all remaining data
# is sent in a final call (optional).
# :exit - The callback {Function} which receives a single argument
# containing the exit status (optional).
# * `options` An {Object} with the following keys:
# * `command` The {String} command to execute.
# * `args` The {Array} of arguments to pass to the command (optional).
# * `options` The options {Object} to pass to Node's `ChildProcess.spawn`
# method (optional).
# * `stdout` The callback {Function} that receives a single argument which
# contains the standard output from the command. The callback is
# called as data is received but it's buffered to ensure only
# complete lines are passed until the source stream closes. After
# the source stream has closed all remaining data is sent in a
# final call (optional).
# * `stderr` The callback {Function} that receives a single argument which
# contains the standard error output from the command. The
# callback is called as data is received but it's buffered to
# ensure only complete lines are passed until the source stream
# closes. After the source stream has closed all remaining data
# is sent in a final call (optional).
# * `exit` The callback {Function} which receives a single argument
# containing the exit status (optional).
constructor: ({command, args, options, stdout, stderr, exit}={}) ->
options ?= {}
# Quick hack. Killing @process will only kill cmd.exe, and not the child
# process and will just orphan it. Does not escape ^ (cmd's escape symbol).
# Related to joyent/node#2318
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 = []
cmdArgs.unshift("\"#{command}\"")
if /\s/.test(command)
cmdArgs.unshift("\"#{command}\"")
else
cmdArgs.unshift(command)
cmdArgs = ['/s', '/c', "\"#{cmdArgs.join(' ')}\""]
cmdOptions = _.clone(options)
cmdOptions.windowsVerbatimArguments = true
@@ -94,9 +96,9 @@ class BufferedProcess
# Helper method to pass data line by line.
#
# stream - The Stream to read from.
# onLines - The callback to call with each line of data.
# onDone - The callback to call when the stream has closed.
# * `stream` The Stream to read from.
# * `onLines` The callback to call with each line of data.
# * `onDone` The callback to call when the stream has closed.
bufferStream: (stream, onLines, onDone) ->
stream.setEncoding('utf8')
buffered = ''
@@ -114,8 +116,48 @@ class BufferedProcess
onLines(buffered) if buffered.length > 0
onDone()
# Kill all child processes of the spawned cmd.exe process on Windows.
#
# This is required since killing the cmd.exe does not terminate child
# processes.
killOnWindows: ->
parentPid = @process.pid
cmd = 'wmic'
args = [
'process'
'where'
"(ParentProcessId=#{parentPid})"
'get'
'processid'
]
wmicProcess = ChildProcess.spawn(cmd, args)
wmicProcess.on 'error', -> # ignore errors
output = ''
wmicProcess.stdout.on 'data', (data) -> output += data
wmicProcess.stdout.on 'close', =>
pidsToKill = output.split(/\s+/)
.filter (pid) -> /^\d+$/.test(pid)
.map (pid) -> parseInt(pid)
.filter (pid) -> pid isnt parentPid and 0 < pid < Infinity
for pid in pidsToKill
try
process.kill(pid)
@killProcess()
killProcess: ->
@process?.kill()
@process = null
# Public: Terminate the process.
kill: ->
return if @killed
@killed = true
@process.kill()
@process = null
if process.platform is 'win32'
@killOnWindows()
else
@killProcess()
undefined
+14 -6
Ver Arquivo
@@ -1,9 +1,17 @@
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.
#
# ## Examples
#
# ```coffee
# atom.clipboard.write('hello')
#
# console.log(atom.clipboard.read()) # 'hello'
# ```
module.exports =
class Clipboard
metadata: null
@@ -11,7 +19,7 @@ class Clipboard
# Creates an `md5` hash of some text.
#
# text - A {String} to hash.
# * `text` A {String} to hash.
#
# Returns a hashed {String}.
md5: (text) ->
@@ -22,8 +30,8 @@ class Clipboard
# The metadata associated with the text is available by calling
# {::readWithMetadata}.
#
# text - The {String} to store.
# metadata - The additional info to associate with the text.
# * `text` The {String} to store.
# * `metadata` The additional info to associate with the text.
write: (text, metadata) ->
@signatureForMetadata = @md5(text)
@metadata = metadata
@@ -39,8 +47,8 @@ class Clipboard
# associated metadata.
#
# Returns an {Object} with the following keys:
# :text - The {String} clipboard text.
# :metadata - The metadata stored by an earlier call to {::write}.
# * `text` The {String} clipboard text.
# * `metadata` The metadata stored by an earlier call to {::write}.
readWithMetadata: ->
text = @read()
if @signatureForMetadata is @md5(text)
+1 -1
Ver Arquivo
@@ -41,7 +41,7 @@ module.exports =
callback()
return
symlinkCommand commandPath, destinationPath, (error) =>
symlinkCommand commandPath, destinationPath, (error) ->
if askForPrivilege and error?.code is 'EACCES'
try
error = null
+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
+55 -47
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.
#
@@ -15,9 +15,9 @@ pathWatcher = require 'pathwatcher'
# * Create your own root keypath using your package's name.
# * Don't depend on (or write to) configuration keys outside of your keypath.
#
# ## Example
# ## Examples
#
# ```coffeescript
# ```coffee
# atom.config.set('my-package.key', 'value')
# atom.config.observe 'my-package.key', ->
# console.log 'My configuration changed:', atom.config.get('my-package.key')
@@ -39,7 +39,7 @@ class Config
fs.makeTreeSync(@configDirPath)
queue = async.queue ({sourcePath, destinationPath}, callback) =>
queue = async.queue ({sourcePath, destinationPath}, callback) ->
fs.copy(sourcePath, destinationPath, callback)
queue.drain = done
@@ -88,37 +88,48 @@ class Config
_.extend hash, defaults
@emit 'updated'
# Public: Get the {String} path to the config file being used.
# Extended: Get the {String} path to the config file being used.
getUserConfigPath: ->
@configFilePath
# Public: Returns a new {Object} containing all of settings and defaults.
# Extended: Returns a new {Object} containing all of settings and defaults.
getSettings: ->
_.deepExtend(@settings, @defaultSettings)
# Public: Retrieves the setting for the given key.
# Essential: Retrieves the setting for the given key.
#
# keyPath - The {String} name of the key to retrieve.
# * `keyPath` The {String} name of the key to retrieve.
#
# Returns the value from Atom's default settings, the user's configuration
# file, or `null` if the key doesn't exist in either.
get: (keyPath) ->
value = _.valueForKeyPath(@settings, keyPath) ? _.valueForKeyPath(@defaultSettings, keyPath)
_.deepClone(value)
value = _.valueForKeyPath(@settings, keyPath)
defaultValue = _.valueForKeyPath(@defaultSettings, keyPath)
# Public: Retrieves the setting for the given key as an integer.
if value?
value = _.deepClone(value)
valueIsObject = _.isObject(value) and not _.isArray(value)
defaultValueIsObject = _.isObject(defaultValue) and not _.isArray(defaultValue)
if valueIsObject and defaultValueIsObject
_.defaults(value, defaultValue)
else
value = _.deepClone(defaultValue)
value
# Extended: Retrieves the setting for the given key as an integer.
#
# keyPath - The {String} name of the key to retrieve
# * `keyPath` The {String} name of the key to retrieve
#
# Returns the value from Atom's default settings, the user's configuration
# file, or `NaN` if the key doesn't exist in either.
getInt: (keyPath) ->
parseInt(@get(keyPath))
# Public: Retrieves the setting for the given key as a positive integer.
# Extended: Retrieves the setting for the given key as a positive integer.
#
# keyPath - The {String} name of the key to retrieve
# defaultValue - The integer {Number} to fall back to if the value isn't
# * `keyPath` The {String} name of the key to retrieve
# * `defaultValue` The integer {Number} to fall back to if the value isn't
# positive, defaults to 0.
#
# Returns the value from Atom's default settings, the user's configuration
@@ -126,12 +137,12 @@ class Config
getPositiveInt: (keyPath, defaultValue=0) ->
Math.max(@getInt(keyPath), 0) or defaultValue
# Public: Sets the value for a configuration setting.
# Essential: Sets the value for a configuration setting.
#
# This value is stored in Atom's internal configuration file.
#
# keyPath - The {String} name of the key.
# value - The value of the setting.
# * `keyPath` The {String} name of the key.
# * `value` The value of the setting.
#
# Returns the `value`.
set: (keyPath, value) ->
@@ -142,47 +153,47 @@ class Config
@update()
value
# Public: Toggle the value at the key path.
# Extended: Toggle the value at the key path.
#
# The new value will be `true` if the value is currently falsy and will be
# `false` if the value is currently truthy.
#
# keyPath - The {String} name of the key.
# * `keyPath` The {String} name of the key.
#
# Returns the new value.
toggle: (keyPath) ->
@set(keyPath, !@get(keyPath))
# Public: Restore the key path to its default value.
# Extended: Restore the key path to its default value.
#
# keyPath - The {String} name of the key.
# * `keyPath` The {String} name of the key.
#
# Returns the new value.
restoreDefault: (keyPath) ->
@set(keyPath, _.valueForKeyPath(@defaultSettings, keyPath))
# Public: Get the default value of the key path.
# Extended: Get the default value of the key path.
#
# keyPath - The {String} name of the key.
# * `keyPath` The {String} name of the key.
#
# Returns the default value.
getDefault: (keyPath) ->
defaultValue = _.valueForKeyPath(@defaultSettings, keyPath)
_.deepClone(defaultValue)
# Public: Is the key path value its default value?
# Extended: Is the key path value its default value?
#
# keyPath - The {String} name of the key.
# * `keyPath` The {String} name of the key.
#
# Returns a {Boolean}, `true` if the current value is the default, `false`
# otherwise.
isDefault: (keyPath) ->
not _.valueForKeyPath(@settings, keyPath)?
# Public: Push the value to the array at the key path.
# Extended: Push the value to the array at the key path.
#
# keyPath - The {String} key path.
# value - The value to push to the array.
# * `keyPath` The {String} key path.
# * `value` The value to push to the array.
#
# Returns the new array length {Number} of the setting.
pushAtKeyPath: (keyPath, value) ->
@@ -191,10 +202,10 @@ class Config
@set(keyPath, arrayValue)
result
# Public: Add the value to the beginning of the array at the key path.
# Extended: Add the value to the beginning of the array at the key path.
#
# keyPath - The {String} key path.
# value - The value to shift onto the array.
# * `keyPath` The {String} key path.
# * `value` The value to shift onto the array.
#
# Returns the new array length {Number} of the setting.
unshiftAtKeyPath: (keyPath, value) ->
@@ -205,8 +216,8 @@ class Config
# Public: Remove the value from the array at the key path.
#
# keyPath - The {String} key path.
# value - The value to remove from the array.
# * `keyPath` The {String} key path.
# * `value` The value to remove from the array.
#
# Returns the new array value of the setting.
removeAtKeyPath: (keyPath, value) ->
@@ -215,20 +226,17 @@ class Config
@set(keyPath, arrayValue)
result
# Public: Establishes an event listener for a given key.
# Essential: Add a listener for changes to a given key path.
#
# `callback` is fired whenever the value of the key is changed and will
# be fired immediately unless the `callNow` option is `false`.
#
# keyPath - The {String} name of the key to observe
# options - An optional {Object} containing the `callNow` key.
# callback - The {Function} to call when the value of the key changes.
# The first argument will be the new value of the key and the
#   second argument will be an {Object} with a `previous` property
# that is the prior value of the key.
# * `keyPath` The {String} name of the key to observe
# * `options` An optional {Object} containing the `callNow` key.
# * `callback` The {Function} to call when the value of the key changes.
# The first argument will be the new value of the key and the
#   second argument will be an {Object} with a `previous` property
# that is the prior value of the key.
#
# Returns an {Object} with the following keys:
# :off - A {Function} that unobserves the `keyPath` when called.
# * `off` A {Function} that unobserves the `keyPath` when called.
observe: (keyPath, options={}, callback) ->
if _.isFunction(options)
callback = options
@@ -248,9 +256,9 @@ class Config
callback(value) if options.callNow ? true
subscription
# Public: Unobserve all callbacks on a given key.
# Unobserve all callbacks on a given key.
#
# keyPath - The {String} name of the key to unobserve.
# * `keyPath` The {String} name of the key to unobserve.
unobserve: (keyPath) ->
@off("updated.#{keyPath.replace(/\./, '-')}")
+31 -17
Ver Arquivo
@@ -1,15 +1,18 @@
{$} = require './space-pen-extensions'
_ = require 'underscore-plus'
remote = require 'remote'
path = require 'path'
CSON = require 'season'
fs = require 'fs-plus'
# Public: Provides a registry for commands that you'd like to appear in the
# 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`
# global.
module.exports =
class ContextMenuManager
constructor: (@devMode=false) ->
constructor: ({@resourcePath, @devMode}) ->
@definitions = {}
@devModeDefinitions = {}
@activeElement = null
@@ -21,16 +24,22 @@ class ContextMenuManager
@commandOptions = x: e.pageX, y: e.pageY
]
atom.keymaps.onDidLoadBundledKeymaps => @loadPlatformItems()
loadPlatformItems: ->
menusDirPath = path.join(@resourcePath, 'menus')
platformMenuPath = fs.resolve(menusDirPath, process.platform, ['cson', 'json'])
map = CSON.readFileSync(platformMenuPath)
atom.contextMenu.add(platformMenuPath, map['context-menu'])
# Public: Creates menu definitions from the object specified by the menu
# cson API.
# JSON API.
#
# name - The path of the file that contains the menu definitions.
# object - The 'context-menu' object specified in the menu cson API.
# options - An {Object} with the following keys:
# :devMode - Determines whether the entries should only be shown when
# the window is in dev mode.
#
# Returns nothing.
# * `name` The path of the file that contains the menu definitions.
# * `object` The 'context-menu' object specified in the menu JSON API.
# * `options` An optional {Object} with the following keys:
# * `devMode` Determines whether the entries should only be shown when
# the window is in dev mode.
add: (name, object, {devMode}={}) ->
for selector, items of object
for label, commandOrSubmenu of items
@@ -43,6 +52,8 @@ class ContextMenuManager
menuItem = @buildMenuItem(label, commandOrSubmenu)
@addBySelector(selector, menuItem, {devMode})
undefined
buildMenuItem: (label, command) ->
if command is '-'
{type: 'separator'}
@@ -52,12 +63,12 @@ class ContextMenuManager
# Registers a command to be displayed when the relevant item is right
# clicked.
#
# selector - The css selector for the active element which should include
# the given command in its context menu.
# definition - The object containing keys which match the menu template API.
# options - An {Object} with the following keys:
# :devMode - Indicates whether this command should only appear while the
# editor is in dev mode.
# * `selector` The css selector for the active element which should include
# the given command in its context menu.
# * `definition` The object containing keys which match the menu template API.
# * `options` An optional {Object} with the following keys:
# * `devMode` Indicates whether this command should only appear while the
# editor is in dev mode.
addBySelector: (selector, definition, {devMode}={}) ->
definitions = if devMode then @devModeDefinitions else @definitions
if not _.findWhere(definitions[selector], definition) or _.isEqual(definition, {type: 'separator'})
@@ -79,7 +90,7 @@ class ContextMenuManager
# active element are listed first. The further down the list you go, the higher
# up the ancestor hierarchy they match.
#
# element - The DOM element to generate the menu template for.
# * `element` The DOM element to generate the menu template for.
menuTemplateForMostSpecificElement: (element, {devMode}={}) ->
menuTemplate = @definitionsForElement(element, {devMode})
if element.parentElement
@@ -109,9 +120,12 @@ class ContextMenuManager
delete template.executeAtBuild
# Public: Request a context menu to be displayed.
#
# * `event` A DOM event.
showForEvent: (event) ->
@activeElement = event.target
menuTemplate = @combinedMenuTemplateForElement(event.target)
return unless menuTemplate?.length > 0
@executeBuildHandlers(event, menuTemplate)
remote.getCurrentWindow().emit('context-menu', menuTemplate)
undefined
-113
Ver Arquivo
@@ -1,113 +0,0 @@
{View} = require './space-pen-extensions'
_ = require 'underscore-plus'
module.exports =
class CursorView extends View
@content: ->
@div class: 'cursor idle', => @raw '&nbsp;'
@blinkPeriod: 800
@blinkCursors: ->
element.classList.toggle('blink-off') for [element] in @cursorViews
@startBlinking: (cursorView) ->
@cursorViews ?= []
@cursorViews.push(cursorView)
if @cursorViews.length is 1
@blinkInterval = setInterval(@blinkCursors.bind(this), @blinkPeriod / 2)
@stopBlinking: (cursorView) ->
cursorView[0].classList.remove('blink-off')
_.remove(@cursorViews, cursorView)
clearInterval(@blinkInterval) if @cursorViews.length is 0
blinking: false
visible: true
needsUpdate: true
needsRemoval: false
shouldPauseBlinking: false
initialize: (@cursor, @editorView) ->
@subscribe @cursor, 'moved', =>
@needsUpdate = true
@shouldPauseBlinking = true
@subscribe @cursor, 'visibility-changed', =>
@needsUpdate = true
@subscribe @cursor, 'autoscrolled', =>
@editorView.requestDisplayUpdate()
@subscribe @cursor, 'destroyed', =>
@needsRemoval = true
beforeRemove: ->
@editorView.removeCursorView(this)
@stopBlinking()
updateDisplay: ->
screenPosition = @getScreenPosition()
pixelPosition = @getPixelPosition()
unless _.isEqual(@lastPixelPosition, pixelPosition)
@lastPixelPosition = pixelPosition
@css(pixelPosition)
@trigger 'cursor:moved'
if @shouldPauseBlinking
@resetBlinking()
else if !@startBlinkingTimeout
@startBlinking()
@setVisible(@cursor.isVisible() and not @editorView.getEditor().isFoldedAtScreenRow(screenPosition.row))
# Override for speed. The base function checks the computedStyle
isHidden: ->
this[0].style.display is 'none' or not @isOnDom()
needsAutoscroll: ->
@cursor.needsAutoscroll
clearAutoscroll: ->
@cursor.clearAutoscroll()
getPixelPosition: ->
@editorView.pixelPositionForScreenPosition(@getScreenPosition())
setVisible: (visible) ->
unless @visible is visible
@visible = visible
hiddenCursor = 'hidden-cursor'
if visible
@removeClass hiddenCursor
else
@addClass hiddenCursor
stopBlinking: ->
@constructor.stopBlinking(this) if @blinking
@blinking = false
startBlinking: ->
@constructor.startBlinking(this) unless @blinking
@blinking = true
resetBlinking: ->
@stopBlinking()
@startBlinking()
getBufferPosition: ->
@cursor.getBufferPosition()
getScreenPosition: ->
@cursor.getScreenPosition()
removeIdleClassTemporarily: ->
@removeClass 'idle'
window.clearTimeout(@idleTimeout) if @idleTimeout
@idleTimeout = window.setTimeout (=> @addClass 'idle'), 200
resetCursorAnimation: ->
window.clearTimeout(@idleTimeout) if @idleTimeout
@removeClass 'idle'
_.defer => @addClass 'idle'
+336 -203
Ver Arquivo
@@ -1,8 +1,10 @@
{Point, Range} = require 'text-buffer'
{Model} = require 'theorist'
{Emitter} = require 'event-kit'
_ = require 'underscore-plus'
Grim = require 'grim'
# Public: The `Cursor` class represents the little blinking line identifying
# Extended: The `Cursor` class represents the little blinking line identifying
# where text can be inserted.
#
# Cursors belong to {Editor}s and have some metadata attached in the form
@@ -17,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
@@ -38,36 +42,80 @@ 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.
#
# screenPosition - An {Array} of two numbers: the screen row, and the screen
# column.
# options - An {Object} with the following keys:
# :autoscroll - A Boolean which, if `true`, scrolls the {Editor} to wherever
# the cursor moves to.
# * `screenPosition` {Array} of two numbers: the screen row, and the screen column.
# * `options` (optional) {Object} with the following keys:
# * `autoscroll` A Boolean which, if `true`, scrolls the {Editor} to wherever
# the cursor moves to.
setScreenPosition: (screenPosition, options={}) ->
@changePosition options, =>
@marker.setHeadScreenPosition(screenPosition, options)
@@ -76,17 +124,12 @@ 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 - An {Array} of two numbers: the buffer row, and the buffer
# column.
# options - An {Object} with the following keys:
# :autoscroll - A Boolean which, if `true`, scrolls the {Editor} to wherever
# the cursor moves to.
# * `bufferPosition` {Array} of two numbers: the buffer row, and the buffer column.
# * `options` (optional) {Object} with the following keys:
# * `autoscroll` A Boolean which, if `true`, scrolls the {Editor} to wherever
# the cursor moves to.
setBufferPosition: (bufferPosition, options={}) ->
@changePosition options, =>
@marker.setHeadBufferPosition(bufferPosition, options)
@@ -95,47 +138,38 @@ class Cursor extends Model
getBufferPosition: ->
@marker.getHeadBufferPosition()
autoscroll: ->
@editor.scrollToScreenRange(@getScreenRange())
# 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: An 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.getCursor()
# 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.
#
@@ -173,37 +207,50 @@ 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.lineForBufferRow(@getBufferRow())
###
Section: Moving the Cursor
###
# Public: Moves the cursor up one screen row.
moveUp: (rowCount = 1, {moveToEndOfSelection}={}) ->
#
# * `rowCount` (optional) {Number} number of rows to move (default: 1)
# * `options` (optional) {Object} with the following keys:
# * `moveToEndOfSelection` if true, move to the left of the selection if a
# selection exists.
moveUp: (rowCount=1, {moveToEndOfSelection}={}) ->
range = @marker.getScreenRange()
if moveToEndOfSelection and not range.isEmpty()
{ row, column } = range.start
@@ -215,7 +262,12 @@ class Cursor extends Model
@goalColumn = column
# Public: Moves the cursor down one screen row.
moveDown: (rowCount = 1, {moveToEndOfSelection}={}) ->
#
# * `rowCount` (optional) {Number} number of rows to move (default: 1)
# * `options` (optional) {Object} with the following keys:
# * `moveToEndOfSelection` if true, move to the left of the selection if a
# selection exists.
moveDown: (rowCount=1, {moveToEndOfSelection}={}) ->
range = @marker.getScreenRange()
if moveToEndOfSelection and not range.isEmpty()
{ row, column } = range.end
@@ -228,30 +280,51 @@ class Cursor extends Model
# Public: Moves the cursor left one screen column.
#
# options - An {Object} with the following keys:
# :moveToEndOfSelection - if true, move to the left of the selection if a
# selection exists.
moveLeft: ({moveToEndOfSelection}={}) ->
# * `columnCount` (optional) {Number} number of columns to move (default: 1)
# * `options` (optional) {Object} with the following keys:
# * `moveToEndOfSelection` if true, move to the left of the selection if a
# selection exists.
moveLeft: (columnCount=1, {moveToEndOfSelection}={}) ->
range = @marker.getScreenRange()
if moveToEndOfSelection and not range.isEmpty()
@setScreenPosition(range.start)
else
{row, column} = @getScreenPosition()
[row, column] = if column > 0 then [row, column - 1] else [row - 1, Infinity]
while columnCount > column and row > 0
columnCount -= column
column = @editor.lineTextForScreenRow(--row).length
columnCount-- # subtract 1 for the row move
column = column - columnCount
@setScreenPosition({row, column})
# Public: Moves the cursor right one screen column.
#
# options - An {Object} with the following keys:
# :moveToEndOfSelection - if true, move to the right of the selection if a
# selection exists.
moveRight: ({moveToEndOfSelection}={}) ->
# * `columnCount` (optional) {Number} number of columns to move (default: 1)
# * `options` (optional) {Object} with the following keys:
# * `moveToEndOfSelection` if true, move to the right of the selection if a
# selection exists.
moveRight: (columnCount=1, {moveToEndOfSelection}={}) ->
range = @marker.getScreenRange()
if moveToEndOfSelection and not range.isEmpty()
@setScreenPosition(range.end)
else
{ row, column } = @getScreenPosition()
@setScreenPosition([row, column + 1], skipAtomicTokens: true, wrapBeyondNewlines: true, wrapAtSoftNewlines: true)
maxLines = @editor.getScreenLineCount()
rowLength = @editor.lineTextForScreenRow(row).length
columnsRemainingInLine = rowLength - column
while columnCount > columnsRemainingInLine and row < maxLines - 1
columnCount -= columnsRemainingInLine
columnCount-- # subtract 1 for the row move
column = 0
rowLength = @editor.lineTextForScreenRow(++row).length
columnsRemainingInLine = rowLength
column = column + columnCount
@setScreenPosition({row, column}, skipAtomicTokens: true, wrapBeyondNewlines: true, wrapAtSoftNewlines: true)
# Public: Moves the cursor to the top of the buffer.
moveToTop: ->
@@ -272,23 +345,20 @@ class Cursor extends Model
# Public: Moves the cursor to the beginning of the first character in the
# line.
moveToFirstCharacterOfLine: ->
{row, column} = @getScreenPosition()
screenline = @editor.lineForScreenRow(row)
screenRow = @getScreenRow()
lineBufferRange = @editor.bufferRangeForScreenRange([[screenRow, 0], [screenRow, Infinity]])
goalColumn = screenline.text.search(/\S/)
goalColumn = 0 if goalColumn == column or goalColumn == -1
@setScreenPosition([row, goalColumn])
firstCharacterColumn = null
@editor.scanInBufferRange /\S/, lineBufferRange, ({range, stop}) ->
firstCharacterColumn = range.start.column
stop()
# Public: Moves the cursor to the beginning of the buffer line, skipping all
# whitespace.
skipLeadingWhitespace: ->
position = @getBufferPosition()
scanRange = @getCurrentLineBufferRange()
endOfLeadingWhitespace = null
@editor.scanInBufferRange /^[ \t]*/, scanRange, ({range}) =>
endOfLeadingWhitespace = range.end
if firstCharacterColumn? and firstCharacterColumn isnt @getBufferColumn()
targetBufferColumn = firstCharacterColumn
else
targetBufferColumn = lineBufferRange.start.column
@setBufferPosition(endOfLeadingWhitespace) if endOfLeadingWhitespace.isGreaterThan(position)
@setBufferPosition([lineBufferRange.start.row, targetBufferColumn])
# Public: Moves the cursor to the end of the line.
moveToEndOfScreenLine: ->
@@ -322,16 +392,41 @@ class Cursor extends Model
if position = @getMoveNextWordBoundaryBufferPosition()
@setBufferPosition(position)
# Public: Moves the cursor to the beginning of the buffer line, skipping all
# whitespace.
skipLeadingWhitespace: ->
position = @getBufferPosition()
scanRange = @getCurrentLineBufferRange()
endOfLeadingWhitespace = null
@editor.scanInBufferRange /^[ \t]*/, scanRange, ({range}) ->
endOfLeadingWhitespace = range.end
@setBufferPosition(endOfLeadingWhitespace) if endOfLeadingWhitespace.isGreaterThan(position)
# Public: 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 - An {Object} with the following keys:
# :wordRegex - A {RegExp} indicating what constitutes a "word"
# (default: {::wordRegExp}).
# :includeNonWordCharacters - A {Boolean} indicating whether to include
# non-word characters in the default word regex.
# Has no effect if wordRegex is set.
# :allowPrevious - A {Boolean} indicating whether the beginning of the
# previous word can be returned.
# * `options` (optional) An {Object} with the following keys:
# * `wordRegex` A {RegExp} indicating what constitutes a "word"
# (default: {::wordRegExp}).
# * `includeNonWordCharacters` A {Boolean} indicating whether to include
# non-word characters in the default word regex.
# Has no effect if wordRegex is set.
# * `allowPrevious` A {Boolean} indicating whether the beginning of the
# previous word can be returned.
#
# Returns a {Range}.
getBeginningOfCurrentWordBufferPosition: (options = {}) ->
@@ -341,7 +436,7 @@ class Cursor extends Model
scanRange = [[previousNonBlankRow, 0], currentBufferPosition]
beginningOfWordPosition = null
@editor.backwardsScanInBufferRange (options.wordRegex ? @wordRegExp(options)), scanRange, ({range, stop}) =>
@editor.backwardsScanInBufferRange (options.wordRegex ? @wordRegExp(options)), scanRange, ({range, stop}) ->
if range.end.isGreaterThanOrEqual(currentBufferPosition) or allowPrevious
beginningOfWordPosition = range.start
if not beginningOfWordPosition?.isEqual(currentBufferPosition)
@@ -362,7 +457,7 @@ class Cursor extends Model
scanRange = [[previousNonBlankRow, 0], currentBufferPosition]
beginningOfWordPosition = null
@editor.backwardsScanInBufferRange (options.wordRegex ? @wordRegExp()), scanRange, ({range, stop}) =>
@editor.backwardsScanInBufferRange (options.wordRegex ? @wordRegExp()), scanRange, ({range, stop}) ->
if range.start.row < currentBufferPosition.row and currentBufferPosition.column > 0
# force it to stop at the beginning of each line
beginningOfWordPosition = new Point(currentBufferPosition.row, 0)
@@ -383,7 +478,7 @@ class Cursor extends Model
scanRange = [currentBufferPosition, @editor.getEofBufferPosition()]
endOfWordPosition = null
@editor.scanInBufferRange (options.wordRegex ? @wordRegExp()), scanRange, ({range, stop}) =>
@editor.scanInBufferRange (options.wordRegex ? @wordRegExp()), scanRange, ({range, stop}) ->
if range.start.row > currentBufferPosition.row
# force it to stop at the beginning of each line
endOfWordPosition = new Point(range.start.row, 0)
@@ -399,12 +494,12 @@ class Cursor extends Model
# Public: Retrieves the buffer position of where the current word ends.
#
# options - An {Object} with the following keys:
# :wordRegex - A {RegExp} indicating what constitutes a "word"
# (default: {::wordRegExp})
# :includeNonWordCharacters - A Boolean indicating whether to include
# non-word characters in the default word regex.
# Has no effect if wordRegex is set.
# * `options` (optional) {Object} with the following keys:
# * `wordRegex` A {RegExp} indicating what constitutes a "word"
# (default: {::wordRegExp})
# * `includeNonWordCharacters` A Boolean indicating whether to include
# non-word characters in the default word regex. Has no effect if
# wordRegex is set.
#
# Returns a {Range}.
getEndOfCurrentWordBufferPosition: (options = {}) ->
@@ -413,7 +508,7 @@ class Cursor extends Model
scanRange = [currentBufferPosition, @editor.getEofBufferPosition()]
endOfWordPosition = null
@editor.scanInBufferRange (options.wordRegex ? @wordRegExp(options)), scanRange, ({range, stop}) =>
@editor.scanInBufferRange (options.wordRegex ? @wordRegExp(options)), scanRange, ({range, stop}) ->
if range.start.isLessThanOrEqual(currentBufferPosition) or allowNext
endOfWordPosition = range.end
if not endOfWordPosition?.isEqual(currentBufferPosition)
@@ -423,18 +518,18 @@ class Cursor extends Model
# Public: Retrieves the buffer position of where the next word starts.
#
# options -
# :wordRegex - A {RegExp} indicating what constitutes a "word"
# (default: {::wordRegExp}).
# * `options` (optional) {Object}
# * `wordRegex` A {RegExp} indicating what constitutes a "word"
# (default: {::wordRegExp}).
#
# Returns a {Range}.
# Returns a {Range}
getBeginningOfNextWordBufferPosition: (options = {}) ->
currentBufferPosition = @getBufferPosition()
start = if @isInsideWord() then @getEndOfCurrentWordBufferPosition() else currentBufferPosition
scanRange = [start, @editor.getEofBufferPosition()]
beginningOfNextWordPosition = null
@editor.scanInBufferRange (options.wordRegex ? @wordRegExp()), scanRange, ({range, stop}) =>
@editor.scanInBufferRange (options.wordRegex ? @wordRegExp()), scanRange, ({range, stop}) ->
beginningOfNextWordPosition = range.start
stop()
@@ -442,9 +537,9 @@ class Cursor extends Model
# Public: Returns the buffer Range occupied by the word located under the cursor.
#
# options -
# :wordRegex - A {RegExp} indicating what constitutes a "word"
# (default: {::wordRegExp}).
# * `options` (optional) {Object}
# * `wordRegex` A {RegExp} indicating what constitutes a "word"
# (default: {::wordRegExp}).
getCurrentWordBufferRange: (options={}) ->
startOptions = _.extend(_.clone(options), allowPrevious: false)
endOptions = _.extend(_.clone(options), allowNext: false)
@@ -452,49 +547,12 @@ class Cursor extends Model
# Public: Returns the buffer Range for the current line.
#
# options -
# :includeNewline: - A {Boolean} which controls whether the Range should
# include the newline.
# * `options` (optional) {Object}
# * `includeNewline` A {Boolean} which controls whether the Range should
# include the newline.
getCurrentLineBufferRange: (options) ->
@editor.bufferRangeForBufferRow(@getBufferRow(), options)
# 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)
getBeginningOfNextParagraphBufferPosition: (editor) ->
start = @getBufferPosition()
eof = @editor.getEofBufferPosition()
scanRange = [start, eof]
{row, column} = eof
position = new Point(row, column - 1)
@editor.scanInBufferRange /^\n*$/g, scanRange, ({range, stop}) =>
if !range.start.isEqual(start)
position = range.start
stop()
@editor.screenPositionForBufferPosition(position)
getBeginningOfPreviousParagraphBufferPosition: (editor) ->
start = @editor.getCursorBufferPosition()
{row, column} = start
scanRange = [[row-1, column], [0,0]]
position = new Point(0, 0)
zero = new Point(0,0)
@editor.backwardsScanInBufferRange /^\n*$/g, scanRange, ({range, stop}) =>
if !range.start.isEqual(zero)
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.
@@ -507,35 +565,110 @@ class Cursor extends Model
getCurrentWordPrefix: ->
@editor.getTextInBufferRange([@getBeginningOfCurrentWordBufferPosition(), @getBufferPosition()])
# Public: Returns whether the cursor is at the start of a line.
isAtBeginningOfLine: ->
@getBufferPosition().column == 0
###
Section: Visibility
###
# Public: Returns the indentation level of the current line.
getIndentLevel: ->
if @editor.getSoftTabs()
@getBufferColumn() / @editor.getTabLength()
else
@getBufferColumn()
# Public: If the marker range is empty, the cursor is marked as being visible.
updateVisibility: ->
@setVisible(@marker.getBufferRange().isEmpty())
# Public: Returns whether the cursor is on the line return character.
isAtEndOfLine: ->
@getBufferPosition().isEqual(@getCurrentLineBufferRange().end)
# 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: Retrieves the grammar's token scopes for the line.
# 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.
#
# Returns an {Array} of {String}s.
getScopes: ->
@editor.scopesForBufferPosition(@getBufferPosition())
# See {Point::compare} for more details.
#
# * `otherCursor`{Cursor} to compare against
compare: (otherCursor) ->
@getBufferPosition().compare(otherCursor.getBufferPosition())
# Public: Returns true if this cursor has no non-whitespace characters before
# its current position.
hasPrecedingCharactersOnLine: ->
bufferPosition = @getBufferPosition()
line = @editor.lineForBufferRow(bufferPosition.row)
firstCharacterColumn = line.search(/\S/)
###
Section: Utilities
###
if firstCharacterColumn is -1
false
else
bufferPosition.column > firstCharacterColumn
# 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()
eof = @editor.getEofBufferPosition()
scanRange = [start, eof]
{row, column} = eof
position = new Point(row, column - 1)
@editor.scanInBufferRange /^\n*$/g, scanRange, ({range, stop}) ->
if !range.start.isEqual(start)
position = range.start
stop()
@editor.screenPositionForBufferPosition(position)
getBeginningOfPreviousParagraphBufferPosition: (editor) ->
start = @editor.getCursorBufferPosition()
{row, column} = start
scanRange = [[row-1, column], [0,0]]
position = new Point(0, 0)
zero = new Point(0,0)
@editor.backwardsScanInBufferRange /^\n*$/g, scanRange, ({range, stop}) ->
if !range.start.isEqual(zero)
position = range.start
stop()
@editor.screenPositionForBufferPosition(position)
+122 -45
Ver Arquivo
@@ -1,10 +1,12 @@
_ = require 'underscore-plus'
{Subscriber, Emitter} = require 'emissary'
EmitterMixin = require('emissary').Emitter
{Emitter} = require 'event-kit'
Grim = require 'grim'
idCounter = 0
nextId = -> idCounter++
# Public: Represents a decoration that follows a {Marker}. A decoration is
# Essential: Represents a decoration that follows a {Marker}. A decoration is
# basically a visual representation of a marker. It allows you to add CSS
# classes to line numbers in the gutter, lines, and add selection-line regions
# around marked ranges of text.
@@ -20,88 +22,163 @@ nextId = -> idCounter++
#
# Best practice for destorying the decoration is by destroying the {Marker}.
#
# ```
# ```coffee
# marker.destroy()
# ```
#
# You should only use {Decoration::destroy} when you still need or do not own
# the marker.
#
# ### IDs
# Each {Decoration} has a unique ID available via `decoration.id`.
#
# ### Events
# A couple of events are emitted:
#
# * `destroyed`: When the {Decoration} is destroyed
# * `updated`: When the {Decoration} is updated via {Decoration::update}.
# Event object has properties `oldParams` and `newParams`
#
module.exports =
class Decoration
Emitter.includeInto(this)
EmitterMixin.includeInto(this)
@isType: (decorationParams, type) ->
if _.isArray(decorationParams.type)
type in decorationParams.type
# Private: Check if the `decorationProperties.type` matches `type`
#
# * `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: (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
# Public: Destroy this marker.
@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 @isDestroyed
@isDestroyed = true
@displayBuffer.removeDecoration(this)
return if @destroyed
@markerDestroyDisposable.dispose()
@markerDestroyDisposable = null
@destroyed = true
@emit 'destroyed'
@emitter.emit 'did-destroy'
@emitter.dispose()
# Public: Update the marker with new params. Allows you to change the decoration's class.
###
Section: Event Subscription
###
# Essential: When the {Decoration} is updated via {Decoration::update}.
#
# ```
# decoration.update({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}
# * `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
# Public: Returns the marker associated with this {Decoration}
# 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
# Essential: Returns the marker associated with this {Decoration}
getMarker: -> @marker
# Public: Returns the {Decoration}'s params.
getParams: -> @params
# Public: Check if this decoration is of type `type`
#
# type - A {String} type like `'gutter'`
# * `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 a {Boolean}
# Returns {Boolean}
isType: (type) ->
Decoration.isType(@params, type)
Decoration.isType(@properties, type)
###
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
#
# ```coffee
# decoration.update({type: 'gutter', class: 'my-new-class'})
# ```
#
# * `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)
###
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)
+8 -8
Ver Arquivo
@@ -1,9 +1,9 @@
# 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.
#
# ### Registering a deserializer
# ## Examples
#
# ```coffee
# class MyPackageView extends View
@@ -24,21 +24,21 @@ class DeserializerManager
# Public: Register the given class(es) as deserializers.
#
# classes - One or more classes to register.
# * `classes` One or more classes to register.
add: (classes...) ->
@deserializers[klass.name] = klass for klass in classes
# Public: Remove the given class(es) as deserializers.
#
# classes - One or more classes to remove.
# * `classes` One or more classes to remove.
remove: (classes...) ->
delete @deserializers[name] for {name} in classes
# Public: Deserialize the state and params.
#
# state - The state {Object} to deserialize.
# params - The params {Object} to pass as the second arguments to the
# deserialize method of the deserializer.
# * `state` The state {Object} to deserialize.
# * `params` The params {Object} to pass as the second arguments to the
# deserialize method of the deserializer.
deserialize: (state, params) ->
return unless state?
@@ -51,7 +51,7 @@ class DeserializerManager
# Get the deserializer for the state.
#
# state - The state {Object} being deserialized.
# * `state` The state {Object} being deserialized.
get: (state) ->
return unless state?
-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, 'destroyed', => @destroyed()
@subscribe @bufferMarker, 'changed', (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
+150 -99
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
@@ -31,57 +33,55 @@ class DisplayBuffer extends Model
scrollTop: 0
scrollLeft: 0
scrollWidth: 0
verticalScrollbarWidth: 15
horizontalScrollbarHeight: 15
verticalScrollMargin: 2
horizontalScrollMargin: 6
horizontalScrollbarHeight: 15
verticalScrollbarWidth: 15
scopedCharacterWidthsChangeCount: 0
constructor: ({tabLength, @editorWidthInChars, @tokenizedBuffer, buffer}={}) ->
constructor: ({tabLength, @editorWidthInChars, @tokenizedBuffer, buffer, @invisibles}={}) ->
super
@softWrap ?= atom.config.get('editor.softWrap') ? false
@tokenizedBuffer ?= new TokenizedBuffer({tabLength, buffer})
@emitter = new Emitter
@softWrapped ?= atom.config.get('editor.softWrap') ? false
@tokenizedBuffer ?= new TokenizedBuffer({tabLength, buffer, @invisibles})
@buffer = @tokenizedBuffer.buffer
@charWidthsByScope = {}
@markers = {}
@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 @buffer, 'markers-updated', @handleBufferMarkersUpdated
@subscribe @buffer, 'marker-created', @handleBufferMarkerCreated
@subscribe @$softWrap, (softWrap) =>
@emit 'soft-wrap-changed', softWrap
@updateWrappedScreenLines()
@subscribe @tokenizedBuffer.onDidChange @handleTokenizedBufferChange
@subscribe @buffer.onDidUpdateMarkers @handleBufferMarkersUpdated
@subscribe @buffer.onDidCreateMarker @handleBufferMarkerCreated
@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
tokenizedBuffer: @tokenizedBuffer.serialize()
invisibles: _.clone(@invisibles)
deserializeParams: (params) ->
params.tokenizedBuffer = TokenizedBuffer.deserialize(params.tokenizedBuffer)
params
copy: ->
newDisplayBuffer = new DisplayBuffer({@buffer, tabLength: @getTabLength()})
newDisplayBuffer = new DisplayBuffer({@buffer, tabLength: @getTabLength(), @invisibles})
newDisplayBuffer.setScrollTop(@getScrollTop())
newDisplayBuffer.setScrollLeft(@getScrollLeft())
@@ -95,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
@@ -108,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.
#
@@ -152,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
@@ -177,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
@@ -250,6 +309,7 @@ class DisplayBuffer extends Model
characterWidthsChanged: ->
@computeScrollWidth()
@emit 'character-widths-changed', @scopedCharacterWidthsChangeCount
@emitter.emit 'did-change-character-widths', @scopedCharacterWidthsChangeCount
clearScopedCharWidths: ->
@charWidthsByScope = {}
@@ -340,11 +400,18 @@ class DisplayBuffer extends Model
setTabLength: (tabLength) ->
@tokenizedBuffer.setTabLength(tabLength)
# Deprecated: Use the softWrap property directly
setSoftWrap: (@softWrap) -> @softWrap
setInvisibles: (@invisibles) ->
@tokenizedBuffer.setInvisibles(@invisibles)
# Deprecated: Use the softWrap property directly
getSoftWrap: -> @softWrap
setSoftWrapped: (softWrapped) ->
if softWrapped isnt @softWrapped
@softWrapped = softWrapped
@updateWrappedScreenLines()
@emit 'soft-wrap-changed', @softWrapped
@emitter.emit 'did-change-soft-wrapped', @softWrapped
@softWrapped
isSoftWrapped: -> @softWrapped
# Set the number of characters that fit horizontally in the editor.
#
@@ -353,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.
@@ -373,25 +440,25 @@ class DisplayBuffer extends Model
# Gets the screen line for the given screen row.
#
# screenRow - A {Number} indicating the screen row.
# * `screenRow` - A {Number} indicating the screen row.
#
# Returns a {ScreenLine}.
lineForRow: (row) ->
@screenLines[row]
# Returns {TokenizedLine}
tokenizedLineForScreenRow: (screenRow) ->
@screenLines[screenRow]
# Gets the screen lines for the given screen row range.
#
# startRow - A {Number} indicating the beginning screen row.
# endRow - A {Number} indicating the ending screen row.
#
# Returns an {Array} of {ScreenLine}s.
linesForRows: (startRow, endRow) ->
# Returns an {Array} of {TokenizedLine}s.
tokenizedLinesForScreenRows: (startRow, endRow) ->
@screenLines[startRow..endRow]
# Gets all the screen lines.
#
# Returns an {Array} of {ScreenLines}s.
getLines: ->
# Returns an {Array} of {TokenizedLine}s.
getTokenizedLines: ->
new Array(@screenLines...)
indentLevelForLine: (line) ->
@@ -551,7 +618,7 @@ class DisplayBuffer extends Model
top = targetRow * @lineHeightInPixels
left = 0
column = 0
for token in @lineForRow(targetRow).tokens
for token in @tokenizedLineForScreenRow(targetRow).tokens
charWidths = @getScopedCharWidths(token.scopes)
for char in token.value
return {top, left} if column is targetColumn
@@ -569,7 +636,7 @@ class DisplayBuffer extends Model
left = 0
column = 0
for token in @lineForRow(row).tokens
for token in @tokenizedLineForScreenRow(row).tokens
charWidths = @getScopedCharWidths(token.scopes)
for char in token.value
charWidth = charWidths[char] ? defaultCharWidth
@@ -623,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()
@@ -739,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])
@@ -762,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])
@@ -771,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) ->
@@ -799,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)
@@ -888,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]
@@ -909,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)
@@ -961,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()
@@ -977,9 +1024,9 @@ class DisplayBuffer extends Model
@tokenizedBuffer.destroy()
@unsubscribe()
logLines: (start=0, end=@getLastRow())->
logLines: (start=0, end=@getLastRow()) ->
for row in [start..end]
line = @lineForRow(row).text
line = @tokenizedLineForScreenRow(row).text
console.log row, @bufferRowForScreenRow(row), line, line.length
handleTokenizedBufferChange: (tokenizedBufferChange) =>
@@ -1008,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 = []
@@ -1020,7 +1067,7 @@ class DisplayBuffer extends Model
bufferRow = startBufferRow
while bufferRow < endBufferRow
tokenizedLine = @tokenizedBuffer.lineForScreenRow(bufferRow)
tokenizedLine = @tokenizedBuffer.tokenizedLineForRow(bufferRow)
if fold = @largestFoldStartingAtBufferRow(bufferRow)
foldLine = tokenizedLine.copy()
@@ -1083,17 +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())
@emit 'marker-created', @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', marker
@emitter.emit 'did-create-marker', marker
createFoldForMarker: (marker) ->
@decorateMarker(marker, type: 'gutter', class: 'folded')
+294 -215
Ver Arquivo
@@ -1,8 +1,10 @@
_ = require 'underscore-plus'
React = require 'react-atom-fork'
{div, span} = require 'reactionary-atom-fork'
{debounce, defaults, isEqualForProperties} = require 'underscore-plus'
scrollbarStyle = require 'scrollbar-style'
{Range, Point} = require 'text-buffer'
grim = require 'grim'
GutterComponent = require './gutter-component'
InputComponent = require './input-component'
@@ -29,30 +31,27 @@ EditorComponent = React.createClass
updateRequested: false
updatesPaused: false
updateRequestedWhilePaused: false
cursorsMoved: false
cursorMoved: false
selectionChanged: false
selectionAdded: false
scrollingVertically: false
refreshingScrollbars: false
measuringScrollbars: true
mouseWheelScreenRow: null
mouseWheelScreenRowClearDelay: 150
scrollSensitivity: 0.4
heightAndWidthMeasurementRequested: false
measureLineHeightAndDefaultCharWidthWhenShown: false
remeasureCharacterWidthsWhenShown: false
inputEnabled: true
scopedCharacterWidthsChangeCount: null
domPollingInterval: 100
domPollingIntervalId: null
domPollingPaused: false
measureScrollbarsWhenShown: true
measureLineHeightAndDefaultCharWidthWhenShown: true
remeasureCharacterWidthsWhenShown: false
render: ->
{focused, showIndentGuide, showInvisibles, showLineNumbers, visible} = @state
{focused, showIndentGuide, showLineNumbers, visible} = @state
{editor, mini, cursorBlinkPeriod, cursorBlinkResumeDelay} = @props
maxLineNumberDigits = editor.getLineCount().toString().length
invisibles = if showInvisibles and not mini then @state.invisibles else {}
hasSelection = editor.getSelection()? and !editor.getSelection().isEmpty()
hasSelection = editor.getLastSelection()? and !editor.getLastSelection().isEmpty()
style = {}
if @performedInitialMeasurement
@@ -60,10 +59,13 @@ EditorComponent = React.createClass
[renderedStartRow, renderedEndRow] = renderedRowRange
cursorPixelRects = @getCursorPixelRects(renderedRowRange)
tokenizedLines = editor.tokenizedLinesForScreenRows(renderedStartRow, renderedEndRow - 1)
decorations = editor.decorationsForScreenRowRange(renderedStartRow, renderedEndRow)
highlightDecorations = @getHighlightDecorations(decorations)
lineDecorations = @getLineDecorations(decorations)
placeholderText = @props.placeholderText if @props.placeholderText? and editor.isEmpty()
visible = @isVisible()
scrollHeight = editor.getScrollHeight()
scrollWidth = editor.getScrollWidth()
@@ -107,12 +109,12 @@ EditorComponent = React.createClass
LinesComponent {
ref: 'lines',
editor, lineHeightInPixels, defaultCharWidth, lineDecorations, highlightDecorations,
editor, lineHeightInPixels, defaultCharWidth, tokenizedLines, lineDecorations, highlightDecorations,
showIndentGuide, renderedRowRange, @pendingChanges, scrollTop, scrollLeft,
@scrollingVertically, scrollHeight, scrollWidth, mouseWheelScreenRow, invisibles,
@visible, scrollViewHeight, @scopedCharacterWidthsChangeCount, lineWidth, @useHardwareAcceleration,
@scrollingVertically, scrollHeight, scrollWidth, mouseWheelScreenRow,
visible, scrollViewHeight, @scopedCharacterWidthsChangeCount, lineWidth, @useHardwareAcceleration,
placeholderText, @performedInitialMeasurement, @backgroundColor, cursorPixelRects,
cursorBlinkPeriod, cursorBlinkResumeDelay
cursorBlinkPeriod, cursorBlinkResumeDelay, mini
}
ScrollbarComponent
@@ -122,10 +124,11 @@ EditorComponent = React.createClass
onScroll: @onHorizontalScroll
scrollLeft: scrollLeft
scrollWidth: scrollWidth
visible: horizontallyScrollable and not @refreshingScrollbars and not @measuringScrollbars
visible: horizontallyScrollable
scrollableInOppositeDirection: verticallyScrollable
verticalScrollbarWidth: verticalScrollbarWidth
horizontalScrollbarHeight: horizontalScrollbarHeight
useHardwareAcceleration: @useHardwareAcceleration
ScrollbarComponent
ref: 'verticalScrollbar'
@@ -134,15 +137,16 @@ EditorComponent = React.createClass
onScroll: @onVerticalScroll
scrollTop: scrollTop
scrollHeight: scrollHeight
visible: verticallyScrollable and not @refreshingScrollbars and not @measuringScrollbars
visible: verticallyScrollable
scrollableInOppositeDirection: horizontallyScrollable
verticalScrollbarWidth: verticalScrollbarWidth
horizontalScrollbarHeight: horizontalScrollbarHeight
useHardwareAcceleration: @useHardwareAcceleration
# Also used to measure the height/width of scrollbars after the initial render
ScrollbarCornerComponent
ref: 'scrollbarCorner'
visible: not @refreshingScrollbars and (@measuringScrollbars or horizontallyScrollable and verticallyScrollable)
visible: horizontallyScrollable and verticallyScrollable
measuringScrollbars: @measuringScrollbars
height: horizontalScrollbarHeight
width: verticalScrollbarWidth
@@ -170,59 +174,60 @@ EditorComponent = React.createClass
componentDidMount: ->
{editor} = @props
@domPollingIntervalId = setInterval(@pollDOM, @domPollingInterval)
@observeEditor()
@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
if @visible = @isVisible()
@performInitialMeasurement()
@forceUpdate()
@domPollingIntervalId = setInterval(@pollDOM, @domPollingInterval)
@updateParentViewFocusedClassIfNeeded({})
@updateParentViewMiniClassIfNeeded({})
@checkForVisibilityChange()
componentWillUnmount: ->
@props.parentView.trigger 'editor:will-be-removed', [@props.parentView]
{editor, parentView} = @props
parentView.trigger 'editor:will-be-removed', [parentView]
@unsubscribe()
window.removeEventListener 'resize', @requestHeightAndWidthMeasurement
clearInterval(@domPollingIntervalId)
@domPollingIntervalId = null
componentWillUpdate: ->
wasVisible = @visible
@visible = @isVisible()
@performInitialMeasurement() if @visible and not wasVisible
componentWillReceiveProps: (newProps) ->
@props.editor.setMini(newProps.mini)
componentDidUpdate: (prevProps, prevState) ->
cursorsMoved = @cursorsMoved
cursorMoved = @cursorMoved
selectionChanged = @selectionChanged
@pendingChanges.length = 0
@cursorsMoved = false
@cursorMoved = false
@selectionChanged = false
@refreshingScrollbars = 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'
if @performedInitialMeasurement
@measureScrollbars() if @measuringScrollbars
performInitialMeasurement: ->
becameVisible: ->
@updatesPaused = true
@measureHeightAndWidth()
@sampleFontStyling()
@sampleBackgroundColors()
@measureScrollbars()
@measureHeightAndWidth()
@measureScrollbars() if @measureScrollbarsWhenShown
@measureLineHeightAndDefaultCharWidth() if @measureLineHeightAndDefaultCharWidthWhenShown
@remeasureCharacterWidths() if @remeasureCharacterWidthsWhenShown
@props.editor.setVisible(true)
@updatesPaused = false
@performedInitialMeasurement = true
@updatesPaused = false
@forceUpdate() if @updateRequestedWhilePaused
requestUpdate: ->
return unless @isMounted()
@@ -262,9 +267,9 @@ EditorComponent = React.createClass
getHiddenInputPosition: ->
{editor} = @props
{focused} = @state
return {top: 0, left: 0} unless @isMounted() and focused and editor.getCursor()?
return {top: 0, left: 0} unless @isMounted() and focused and editor.getLastCursor()?
{top, left, height, width} = editor.getCursor().getPixelRect()
{top, left, height, width} = editor.getLastCursor().getPixelRect()
width = 2 if width is 0 # Prevent autoscroll at the end of longest line
top -= editor.getScrollTop()
left -= editor.getScrollLeft()
@@ -308,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
@@ -335,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)
@@ -347,17 +352,16 @@ 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
@subscribe editor.$horizontalScrollbarHeight.changes, @requestUpdate
@subscribe editor.$height.changes, @requestUpdate
@subscribe editor.$width.changes, @requestUpdate
@subscribe editor.$defaultCharWidth.changes, @requestUpdate
@@ -405,125 +409,135 @@ EditorComponent = React.createClass
{parentView, editor, mini} = @props
@addCommandListeners
'core:move-left': => editor.moveCursorLeft()
'core:move-right': => editor.moveCursorRight()
'core:select-left': => editor.selectLeft()
'core:select-right': => editor.selectRight()
'core:select-all': => editor.selectAll()
'core:backspace': => editor.backspace()
'core:delete': => editor.delete()
'core:undo': => editor.undo()
'core:redo': => editor.redo()
'core:cut': => editor.cutSelectedText()
'core:copy': => editor.copySelectedText()
'core:paste': => editor.pasteText()
'editor:move-to-previous-word': => editor.moveCursorToPreviousWord()
'editor:select-word': => editor.selectWord()
'core:move-left': -> editor.moveLeft()
'core:move-right': -> editor.moveRight()
'core:select-left': -> editor.selectLeft()
'core:select-right': -> editor.selectRight()
'core:select-all': -> editor.selectAll()
'core:backspace': -> editor.backspace()
'core:delete': -> editor.delete()
'core:undo': -> editor.undo()
'core:redo': -> editor.redo()
'core:cut': -> editor.cutSelectedText()
'core:copy': -> editor.copySelectedText()
'core:paste': -> editor.pasteText()
'editor:move-to-previous-word': -> editor.moveToPreviousWord()
'editor:select-word': -> editor.selectWordsContainingCursors()
'editor:consolidate-selections': @consolidateSelections
'editor:delete-to-beginning-of-word': => editor.deleteToBeginningOfWord()
'editor:delete-to-beginning-of-line': => editor.deleteToBeginningOfLine()
'editor:delete-to-end-of-line': => editor.deleteToEndOfLine()
'editor:delete-to-end-of-word': => editor.deleteToEndOfWord()
'editor:delete-line': => editor.deleteLine()
'editor:cut-to-end-of-line': => editor.cutToEndOfLine()
'editor:move-to-beginning-of-next-paragraph': => editor.moveCursorToBeginningOfNextParagraph()
'editor:move-to-beginning-of-previous-paragraph': => editor.moveCursorToBeginningOfPreviousParagraph()
'editor:move-to-beginning-of-screen-line': => editor.moveCursorToBeginningOfScreenLine()
'editor:move-to-beginning-of-line': => editor.moveCursorToBeginningOfLine()
'editor:move-to-end-of-screen-line': => editor.moveCursorToEndOfScreenLine()
'editor:move-to-end-of-line': => editor.moveCursorToEndOfLine()
'editor:move-to-first-character-of-line': => editor.moveCursorToFirstCharacterOfLine()
'editor:move-to-beginning-of-word': => editor.moveCursorToBeginningOfWord()
'editor:move-to-end-of-word': => editor.moveCursorToEndOfWord()
'editor:move-to-beginning-of-next-word': => editor.moveCursorToBeginningOfNextWord()
'editor:move-to-previous-word-boundary': => editor.moveCursorToPreviousWordBoundary()
'editor:move-to-next-word-boundary': => editor.moveCursorToNextWordBoundary()
'editor:select-to-beginning-of-next-paragraph': => editor.selectToBeginningOfNextParagraph()
'editor:select-to-beginning-of-previous-paragraph': => editor.selectToBeginningOfPreviousParagraph()
'editor:select-to-end-of-line': => editor.selectToEndOfLine()
'editor:select-to-beginning-of-line': => editor.selectToBeginningOfLine()
'editor:select-to-end-of-word': => editor.selectToEndOfWord()
'editor:select-to-beginning-of-word': => editor.selectToBeginningOfWord()
'editor:select-to-beginning-of-next-word': => editor.selectToBeginningOfNextWord()
'editor:select-to-next-word-boundary': => editor.selectToNextWordBoundary()
'editor:select-to-previous-word-boundary': => editor.selectToPreviousWordBoundary()
'editor:select-to-first-character-of-line': => editor.selectToFirstCharacterOfLine()
'editor:select-line': => editor.selectLine()
'editor:transpose': => editor.transpose()
'editor:upper-case': => editor.upperCase()
'editor:lower-case': => editor.lowerCase()
'editor:delete-to-beginning-of-word': -> editor.deleteToBeginningOfWord()
'editor:delete-to-beginning-of-line': -> editor.deleteToBeginningOfLine()
'editor:delete-to-end-of-line': -> editor.deleteToEndOfLine()
'editor:delete-to-end-of-word': -> editor.deleteToEndOfWord()
'editor:delete-line': -> editor.deleteLine()
'editor:cut-to-end-of-line': -> editor.cutToEndOfLine()
'editor:move-to-beginning-of-next-paragraph': -> editor.moveToBeginningOfNextParagraph()
'editor:move-to-beginning-of-previous-paragraph': -> editor.moveToBeginningOfPreviousParagraph()
'editor:move-to-beginning-of-screen-line': -> editor.moveToBeginningOfScreenLine()
'editor:move-to-beginning-of-line': -> editor.moveToBeginningOfLine()
'editor:move-to-end-of-screen-line': -> editor.moveToEndOfScreenLine()
'editor:move-to-end-of-line': -> editor.moveToEndOfLine()
'editor:move-to-first-character-of-line': -> editor.moveToFirstCharacterOfLine()
'editor:move-to-beginning-of-word': -> editor.moveToBeginningOfWord()
'editor:move-to-end-of-word': -> editor.moveToEndOfWord()
'editor:move-to-beginning-of-next-word': -> editor.moveToBeginningOfNextWord()
'editor:move-to-previous-word-boundary': -> editor.moveToPreviousWordBoundary()
'editor:move-to-next-word-boundary': -> editor.moveToNextWordBoundary()
'editor:select-to-beginning-of-next-paragraph': -> editor.selectToBeginningOfNextParagraph()
'editor:select-to-beginning-of-previous-paragraph': -> editor.selectToBeginningOfPreviousParagraph()
'editor:select-to-end-of-line': -> editor.selectToEndOfLine()
'editor:select-to-beginning-of-line': -> editor.selectToBeginningOfLine()
'editor:select-to-end-of-word': -> editor.selectToEndOfWord()
'editor:select-to-beginning-of-word': -> editor.selectToBeginningOfWord()
'editor:select-to-beginning-of-next-word': -> editor.selectToBeginningOfNextWord()
'editor:select-to-next-word-boundary': -> editor.selectToNextWordBoundary()
'editor:select-to-previous-word-boundary': -> editor.selectToPreviousWordBoundary()
'editor:select-to-first-character-of-line': -> editor.selectToFirstCharacterOfLine()
'editor:select-line': -> editor.selectLinesContainingCursors()
'editor:transpose': -> editor.transpose()
'editor:upper-case': -> editor.upperCase()
'editor:lower-case': -> editor.lowerCase()
unless mini
@addCommandListeners
'core:move-up': => editor.moveCursorUp()
'core:move-down': => editor.moveCursorDown()
'core:move-to-top': => editor.moveCursorToTop()
'core:move-to-bottom': => editor.moveCursorToBottom()
'core:page-up': => editor.pageUp()
'core:page-down': => editor.pageDown()
'core:select-up': => editor.selectUp()
'core:select-down': => editor.selectDown()
'core:select-to-top': => editor.selectToTop()
'core:select-to-bottom': => editor.selectToBottom()
'core:select-page-up': => editor.selectPageUp()
'core:select-page-down': => editor.selectPageDown()
'editor:indent': => editor.indent()
'editor:auto-indent': => editor.autoIndentSelectedRows()
'editor:indent-selected-rows': => editor.indentSelectedRows()
'editor:outdent-selected-rows': => editor.outdentSelectedRows()
'editor:newline': => editor.insertNewline()
'editor:newline-below': => editor.insertNewlineBelow()
'editor:newline-above': => editor.insertNewlineAbove()
'editor:add-selection-below': => editor.addSelectionBelow()
'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:fold-all': => editor.foldAll()
'editor:unfold-all': => editor.unfoldAll()
'editor:fold-current-row': => editor.foldCurrentRow()
'editor:unfold-current-row': => editor.unfoldCurrentRow()
'editor:fold-selection': => editor.foldSelectedLines()
'editor:fold-at-indent-level-1': => editor.foldAllAtIndentLevel(0)
'editor:fold-at-indent-level-2': => editor.foldAllAtIndentLevel(1)
'editor:fold-at-indent-level-3': => editor.foldAllAtIndentLevel(2)
'editor:fold-at-indent-level-4': => editor.foldAllAtIndentLevel(3)
'editor:fold-at-indent-level-5': => editor.foldAllAtIndentLevel(4)
'editor:fold-at-indent-level-6': => editor.foldAllAtIndentLevel(5)
'editor:fold-at-indent-level-7': => editor.foldAllAtIndentLevel(6)
'editor:fold-at-indent-level-8': => editor.foldAllAtIndentLevel(7)
'editor:fold-at-indent-level-9': => editor.foldAllAtIndentLevel(8)
'editor:toggle-line-comments': => editor.toggleLineCommentsInSelection()
'editor:log-cursor-scope': => editor.logCursorScope()
'editor:checkout-head-revision': => editor.checkoutHead()
'editor:copy-path': => editor.copyPathToClipboard()
'editor:move-line-up': => editor.moveLineUp()
'editor:move-line-down': => editor.moveLineDown()
'editor:duplicate-lines': => editor.duplicateLines()
'editor:join-lines': => editor.joinLines()
'editor:toggle-indent-guide': => atom.config.toggle('editor.showIndentGuide')
'editor:toggle-line-numbers': => atom.config.toggle('editor.showLineNumbers')
'editor:scroll-to-cursor': => editor.scrollToCursorPosition()
'core:move-up': -> editor.moveUp()
'core:move-down': -> editor.moveDown()
'core:move-to-top': -> editor.moveToTop()
'core:move-to-bottom': -> editor.moveToBottom()
'core:page-up': -> editor.pageUp()
'core:page-down': -> editor.pageDown()
'core:select-up': -> editor.selectUp()
'core:select-down': -> editor.selectDown()
'core:select-to-top': -> editor.selectToTop()
'core:select-to-bottom': -> editor.selectToBottom()
'core:select-page-up': -> editor.selectPageUp()
'core:select-page-down': -> editor.selectPageDown()
'editor:indent': -> editor.indent()
'editor:auto-indent': -> editor.autoIndentSelectedRows()
'editor:indent-selected-rows': -> editor.indentSelectedRows()
'editor:outdent-selected-rows': -> editor.outdentSelectedRows()
'editor:newline': -> editor.insertNewline()
'editor:newline-below': -> editor.insertNewlineBelow()
'editor:newline-above': -> editor.insertNewlineAbove()
'editor:add-selection-below': -> editor.addSelectionBelow()
'editor:add-selection-above': -> editor.addSelectionAbove()
'editor:split-selections-into-lines': -> editor.splitSelectionsIntoLines()
'editor:toggle-soft-tabs': -> editor.toggleSoftTabs()
'editor:toggle-soft-wrap': -> editor.toggleSoftWrapped()
'editor:fold-all': -> editor.foldAll()
'editor:unfold-all': -> editor.unfoldAll()
'editor:fold-current-row': -> editor.foldCurrentRow()
'editor:unfold-current-row': -> editor.unfoldCurrentRow()
'editor:fold-selection': -> editor.foldSelectedLines()
'editor:fold-at-indent-level-1': -> editor.foldAllAtIndentLevel(0)
'editor:fold-at-indent-level-2': -> editor.foldAllAtIndentLevel(1)
'editor:fold-at-indent-level-3': -> editor.foldAllAtIndentLevel(2)
'editor:fold-at-indent-level-4': -> editor.foldAllAtIndentLevel(3)
'editor:fold-at-indent-level-5': -> editor.foldAllAtIndentLevel(4)
'editor:fold-at-indent-level-6': -> editor.foldAllAtIndentLevel(5)
'editor:fold-at-indent-level-7': -> editor.foldAllAtIndentLevel(6)
'editor:fold-at-indent-level-8': -> editor.foldAllAtIndentLevel(7)
'editor:fold-at-indent-level-9': -> editor.foldAllAtIndentLevel(8)
'editor:toggle-line-comments': -> editor.toggleLineCommentsInSelection()
'editor:log-cursor-scope': -> editor.logCursorScope()
'editor:checkout-head-revision': -> atom.project.getRepo()?.checkoutHeadForEditor(editor)
'editor:copy-path': -> editor.copyPathToClipboard()
'editor:move-line-up': -> editor.moveLineUp()
'editor:move-line-down': -> editor.moveLineDown()
'editor:duplicate-lines': -> editor.duplicateLines()
'editor:join-lines': -> editor.joinLines()
'editor:toggle-indent-guide': -> atom.config.toggle('editor.showIndentGuide')
'editor:toggle-line-numbers': -> atom.config.toggle('editor.showLineNumbers')
'editor:scroll-to-cursor': -> editor.scrollToCursorPosition()
'benchmark:scroll': @runScrollBenchmark
addCommandListeners: (listenersByCommandName) ->
{parentView} = @props
for command, listener of listenersByCommandName
parentView.command command, listener
addListener = (command, listener) ->
parentView.command command, (event) ->
event.stopPropagation()
listener(event)
addListener(command, listener) for command, listener of listenersByCommandName
return
observeConfig: ->
@subscribe atom.config.observe 'editor.showIndentGuide', @setShowIndentGuide
@subscribe atom.config.observe 'editor.invisibles', @setInvisibles
@subscribe atom.config.observe 'editor.showInvisibles', @setShowInvisibles
@subscribe atom.config.observe 'editor.showLineNumbers', @setShowLineNumbers
@subscribe atom.config.observe 'editor.scrollSensitivity', @setScrollSensitivity
@subscribe atom.config.observe 'editor.useHardwareAcceleration', @setUseHardwareAcceleration
onFocus: ->
@refs.input.focus()
@refs.input.focus() if @isMounted()
onTextInput: (event) ->
event.stopPropagation()
# If we prevent the insertion of a space character, then the browser
# interprets the spacebar keypress as a page-down command.
event.preventDefault() unless event.data is ' '
return unless @isInputEnabled()
{editor} = @props
@@ -536,12 +550,8 @@ EditorComponent = React.createClass
selectedLength = inputNode.selectionEnd - inputNode.selectionStart
editor.selectLeft() if selectedLength is 1
editor.insertText(event.data)
inputNode.value = event.data
inputNode.value = event.data if editor.insertText(event.data)
# If we prevent the insertion of a space character, then the browser
# interprets the spacebar keypress as a page-down command.
event.preventDefault() unless event.data is ' '
onInputFocused: ->
@setState(focused: true)
@@ -602,9 +612,17 @@ EditorComponent = React.createClass
onMouseDown: (event) ->
return unless event.button is 0 # only handle the left mouse button
return if event.target?.classList.contains('horizontal-scrollbar')
{editor} = @props
{detail, shiftKey, metaKey, ctrlKey} = event
# CTRL+click brings up the context menu on OSX, so don't handle those either
return if ctrlKey and process.platform is 'darwin'
# Prevent focusout event on hidden input if editor is already focused
event.preventDefault() if @state.focused
screenPosition = @screenPositionForMouseEvent(event)
if event.target?.classList.contains('fold-marker')
@@ -631,8 +649,12 @@ EditorComponent = React.createClass
onGutterMouseDown: (event) ->
return unless event.button is 0 # only handle the left mouse button
if event.shiftKey
{shiftKey, metaKey, ctrlKey} = event
if shiftKey
@onGutterShiftClick(event)
else if metaKey or (ctrlKey and process.platform isnt 'darwin')
@onGutterMetaClick(event)
else
@onGutterClick(event)
@@ -640,19 +662,43 @@ EditorComponent = React.createClass
{editor} = @props
clickedRow = @screenPositionForMouseEvent(event).row
editor.setCursorScreenPosition([clickedRow, 0])
editor.setSelectedScreenRange([[clickedRow, 0], [clickedRow + 1, 0]], preserveFolds: true)
@handleDragUntilMouseUp event, (screenPosition) ->
dragRow = screenPosition.row
if dragRow < clickedRow # dragging up
editor.setSelectedScreenRange([[dragRow, 0], [clickedRow + 1, 0]])
editor.setSelectedScreenRange([[dragRow, 0], [clickedRow + 1, 0]], preserveFolds: true)
else
editor.setSelectedScreenRange([[clickedRow, 0], [dragRow + 1, 0]])
editor.setSelectedScreenRange([[clickedRow, 0], [dragRow + 1, 0]], preserveFolds: true)
onGutterMetaClick: (event) ->
{editor} = @props
clickedRow = @screenPositionForMouseEvent(event).row
bufferRange = editor.bufferRangeForScreenRange([[clickedRow, 0], [clickedRow + 1, 0]])
rowSelection = editor.addSelectionForBufferRange(bufferRange, preserveFolds: true)
@handleDragUntilMouseUp event, (screenPosition) ->
dragRow = screenPosition.row
if dragRow < clickedRow # dragging up
rowSelection.setScreenRange([[dragRow, 0], [clickedRow + 1, 0]], preserveFolds: true)
else
rowSelection.setScreenRange([[clickedRow, 0], [dragRow + 1, 0]], preserveFolds: true)
# After updating the selected screen range, merge overlapping selections
editor.mergeIntersectingSelections(preserveFolds: true)
# The merge process will possibly destroy the current selection because
# it will be merged into another one. Therefore, we need to obtain a
# reference to the new selection that contains the originally selected row
rowSelection = _.find editor.getSelections(), (selection) ->
selection.intersectsBufferRange(bufferRange)
onGutterShiftClick: (event) ->
{editor} = @props
clickedRow = @screenPositionForMouseEvent(event).row
tailPosition = editor.getSelection().getTailScreenPosition()
tailPosition = editor.getLastSelection().getTailScreenPosition()
if clickedRow < tailPosition.row
editor.selectToScreenPosition([clickedRow, 0])
@@ -662,14 +708,15 @@ EditorComponent = React.createClass
@handleDragUntilMouseUp event, (screenPosition) ->
dragRow = screenPosition.row
if dragRow < tailPosition.row # dragging up
editor.setSelectedScreenRange([[dragRow, 0], tailPosition])
editor.setSelectedScreenRange([[dragRow, 0], tailPosition], preserveFolds: true)
else
editor.setSelectedScreenRange([tailPosition, [dragRow + 1, 0]])
editor.setSelectedScreenRange([tailPosition, [dragRow + 1, 0]], preserveFolds: true)
onStylesheetsChanged: (stylesheet) ->
return unless @performedInitialMeasurement
return unless atom.themes.isInitialLoadComplete()
@refreshScrollbars() if @containsScrollbarSelector(stylesheet)
@refreshScrollbars() if not stylesheet? or @containsScrollbarSelector(stylesheet)
@sampleFontStyling()
@sampleBackgroundColors()
@remeasureCharacterWidths()
@@ -679,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: ->
@@ -707,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()
@@ -766,15 +829,20 @@ EditorComponent = React.createClass
pollDOM: ->
return if @domPollingPaused or @updateRequested or not @isMounted()
wasVisible = @visible
if @visible = @isVisible()
if wasVisible
@measureHeightAndWidth()
@sampleFontStyling()
@sampleBackgroundColors()
unless @checkForVisibilityChange()
@sampleBackgroundColors()
@measureHeightAndWidth()
@sampleFontStyling()
checkForVisibilityChange: ->
if @isVisible()
if @wasVisible
false
else
@performInitialMeasurement()
@forceUpdate()
@becameVisible()
@wasVisible = true
else
@wasVisible = false
requestHeightAndWidthMeasurement: ->
return if @heightAndWidthMeasurementRequested
@@ -800,7 +868,7 @@ EditorComponent = React.createClass
if position is 'absolute' or height
if @autoHeight
@autoHeight = false
@forceUpdate()
@forceUpdate() unless @updatesPaused
clientHeight = scrollViewNode.clientHeight
editor.setHeight(clientHeight) if clientHeight > 0
@@ -842,30 +910,36 @@ EditorComponent = React.createClass
@requestUpdate() unless suppressUpdate
measureLineHeightAndDefaultCharWidth: ->
if @visible
if @isVisible()
@measureLineHeightAndDefaultCharWidthWhenShown = false
@refs.lines.measureLineHeightAndDefaultCharWidth()
else
@measureLineHeightAndDefaultCharWidthWhenShown = true
remeasureCharacterWidths: ->
if @visible
if @isVisible()
@remeasureCharacterWidthsWhenShown = false
@refs.lines.remeasureCharacterWidths()
else
@remeasureCharacterWidthsWhenShown = true
measureScrollbars: ->
return unless @visible
@measuringScrollbars = false
@measureScrollbarsWhenShown = false
{editor} = @props
scrollbarCornerNode = @refs.scrollbarCorner.getDOMNode()
width = (scrollbarCornerNode.offsetWidth - scrollbarCornerNode.clientWidth) or 15
height = (scrollbarCornerNode.offsetHeight - scrollbarCornerNode.clientHeight) or 15
cornerNode = @refs.scrollbarCorner.getDOMNode()
originalDisplayValue = cornerNode.style.display
cornerNode.style.display = 'block'
width = (cornerNode.offsetWidth - cornerNode.clientWidth) or 15
height = (cornerNode.offsetHeight - cornerNode.clientHeight) or 15
editor.setVerticalScrollbarWidth(width)
editor.setHorizontalScrollbarHeight(height)
cornerNode.style.display = originalDisplayValue
containsScrollbarSelector: (stylesheet) ->
for rule in stylesheet.cssRules
if rule.selectorText?.indexOf('scrollbar') > -1
@@ -873,24 +947,39 @@ EditorComponent = React.createClass
false
refreshScrollbars: ->
# Believe it or not, proper handling of changes to scrollbar styles requires
# three DOM updates.
if @isVisible()
@measureScrollbarsWhenShown = false
else
@measureScrollbarsWhenShown = true
return
# Scrollbar style changes won't apply to scrollbars that are already
# visible, so first we need to hide scrollbars so we can redisplay them and
# force Chromium to apply updates.
@refreshingScrollbars = true
@forceUpdate()
{verticalScrollbar, horizontalScrollbar, scrollbarCorner} = @refs
# Next, we display only the scrollbar corner so we can measure the new
# scrollbar dimensions. The ::measuringScrollbars property will be set back
# to false after the scrollbars are measured.
@measuringScrollbars = true
@forceUpdate()
verticalNode = verticalScrollbar.getDOMNode()
horizontalNode = horizontalScrollbar.getDOMNode()
cornerNode = scrollbarCorner.getDOMNode()
# Finally, we restore the scrollbars based on the newly-measured dimensions
# if the editor's content and dimensions require them to be visible.
@forceUpdate()
originalVerticalDisplayValue = verticalNode.style.display
originalHorizontalDisplayValue = horizontalNode.style.display
originalCornerDisplayValue = cornerNode.style.display
# First, hide all scrollbars in case they are visible so they take on new
# styles when they are shown again.
verticalNode.style.display = 'none'
horizontalNode.style.display = 'none'
cornerNode.style.display = 'none'
# Force a reflow
cornerNode.offsetWidth
# Now measure the new scrollbar dimensions
@measureScrollbars()
# Now restore the display value for all scrollbars, since they were
# previously hidden
verticalNode.style.display = originalVerticalDisplayValue
horizontalNode.style.display = originalHorizontalDisplayValue
cornerNode.style.display = originalCornerDisplayValue
clearMouseWheelScreenRow: ->
if @mouseWheelScreenRow?
@@ -934,24 +1023,14 @@ EditorComponent = React.createClass
setShowIndentGuide: (showIndentGuide) ->
@setState({showIndentGuide})
# Public: Defines which characters are invisible.
#
# invisibles - An {Object} defining the invisible characters:
# :eol - The end of line invisible {String} (default: `\u00ac`).
# :space - The space invisible {String} (default: `\u00b7`).
# :tab - The tab invisible {String} (default: `\u00bb`).
# :cr - The carriage return invisible {String} (default: `\u00a4`).
# Deprecated
setInvisibles: (invisibles={}) ->
defaults invisibles,
eol: '\u00ac'
space: '\u00b7'
tab: '\u00bb'
cr: '\u00a4'
@setState({invisibles})
grim.deprecate "Use config.set('editor.invisibles', invisibles) instead"
atom.config.set('editor.invisibles', invisibles)
# Deprecated
setShowInvisibles: (showInvisibles) ->
@setState({showInvisibles})
atom.config.set('editor.showInvisibles', showInvisibles)
setShowLineNumbers: (showLineNumbers) ->
@setState({showLineNumbers})
+304 -1527
Ver Arquivo
Diferenças do arquivo suprimidas por serem muito extensas Carregar Diff
+2207 -1490
Ver Arquivo
Diferenças do arquivo suprimidas por serem muito extensas Carregar Diff
+2 -2
Ver Arquivo
@@ -14,8 +14,8 @@ class Fold
@id = @marker.id
@displayBuffer.foldsByMarkerId[@marker.id] = this
@updateDisplayBuffer()
@marker.on 'destroyed', => @destroyed()
@marker.on 'changed', ({isValid}) => @destroy() unless isValid
@marker.onDidDestroy => @destroyed()
@marker.onDidChange ({isValid}) => @destroy() unless isValid
# Returns whether this fold is contained within another fold
isInsideLargerFold: ->
+302 -202
Ver Arquivo
@@ -1,13 +1,16 @@
{join} = require 'path'
{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
@@ -25,38 +28,25 @@ Task = require './task'
# repo.getShortHead('vendor/path/to/a/submodule') # 'dead1234'
# ```
#
# ## Example
# ## Examples
#
# ```coffeescript
# ### Logging the URL of the origin remote
#
# ```coffee
# git = atom.project.getRepo()
# console.log git.getOriginUrl()
# ```
#
# ## Requiring in packages
# ### Requiring in packages
#
# ```coffee
# {Git} = require 'atom'
# {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 path to the Git repository to open.
# options - An object with the following keys (default: {}):
# :refreshOnWindowFocus - `true` to refresh the index and statuses when the
# window is focused.
#
# 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()
@@ -64,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}")
@@ -86,15 +96,10 @@ class Git
if @project?
@subscribe @project.eachBuffer (buffer) => @subscribeToBuffer(buffer)
# Subscribes to buffer events.
subscribeToBuffer: (buffer) ->
@subscribe buffer, 'saved reloaded path-changed', =>
if path = buffer.getPath()
@getPathStatus(path)
@subscribe buffer, 'destroyed', => @unsubscribe(buffer)
# Public: Destroy this `Git` object. This destroys any tasks and subscriptions
# and releases the underlying libgit2 repository handle.
# Public: Destroy this {GitRepository} object.
#
# This destroys any tasks and subscriptions and releases the underlying
# libgit2 repository handle.
destroy: ->
if @statusTask?
@statusTask.terminate()
@@ -106,16 +111,48 @@ class Git
@unsubscribe()
# Returns the corresponding {Repository}
getRepo: (path) ->
if @repo?
@repo.submoduleForPath(path) ? @repo
else
throw new Error("Repository has been destroyed")
###
Section: Event Subscription
###
# Reread the index to update any values that have changed since the
# last time the index was read.
refreshIndex: -> @getRepo().refreshIndex()
# 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: ->
@@ -124,9 +161,136 @@ class Git
# 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.
# `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.
@@ -142,56 +306,75 @@ class Git
delete @statuses[relativePath]
if currentPathStatus isnt pathStatus
@emit 'status-changed', path, pathStatus
@emitter.emit 'did-change-status', {path, pathStatus}
pathStatus
# Public: Is the given path ignored?
# Public: Get the cached status for the given path.
#
# Returns a {Boolean}.
isPathIgnored: (path) -> @getRepo().isIgnored(@relativize(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 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))
###
Section: Retrieving Diffs
###
# Public: Returns true if at the root, false if in a subfolder of the
# repository.
isProjectAtRoot: ->
@projectAtRoot ?= @project?.relativize(@getWorkingDirectory()) is ''
# 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: Makes a path relative to the repository's working directory.
relativize: (path) -> @getRepo().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)
# 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()
###
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:
#
# ```
# git reset HEAD -- <path>
# git checkout HEAD -- <path>
# ```sh
# git reset HEAD -- <path>
# git checkout HEAD -- <path>
# ```
#
# path - The {String} path to checkout.
# * `path` The {String} path to checkout.
#
# Returns a {Boolean} that's true if the method was successful.
checkoutHead: (path) ->
@@ -202,145 +385,60 @@ class Git
# Public: Checks out a branch in your repository.
#
# reference - The String reference to checkout
# create - A Boolean value which, if true creates the new reference if it
# doesn't exist.
# * `reference` The {String} reference to checkout.
# * `create` A {Boolean} value which, if true creates the new reference if
# it doesn't exist.
#
# Returns a Boolean that's true if the method was successful.
checkoutReference: (reference, create) ->
@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))
###
Section: Private
###
# 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
# Subscribes to buffer events.
subscribeToBuffer: (buffer) ->
getBufferPathStatus = =>
if path = buffer.getPath()
@getPathStatus(path)
repo = @getRepo(path)
if repo.isSubmodule(repo.relativize(path))
true
@subscribe buffer.onDidSave(getBufferPathStatus)
@subscribe buffer.onDidReload(getBufferPathStatus)
@subscribe buffer.onDidChangePath(getBufferPathStatus)
@subscribe buffer.onDidDestroy => @unsubscribe(buffer)
# Subscribes to editor view event.
checkoutHeadForEditor: (editor) ->
filePath = editor.getPath()
return unless filePath
fileName = basename(filePath)
checkoutHead = =>
editor.buffer.reload() if editor.buffer.isModified()
@checkoutHead(filePath)
if atom.config.get('editor.confirmCheckoutHeadRevision')
atom.confirm
message: 'Confirm Checkout HEAD Revision'
detailedMessage: "Are you sure you want to discard all changes to \"#{fileName}\" since the last Git commit?"
buttons:
OK: checkoutHead
Cancel: null
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'
checkoutHead()
# 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
# Returns the corresponding {Repository}
getRepo: (path) ->
if @repo?
@repo.submoduleForPath(path) ? @repo
else
throw new Error("Repository has been destroyed")
# 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 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}")?
# Reread the index to update any values that have changed since the
# last time the index was read.
refreshIndex: -> @getRepo().refreshIndex()
# Refreshes the current git status in an outside process and asynchronously
# updates the relevant properties.
@@ -362,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'
+9 -1
Ver Arquivo
@@ -21,7 +21,7 @@ GutterComponent = React.createClass
if gutterBackgroundColor isnt 'rbga(0, 0, 0, 0)'
backgroundColor = gutterBackgroundColor
div className: 'gutter', onClick: @onClick, onMouseDown: onMouseDown,
div className: 'gutter', onClick: @onClick, onMouseDown: @onMouseDown,
div className: 'line-numbers', ref: 'lineNumbers', style:
height: Math.max(scrollHeight, scrollViewHeight)
WebkitTransform: @getTransform()
@@ -215,6 +215,14 @@ GutterComponent = React.createClass
lineNumberNodeForScreenRow: (screenRow) ->
@lineNumberNodesById[@lineNumberIdsByScreenRow[screenRow]]
onMouseDown: (event) ->
{editor} = @props
{target} = event
lineNumber = target.parentNode
unless target.classList.contains('icon-right') and lineNumber.classList.contains('foldable')
@props.onMouseDown(event)
onClick: (event) ->
{editor} = @props
{target} = event
-275
Ver Arquivo
@@ -1,275 +0,0 @@
{View, $, $$, $$$} = require './space-pen-extensions'
{Range} = require 'text-buffer'
_ = require 'underscore-plus'
# Represents the portion of the {EditorView} containing row numbers.
#
# The gutter also indicates if rows are folded.
module.exports =
class GutterView extends View
@content: ->
@div class: 'gutter', =>
@div outlet: 'lineNumbers', class: 'line-numbers'
firstScreenRow: null
lastScreenRow: null
initialize: ->
@elementBuilder = document.createElement('div')
afterAttach: (onDom) ->
return if @attached or not onDom
@attached = true
highlightLines = => @highlightLines()
@getEditorView().on 'cursor:moved', highlightLines
@getEditorView().on 'selection:changed', highlightLines
@on 'mousedown', (e) => @handleMouseEvents(e)
beforeRemove: ->
$(document).off(".gutter-#{@getEditorView().id}")
handleMouseEvents: (e) ->
editorView = @getEditorView()
editor = @getEditor()
startRow = editorView.screenPositionFromMouseEvent(e).row
if e.shiftKey
editor.selectToScreenPosition([startRow + 1, 0])
return
else
editor.getSelection().setScreenRange([[startRow, 0], [startRow, 0]])
moveHandler = (e) =>
start = startRow
end = editorView.screenPositionFromMouseEvent(e).row
if end > start then end++ else start++
editor.getSelection().setScreenRange([[start, 0], [end, 0]])
$(document).on "mousemove.gutter-#{editorView.id}", moveHandler
$(document).one "mouseup.gutter-#{editorView.id}", => $(document).off 'mousemove', moveHandler
# Retrieves the containing {EditorView}.
#
# Returns an {EditorView}.
getEditorView: ->
@parentView
getEditor: ->
@getEditorView().getEditor()
# Defines whether to show the gutter or not.
#
# showLineNumbers - A {Boolean} which, if `false`, hides the gutter
setShowLineNumbers: (showLineNumbers) ->
if showLineNumbers then @lineNumbers.show() else @lineNumbers.hide()
# Get all the line-number divs.
#
# Returns a list of {HTMLElement}s.
getLineNumberElements: ->
@lineNumbers[0].children
# Get all the line-number divs.
#
# Returns a list of {HTMLElement}s.
getLineNumberElementsForClass: (klass) ->
@lineNumbers[0].getElementsByClassName(klass)
# Get a single line-number div.
#
# * bufferRow: 0 based line number
#
# Returns a list of {HTMLElement}s that correspond to the bufferRow. More than
# one in the list indicates a wrapped line.
getLineNumberElement: (bufferRow) ->
@getLineNumberElementsForClass("line-number-#{bufferRow}")
# Add a class to all line-number divs.
#
# * klass: string class name
#
# Returns true if the class was added to any lines
addClassToAllLines: (klass)->
elements = @getLineNumberElements()
el.classList.add(klass) for el in elements
!!elements.length
# Remove a class from all line-number divs.
#
# * klass: string class name. Can only be one class name. i.e. 'my-class'
#
# Returns true if the class was removed from any lines
removeClassFromAllLines: (klass)->
# This is faster than calling $.removeClass on all lines, and faster than
# making a new array and iterating through it.
elements = @getLineNumberElementsForClass(klass)
willRemoveClasses = !!elements.length
elements[0].classList.remove(klass) while elements.length > 0
willRemoveClasses
# Add a class to a single line-number div
#
# * bufferRow: 0 based line number
# * klass: string class name
#
# Returns true if there were lines the class was added to
addClassToLine: (bufferRow, klass)->
elements = @getLineNumberElement(bufferRow)
el.classList.add(klass) for el in elements
!!elements.length
# Remove a class from a single line-number div
#
# * bufferRow: 0 based line number
# * klass: string class name
#
# Returns true if there were lines the class was removed from
removeClassFromLine: (bufferRow, klass)->
classesRemoved = false
elements = @getLineNumberElement(bufferRow)
for el in elements
hasClass = el.classList.contains(klass)
classesRemoved |= hasClass
el.classList.remove(klass) if hasClass
classesRemoved
updateLineNumbers: (changes, startScreenRow, endScreenRow) ->
# Check if we have something already rendered that overlaps the requested range
updateAllLines = not (startScreenRow? and endScreenRow?)
updateAllLines |= endScreenRow <= @firstScreenRow or startScreenRow >= @lastScreenRow
unless updateAllLines
for change in changes
if change.screenDelta or change.bufferDelta
updateAllLines = true
break
# Rebuild the entire gutter if a change added or removed lines
if updateAllLines
@lineNumbers[0].innerHTML = @buildLineElementsHtml(startScreenRow, endScreenRow)
# Handle changes that didn't add/remove lines more optimally
else
if startScreenRow < @firstScreenRow
@prependLineElements(@buildLineElements(startScreenRow, @firstScreenRow-1))
else if startScreenRow != @firstScreenRow
@removeLineElements(startScreenRow - @firstScreenRow)
if endScreenRow > @lastScreenRow
@appendLineElements(@buildLineElements(@lastScreenRow+1, endScreenRow))
else if endScreenRow != @lastScreenRow
@removeLineElements(endScreenRow - @lastScreenRow)
@updateFoldableClasses(changes)
@firstScreenRow = startScreenRow
@lastScreenRow = endScreenRow
@highlightedRows = null
@highlightLines()
prependLineElements: (lineElements) ->
anchor = @lineNumbers[0].children[0]
return appendLineElements(lineElements) unless anchor?
@lineNumbers[0].insertBefore(lineElements[0], anchor) while lineElements.length > 0
null # defeat coffeescript array return
appendLineElements: (lineElements) ->
@lineNumbers[0].appendChild(lineElements[0]) while lineElements.length > 0
null # defeat coffeescript array return
removeLineElements: (numberOfElements) ->
children = @getLineNumberElements()
# children is a live NodeList, so remove from the desired end {numberOfElements} times
if numberOfElements < 0
@lineNumbers[0].removeChild(children[children.length-1]) while numberOfElements++
else if numberOfElements > 0
@lineNumbers[0].removeChild(children[0]) while numberOfElements--
null # defeat coffeescript array return
buildLineElements: (startScreenRow, endScreenRow) ->
@elementBuilder.innerHTML = @buildLineElementsHtml(startScreenRow, endScreenRow)
@elementBuilder.children
buildLineElementsHtml: (startScreenRow, endScreenRow) =>
editor = @getEditor()
maxDigits = editor.getLineCount().toString().length
rows = editor.bufferRowsForScreenRows(startScreenRow, endScreenRow)
html = ''
for row in rows
if row is lastRow
rowValue = ''
else
rowValue = (row + 1).toString()
classes = "line-number line-number-#{row}"
classes += ' foldable' if row isnt lastRow and editor.isFoldableAtBufferRow(row)
classes += ' folded' if editor.isFoldedAtBufferRow(row)
rowValuePadding = _.multiplyString('&nbsp;', maxDigits - rowValue.length)
html += """<div class="#{classes}" data-buffer-row=#{row}>#{rowValuePadding}#{rowValue}<div class="icon-right"></div></div>"""
lastRow = row
html
# Called to update the 'foldable' class of line numbers when there's
# a change to the display buffer that doesn't regenerate all the line numbers
# anyway.
updateFoldableClasses: (changes) ->
editor = @getEditor()
for {start, end} in changes when start <= @lastScreenRow and end >= @firstScreenRow
startScreenRow = Math.max(start - 1, @firstScreenRow)
endScreenRow = Math.min(end + 1, @lastScreenRow)
lastBufferRow = null
for bufferRow in editor.bufferRowsForScreenRows(startScreenRow, endScreenRow) when bufferRow isnt lastBufferRow
lastBufferRow = bufferRow
if lineNumberElement = @getLineNumberElement(bufferRow)[0]
if editor.isFoldableAtBufferRow(bufferRow)
lineNumberElement.classList.add('foldable')
else
lineNumberElement.classList.remove('foldable')
removeLineHighlights: ->
return unless @highlightedLineNumbers
for line in @highlightedLineNumbers
line.classList.remove('cursor-line')
line.classList.remove('cursor-line-no-selection')
@highlightedLineNumbers = null
addLineHighlight: (row, emptySelection) ->
return if row < @firstScreenRow or row > @lastScreenRow
@highlightedLineNumbers ?= []
if highlightedLineNumber = @lineNumbers[0].children[row - @firstScreenRow]
highlightedLineNumber.classList.add('cursor-line')
highlightedLineNumber.classList.add('cursor-line-no-selection') if emptySelection
@highlightedLineNumbers.push(highlightedLineNumber)
highlightLines: ->
editor = @getEditor()
return unless editor?.isAlive()
if editor.getSelection().isEmpty()
row = editor.getCursorScreenPosition().row
rowRange = new Range([row, 0], [row, 0])
return if @selectionEmpty and @highlightedRows?.isEqual(rowRange)
@removeLineHighlights()
@addLineHighlight(row, true)
@highlightedRows = rowRange
@selectionEmpty = true
else
selectedRows = editor.getSelection().getScreenRange()
endRow = selectedRows.end.row
endRow-- if selectedRows.end.column is 0
selectedRows = new Range([selectedRows.start.row, 0], [endRow, 0])
return if not @selectionEmpty and @highlightedRows?.isEqual(selectedRows)
@removeLineHighlights()
for row in [selectedRows.start.row..selectedRows.end.row]
@addLineHighlight(row, false)
@highlightedRows = selectedRows
@selectionEmpty = false
+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'))

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