Comparar commits

...

635 Commits

Autor SHA1 Mensagem Data
Kevin Sawicki d79881063a Upgrade version to 21.0.0 2013-08-30 14:09:57 -07:00
Nathan Sobo 49b80d306b 💩 Delete files that were moved to docs/proposals
I thought I deleted these when I moved them but I guess I screwed up.
2013-08-30 15:02:51 -06:00
Nathan Sobo 91adc01e4e 🐎 Don't get every line to check for soft-tabs
Getting all the lines requires SharedString to construct a big array.
It's more efficient to check them one line at a time.
2013-08-30 14:36:45 -06:00
Kevin Sawicki & Matt Colyer 4cc553daf8 🐎 Upgrade to telepath@0.1.2 2013-08-30 11:54:08 -07:00
Kevin Sawicki & Matt Colyer 538b648042 Add more selectors to cover end of ruby embedded strings 2013-08-30 10:10:40 -07:00
Matt Colyer 78b28b6ee6 Fix color highlight issue in Ruby, #716 2013-08-30 10:10:40 -07:00
Kevin Sawicki fe725ec909 Display time in seconds instead of milliseconds 2013-08-29 21:33:21 -07:00
Kevin Sawicki 35d4eadd45 Upgrade to fuzzy-finder@0.3.0 2013-08-29 19:42:37 -07:00
Kevin Sawicki 47bccc142e Upgrade to autocomplete@0.4.0 2013-08-29 19:38:01 -07:00
Kevin Sawicki 8fb10e35a9 🚱 Destroy current project in beforeEach
Previously the window specs were calling window::deserializeEditorWindow
without first destroying the spec project causing the global to be
reassigned over and leaking the initial project and repo.
2013-08-29 18:41:27 -07:00
Kevin Sawicki 2687fafca4 🚱 Destroy environments in an afterEach
These were leaking projects and therefore repos.
2013-08-29 18:37:03 -07:00
Kevin Sawicki 40860a59f5 Destroy deserialized project in an afterEach 2013-08-29 18:24:51 -07:00
Kevin Sawicki 989fffba6a 🚱 Destroy repo in Project::setPath
Previously if the new path was non-null then the current repo would be
leaked and never destroyed
2013-08-29 18:08:01 -07:00
Corey Johnson 9f1edd3189 Use a simpler escapeRegExp method 2013-08-29 15:58:21 -07:00
Kevin Sawicki e03544bab6 Hide body when unloading
This prevents a weird UI flicker when refreshing with the settings
view open.
2013-08-29 15:23:26 -07:00
Kevin Sawicki fd9f3d6543 Don't serialize packages unless the main module was activated
The settings-view activates the config for each package before it renders
causing the main module to be required in order to call activateConfig().
This was causing serialize to be called when the window state was being
saved which was incorrect since activate hadn't actually been called even
though the main module was required.
2013-08-29 14:48:42 -07:00
Matt Colyer 19b5f3e202 Added a section to getting started guide
@xpaulbettsx noted that he wasn't aware that atom windows were tied to a
specific directory.
2013-08-29 10:40:40 -07:00
Kevin Sawicki f80ad91bec Upgrade to grammar-selector@0.2.0 2013-08-29 10:24:26 -07:00
Kevin Sawicki 1e21665b69 Upgrade to status-bar@0.3.0 2013-08-29 10:13:58 -07:00
Kevin Sawicki 57132f57bd Suppress deserialization warning during window spec 2013-08-29 09:18:52 -07:00
Kevin Sawicki de5b2c5cf1 Suppress deserialization warning during pane spec 2013-08-29 09:15:31 -07:00
Kevin Sawicki d12eed3f68 Don't build description string unless actually logging it 2013-08-28 22:19:18 -07:00
Kevin Sawicki 951b3253da Remove unused name field from tracked specs 2013-08-28 22:12:34 -07:00
Kevin Sawicki e40d837b40 Log longest specs/suites during grunt test 2013-08-28 22:07:57 -07:00
Kevin Sawicki 3e626f28c4 Only require AtomReporter if actually being used 2013-08-28 21:20:31 -07:00
Kevin Sawicki 156e9f9b24 Upgrade to collaboration@0.8.0 2013-08-28 21:10:58 -07:00
Kevin Sawicki e0ccfc4788 Use terminal reporter from jasmine-node
This gives the same filtered stack traces and text output
as all our node modules that already use jasmine-node indirectly
through jasmine-focused.
2013-08-28 20:57:43 -07:00
Kevin Sawicki 8307ae8938 💄 correct lint indentation problem 2013-08-28 20:32:35 -07:00
Kevin Sawicki 464785ec3b Map npm test to grunt test 2013-08-28 20:30:23 -07:00
Kevin Sawicki 64e47aeea8 Migrate telepath to package dependency 2013-08-28 20:24:36 -07:00
Kevin Sawicki & Nathan Sobo 2bd4386090 Destroy unretained buffers when serializing project
Previously buffers could linger indefinitely if an error occurred
during startup between the deserialization of the project and the
original retaining edit session.
2013-08-28 18:37:40 -07:00
Kevin Sawicki & Nathan Sobo 40b6183937 🐎 Don't pretty print serialized window state 2013-08-28 18:13:44 -07:00
Nathan Sobo 33dc008b10 🐎 Upgrade telepath for faster SharedArray::findMarkers method 2013-08-28 16:49:06 -06:00
Matt Colyer 9fe9e0dc41 Add documentation for Selection.expandOver* 2013-08-28 15:39:08 -07:00
Kevin Sawicki c8b7040144 🐎 Find elements by id in spec reporter
Previously classes containing the spec/suite id were used which
caused major amounts of time finding DOM nodes using class selectors
instead of id selectors.

This decreases the Editor spec from ~90s to ~30s.
2013-08-28 14:56:52 -07:00
Kevin Sawicki 8e4c9076f1 Upgrade to jasmine-focused@0.12.0 2013-08-28 14:52:32 -07:00
Kevin Sawicki 1381ffdbf5 Invoke grunt callback when shell test command completes 2013-08-28 14:19:29 -07:00
Kevin Sawicki b8c906d00e Only log warning if error occurs 2013-08-28 14:15:30 -07:00
Kevin Sawicki d9c62a76bf Implement test task using grunt shell
This prevents duplicate messages in the CI build logs.
2013-08-28 14:11:05 -07:00
Kevin Sawicki c27103db8a Expect output when -t/--test flag is specified 2013-08-28 12:54:16 -07:00
Kevin Sawicki 2f46539026 Use global.devResourcePath when running package specs
This allows package specs to be launched from windows that
are not in dev mode, previously the window would fail to launch
in this case.
2013-08-28 12:49:18 -07:00
Kevin Sawicki 6261124464 Update spec to use atom::close instead of window::close 2013-08-28 10:43:12 -07:00
Kevin Sawicki 29f1f5cbe5 Call close on native window instead of JS window
Added atom.close() which forwards to remote.getCurrentWindow().close()
since calling window.close() does not call the unload handler registered
on the window global.

Closes #764
2013-08-28 09:10:54 -07:00
Nathan Sobo 2921ac856c Fall back to empty document if window state cannot be deserialized
If the telepath serialization version has changed it will return null
from Site::deserializeDocument.
2013-08-28 10:03:40 -06:00
Nathan Sobo 4474212b3e Upgrade telepath for serialization version fix 2013-08-28 10:00:32 -06:00
Kevin Sawicki b02ac8696e Add missing parens to call to app.quit() 2013-08-28 08:09:52 -07:00
Kevin Sawicki bd96814576 Correct apm command 2013-08-28 08:01:56 -07:00
Kevin Sawicki 5091efab8e Correct apm command 2013-08-28 08:01:24 -07:00
Kevin Sawicki 14522f6769 Doc critical emoji commit message guidelines 2013-08-27 13:03:16 -07:00
Kevin Sawicki & Nathan Sobo 38422150b0 🚱 Clear blinking interval when cursor view is removed 2013-08-27 13:00:41 -07:00
Kevin Sawicki & Nathan Sobo e28ef3a76c 🚱 Call off on active item when it is removed 2013-08-27 13:00:41 -07:00
Kevin Sawicki 6baaf404af 🚱 Use subscribe for tokenized buffer event listeners 2013-08-27 13:00:41 -07:00
Kevin Sawicki f42bd3f34b 🚱 Clear config subscriptions when unobserving 2013-08-27 13:00:41 -07:00
Matt Colyer 2bca1abb2a Remove trailing whitespace 2013-08-27 10:17:02 -07:00
Matt Colyer a44662c885 Actually fix task.coffee 2013-08-27 10:17:02 -07:00
Matt Colyer 0f014463c1 Undo accidental change to method signature 2013-08-27 10:17:02 -07:00
Matt Colyer 7c55348fde Fix incorrect biscotto references 2013-08-27 10:17:01 -07:00
Matt Colyer ae59078c5d Update to biscotto 0.0.14 2013-08-27 10:17:01 -07:00
Matt Colyer 4cb1f6c509 Add comments to Task 2013-08-27 10:17:01 -07:00
Matt Colyer 16ab3e5538 Reformat Selection comments 2013-08-27 10:17:01 -07:00
Matt Colyer 696a54392e Determine public API of SelectList 2013-08-27 10:17:01 -07:00
Matt Colyer 9521358c55 Add note to scroll-view.coffee 2013-08-27 10:17:01 -07:00
Matt Colyer a5e563c04c Reformatted comments for RootView 2013-08-27 10:17:01 -07:00
Matt Colyer 631995996b Reformat comments for project.coffee 2013-08-27 10:17:01 -07:00
Matt Colyer f239cdf307 Add comments to pane.coffee 2013-08-27 10:17:01 -07:00
Matt Colyer d3e482ed6f Reformat Git comments 2013-08-27 10:17:01 -07:00
Matt Colyer 75af26ea3e Reformat comments in file.coffee 2013-08-27 10:17:00 -07:00
Matt Colyer 2d547e3b9e Reformat comments in edit-session.coffee 2013-08-27 10:17:00 -07:00
Matt Colyer e84a6b4869 Reformat Cursor class's comments to Markdown 2013-08-27 10:17:00 -07:00
Matt Colyer c1c73a822a Mark classes as private per discussion 2013-08-27 10:17:00 -07:00
Matt Colyer e774b956e0 Fix visibility of classes. 2013-08-27 10:17:00 -07:00
Matt Colyer 68affd9b08 Update Directory documentation. 2013-08-27 10:17:00 -07:00
Matt Colyer dd1a04aec0 Add visibility to comments of Cursor 2013-08-27 10:17:00 -07:00
Matt Colyer ec37ec1e49 Update Config documentation 2013-08-27 10:17:00 -07:00
Matt Colyer 3d1a27875d Update ApplicationMenu documentation 2013-08-27 10:17:00 -07:00
Matt Colyer ad69522bd1 Update buffered-process's documentation 2013-08-27 10:16:59 -07:00
Matt Colyer 0043b9de77 Update atom-application documentation to latest format 2013-08-27 10:16:59 -07:00
Matt Colyer 0abbe8affb Change to bold for documentation sections 2013-08-27 10:16:59 -07:00
Matt Colyer 1c39b851e4 Update AtomApplication to new documentation style 2013-08-27 10:16:59 -07:00
Matt Colyer fdf250871d Fix all biscoto warnings 2013-08-27 10:16:59 -07:00
Matt Colyer 0e8ec74662 Fix more TomDoc references 2013-08-27 10:16:59 -07:00
Matt Colyer 8e2777ccc0 Get class visibility correct 2013-08-27 10:16:59 -07:00
Matt Colyer d5c2878d53 Document BufferedProcess and BufferedNodeProcess 2013-08-27 10:16:59 -07:00
Matt Colyer f47fdd0ae1 Make AtomApplication class private 2013-08-27 10:16:59 -07:00
Matt Colyer 2f4cca445b Document AtomApplication 2013-08-27 10:16:58 -07:00
Matt Colyer b67496a4f2 Document ApplicationMenu 2013-08-27 10:16:58 -07:00
Matt Colyer a604e51f1c Remove redundant argument to biscotto 2013-08-27 10:16:58 -07:00
Matt Colyer 61e5e6ea28 Fix delegation references in comments 2013-08-27 10:16:58 -07:00
Matt Colyer 3808f81886 Ensure API docs have the proper title 2013-08-27 10:16:58 -07:00
Kevin Sawicki 5a2b2b18c6 Upgrade to gfm@0.2.0 2013-08-27 09:40:37 -07:00
Kevin Sawicki 437cb0ccef Upgrade to symbols-view@0.4.0 2013-08-27 08:47:11 -07:00
Kevin Sawicki decaa3dfcf 💄 Move extend calls to top of class 2013-08-26 19:09:42 -07:00
Kevin Sawicki 03573b4e06 🐎 Upgrade telepath 2013-08-26 18:50:13 -07:00
Kevin Sawicki 70162d39f7 Unsubscribe from SharedString when buffer is destroyed 2013-08-26 14:45:26 -07:00
Kevin Sawicki f6f93342bc Initialize destroyed item states before setting root 2013-08-26 13:47:28 -07:00
Kevin Sawicki b22e45b8a9 Call PaneContainer::itemAdded from PaneContainer::reopenItem
This ensures the active item in the new root is filtered out of
the reopen stack, preventing a duplicate item from being opened.
2013-08-26 13:36:55 -07:00
Kevin Sawicki 419be22b7b Use Subscriber::subscribe for telepath change listeners 2013-08-26 13:04:13 -07:00
Kevin Sawicki c5535bde81 Upgrade to spell-check@0.3.0 2013-08-26 12:25:42 -07:00
Kevin Sawicki 5640f57eae 💄 move extend calls to top of class 2013-08-23 18:33:38 -07:00
Kevin Sawicki 325d534d91 💄 spec description 2013-08-23 18:29:12 -07:00
Kevin Sawicki eaf80a0194 Rename softWrapColumn to editorWidthInChars 2013-08-23 18:09:17 -07:00
Kevin Sawicki 3f848606ee Use setEditorWidthInChars to resize editor
This makes the comparisons for the soft wrap column more sane.
2013-08-23 18:09:17 -07:00
Kevin Sawicki c2b3c2e3aa Rename callbackImmediately option to callNow 2013-08-23 18:09:17 -07:00
Kevin Sawicki 08b80c15ad 💄 Remove comment for removed parameter 2013-08-23 18:09:17 -07:00
Kevin Sawicki 052a489751 💄 toggle comments 2013-08-23 18:09:17 -07:00
Kevin Sawicki 51192bb3e9 Remove config listeners when DisplayBuffer is destroyed 2013-08-23 18:09:17 -07:00
Kevin Sawicki 32396a2a8b Update soft wrapped lines when config changes
DisplayBuffer now observes for config changes to the preferred line length
and the preference to soft wrap at the preferred line length to update
any wrapped screen lines.
2013-08-23 18:09:16 -07:00
Kevin Sawicki a45b93614e Add editor.softWrapAtPreferredLineLength config setting
This is used by the DisplayBuffer to use `editor.preferredLineLength`
as the soft wrap column instead of the editor size.
2013-08-23 18:09:16 -07:00
Kevin Sawicki 8f193e4fb5 Remove default edit session options from Project
Instead read the config values directly where they are actually
used such as in EditSession, TokenizedBuffer, and DisplayBuffer.
2013-08-23 18:09:16 -07:00
Kevin Sawicki cbd4fab8f2 Emit event from display buffer when soft wrap changes
This allows the editor to be reactive to the edit session
and always respect the edit session's current value when
initially opened.
2013-08-23 18:09:16 -07:00
Kevin Sawicki 8b3b033b09 Add explicit call to setSoftWrap in specs
This is now required now that setting the soft wrap
column does not cause wrapping unless soft wrap is enabled.
2013-08-23 18:09:16 -07:00
Kevin Sawicki e675fe73c8 Set soft wrap explicitly on the display buffer
This is required now that soft wrap column only takes affect
when soft wrap is enabled.
2013-08-23 18:09:16 -07:00
Kevin Sawicki 0b7262aa62 Always calculate the soft wrap column 2013-08-23 18:09:16 -07:00
Kevin Sawicki 5001c6e84e Enable soft wrap explicitly in specs
This is required now that the soft wrap setting and soft wrap
column are decoupled.
2013-08-23 18:09:16 -07:00
Kevin Sawicki a4411ab2ca Update specs for resize handler changes 2013-08-23 18:09:16 -07:00
Kevin Sawicki 5ea8c6c27b Don't store soft wrap column on EditSession
This removes duplicate state between the edit session and
display buffer.
2013-08-23 18:09:16 -07:00
Kevin Sawicki da1e5f5c10 Always update the soft wrap column when the window resizes
This allows the edit session and display buffer to always be
notified of soft wrap column changes regardless of their initial
soft wrap state.
2013-08-23 18:09:16 -07:00
Kevin Sawicki c33f7cde2a Move soft wrap state from EditSession to DisplayBuffer 2013-08-23 18:09:16 -07:00
Kevin Sawicki a39e136c43 💄 2013-08-23 18:09:16 -07:00
Kevin Sawicki 275ee62e8d 💩 Upgrade telepath 2013-08-23 15:50:50 -07:00
Kevin Sawicki 62a19aa6fa 🐎 Upgrade telepath 2013-08-23 15:18:15 -07:00
probablycorey 78b9a99f86 Add window:run-package-specs command
This will only run specs found in the current projects spec directory
2013-08-23 09:02:22 -07:00
probablycorey ba632751a0 Rename application:run-specs to application:run-all-specs 2013-08-23 09:02:22 -07:00
Nathan Sobo 96a16494ff Add a proposals folder in docs and put the private beta stuff there 2013-08-22 21:21:40 -06:00
Nathan Sobo a39d1c274e 🐎 Upgrade telepath for performance improvements
Again, addresses #734 but we're still too slow.
2013-08-22 19:24:43 -06:00
Kevin Sawicki de8dab5939 Upgrade to collaboration@0.7.0 2013-08-22 14:53:35 -07:00
Kevin Sawicki f32a289193 Store relative buffer path instead of id
This allows the tokenized buffer to be deserialized during reopening
from the pane container.

Closes #744
2013-08-22 14:42:08 -07:00
Kevin Sawicki 92a80208d3 Update the relative path when the buffer's file moves 2013-08-22 13:59:46 -07:00
Kevin Sawicki 2793ebb5c4 Remove unused bufferId from edit session document
This is now on tokenized buffer instead.
2013-08-22 13:07:28 -07:00
Kevin Sawicki 44d90615ec Remove unused ivar 2013-08-22 13:05:51 -07:00
Kevin Sawicki 7bf350251e Add EditSession::getRelativePath
Closes #746
2013-08-22 12:16:44 -07:00
Kevin Sawicki e4b5cfd600 Call AtomPackage::deactivateConfig from AtomPackage::deactivate
This adds back support for a package's main module implementing
deactivateConfig.
2013-08-22 11:13:32 -07:00
Kevin Sawicki 20a669e94f Upgrade to settings-view@0.8.0 2013-08-22 11:04:03 -07:00
Kevin Sawicki 25be233c5f Call AtomPackage::activateConfig from AtomPackage::activateNow
Previously this method was unused and so packages implementing
activateConfig were not being called.
2013-08-22 11:01:17 -07:00
Matt Colyer 13f35bc6e3 Fix documentation links 2013-08-22 10:43:45 -07:00
Joel Glovier 2efc39a265 Fixed broken links in ReadMe 2013-08-22 13:31:31 -04:00
Joel Glovier 1a31e3418d Fixed broken links for configuring.md, theming.md, and extending.md 2013-08-22 13:29:37 -04:00
Joel Glovier 090d350802 Fixed broken links to configuring.md, theming.md and extending.md 2013-08-22 13:28:33 -04:00
Joel Glovier 4f547b8c21 Fixed broken links to configuring, theming, and extending. 2013-08-22 13:27:52 -04:00
Kevin Sawicki 76992dfaeb Upgrade to autocomplete@0.3.0 2013-08-22 09:32:52 -07:00
Kevin Sawicki 070a72e76c Add ctrl-A/E keybinding to select to beginning/end of line
Closes #711
2013-08-22 09:00:02 -07:00
Kevin Sawicki 95a23cdada Add default config for editor.softTabs 2013-08-21 18:53:34 -07:00
Kevin Sawicki 6fa0c82fac Mention soft wrap and tab length setting 2013-08-21 18:52:14 -07:00
Kevin Sawicki a0db412140 Use editor.softTabs config value when creating edit sessions
This replaces the internal softWrap state and removes the previous
getter and setter for this value that was on Project.
2013-08-21 18:12:26 -07:00
Kevin Sawicki 2f4a57e5e4 Remove get/setSoftWrap from Project
The config should now be the place that soft wrap settings is interacted
with.
2013-08-21 18:08:59 -07:00
Kevin Sawicki 0da647acdf Use display: inline for editor fold marker
This prevents it from wrapping to the next line when the window
is narrower than the line length.

Closes #211
2013-08-21 17:52:19 -07:00
Kevin Sawicki 147e75ad95 Use editor.softWrap config value when creating edit sessions
Closes #666
2013-08-21 17:17:06 -07:00
Kevin Sawicki 2f4db45320 Use editor.tabLength config value when creating edit sessions
Closes #708
2013-08-21 17:12:04 -07:00
Kevin Sawicki c18810ca67 Upgrade to settings-view@0.7.0 2013-08-21 16:48:38 -07:00
probablycorey 204de3ac24 Support long version for foreground command 2013-08-21 16:19:37 -07:00
probablycorey 986a9ce0a0 Add cli option to keep the browser process running in the foreground 2013-08-21 16:19:37 -07:00
probablycorey 25b7d356a1 Make load paths work when Atom is run in stable mode 2013-08-21 16:19:37 -07:00
probablycorey e833649111 Remove aa script and replace it with compile-main-to-app 2013-08-21 16:19:37 -07:00
probablycorey 0d74753d3e The browser process loads files from the resource path in dev mode
main.coffee is the only exception
2013-08-21 16:19:37 -07:00
Kevin Sawicki 9306c9b262 Upgrade to symbols-view@0.3.0 2013-08-21 15:58:28 -07:00
Kevin Sawicki 283cbcc9ab Use constructor.name instead of hard-coded string 2013-08-21 15:41:27 -07:00
Kevin Sawicki 935df2f4f1 Add issues url to package.json 2013-08-21 15:40:55 -07:00
Kevin Sawicki 07bcd8c1ef Upgrade to archive-view@0.3.0 2013-08-21 15:40:00 -07:00
Kevin Sawicki 6ad088f6d5 Upgrade to settings-view@0.6.0 2013-08-21 14:57:39 -07:00
Kevin Sawicki b181a77130 Upgrade to image-view@0.3.0 2013-08-21 14:57:39 -07:00
Matt Colyer d83adc3a27 Update documentation concerning themes 2013-08-21 14:53:56 -07:00
Matt Colyer 1ad971f424 Consistently use 'cmd' to represent 'meta' key 2013-08-21 14:53:56 -07:00
Matt Colyer 0b8800c818 Document favoring less over css 2013-08-21 14:53:56 -07:00
Matt Colyer bb7d8812da Update document regarding symbols 2013-08-21 14:53:56 -07:00
Matt Colyer f0677e43fa First pass at documentation correctness 2013-08-21 14:53:56 -07:00
Matt Colyer 159f521104 Reorganize documentation 2013-08-21 14:53:56 -07:00
Matt Colyer 46d713169f Add missing guides to the index 2013-08-21 14:53:56 -07:00
Matt Colyer 95535d93c6 Remove package related documentation from core 2013-08-21 14:53:56 -07:00
Corey Johnson & Nathan Sobo 7173467b1a 🐎 Upgrade telepath to improve fold performance
This addresses #734. It improves performance from ~10s to ~1.5s when
running a foldAll on edit-session-spec. This still needs to get better.
2013-08-21 15:22:25 -06:00
Corey Johnson & Nathan Sobo 03712392c9 Write DisplayBuffer::findMarkers in terms of TextBuffer::findMarkers 2013-08-21 15:22:25 -06:00
Kevin Sawicki 0e49582616 Upgrade to settings-view@0.5.0 2013-08-21 13:15:17 -07:00
Kevin Sawicki 1dad3ae7ca Upgrade to collaboration@0.6.0 2013-08-21 13:02:50 -07:00
Kevin Sawicki c2123fce1f Upgrade to terminal@0.6.0 2013-08-21 10:51:24 -07:00
Kevin Sawicki 2190a009d8 Upgrade to settings-view@0.4.0 2013-08-21 10:19:04 -07:00
Kevin Sawicki e199000985 Mention python grammar fix 2013-08-21 08:51:04 -07:00
Kevin Sawicki ba70c15328 Upgrade telepath for redo fix
Closes #736
2013-08-20 19:04:14 -07:00
Nathan Sobo 0192c57f46 Fix corner case in RowMap::mapBufferRowRange w/ 0-buffer-row regions
Fixes #688

The DisplayBuffer applies buffer and screen deltas to the row map as
rows are inserted/removed from the buffer/screen. This can leave some
of the regions in a weird state, such as mapping multiple screen rows
to zero buffer rows. But next the DisplayBuffer applies any new mappings
based on the replaced lines over the top of existing regions. These
weirdly shaped regions should be overwritten by newly inserted regions,
so at the end of the operation the row map makes sense again.

This fixes a corner case where regions spanning 0 buffer rows at the
very beginning of the row range were not being included in the set of
regions to replace. This was in turn causing the RowMap to get into a
bad state in certain situations involving soft-wrapped lines.
2013-08-20 19:30:29 -06:00
Nathan Sobo b60b21cf3a Add RowMap::inspect, which returns a string for debugging the regions 2013-08-20 19:30:28 -06:00
Kevin Sawicki & Nathan Sobo 116c56c236 Serialize site across window loads
This prevents issues with the site counter resetting to 1 on each
load causing duplicate array and marker ids to be generated.

Closes #729
2013-08-20 18:29:19 -07:00
Kevin Sawicki 6fb8dcbaa5 Add site color variables to ui-colors
These are used by the collaboration package to represent
participants in the current session.
2013-08-20 17:15:43 -07:00
Kevin Sawicki 6e2fd18f62 Add back ability to open an arbitrary window
atom.open now takes an options has that can contain either pathsToOpen
or the complete settings of a new window.

This will be used by the collaboration package to open the window when a
session is being joined.
2013-08-20 15:30:53 -07:00
Matt Colyer 90da89d31c Use JSON frontmatter 2013-08-20 15:02:01 -07:00
Matt Colyer 0999dc6d44 Add a proper template for the docs 2013-08-20 15:02:01 -07:00
Matt Colyer 72cedf9027 Synchronize directory structure 2013-08-20 15:02:01 -07:00
Matt Colyer c38eccf39d Add a simple documentation index 2013-08-20 15:02:01 -07:00
Matt Colyer 3be3543ad9 Update deploy task to include guides as well 2013-08-20 15:02:01 -07:00
Matt Colyer 588efa2e11 Add grunt 'docs' task to build both guides and API docs 2013-08-20 15:02:01 -07:00
Kevin Sawicki 2fee0f1083 💄 space separate array items 2013-08-20 14:20:16 -07:00
Corey Johnson 55ee11e16a Compile keymaps into atom application 2013-08-20 14:19:32 -07:00
Kevin Sawicki b22e4d67ec Upgrade to terminal@0.5.0 2013-08-20 12:32:01 -07:00
Corey Johnson & Nathan Sobo 85626383ee Move command handling to AtomWindow 2013-08-20 12:23:15 -07:00
Corey Johnson & Nathan Sobo fc60ba682c 💄 2013-08-20 12:23:15 -07:00
Corey Johnson & Nathan Sobo 0e7cb3ff78 🔫 2013-08-20 12:23:15 -07:00
Corey Johnson & Nathan Sobo 03ef5a72c4 Make getTemplate take keystrokesByCommand as a parameter
This clarifies the fact that we can't call this method without having
a keystrokes hash from a running window, which is why we also have a
getDefaultTemplate method which doesn't need the keystrokes.
2013-08-20 12:23:15 -07:00
Corey Johnson & Nathan Sobo 2cd91eda98 💄 2013-08-20 12:23:15 -07:00
Corey Johnson & Nathan Sobo 5d27d56056 Rename ApplicationMenu::parseTemplate to translateTemplate 2013-08-20 12:23:15 -07:00
Corey Johnson & Nathan Sobo 0c9a1fdc80 Rename Keymap::toObject to Keymap::keystrokesByCommand
Also add spec for passing a selector
2013-08-20 12:23:15 -07:00
Corey Johnson & Nathan Sobo 79dd4320da Rename AtomMenu to ApplicationMenu 2013-08-20 12:23:14 -07:00
probablycorey 37c7c8abee Remove the whitespace grunt:lint was complaining about 2013-08-20 12:23:14 -07:00
probablycorey 77bb829a3e Make keymap.toObject(selector) work 2013-08-20 12:23:14 -07:00
probablycorey dba0998687 Revert "trigger commands from the browser process on the active.element"
This reverts commit f023ce89096b1c7a6faf337cf48d29cfbb296091.
2013-08-20 12:23:14 -07:00
probablycorey 0c542d2317 Menu Items only show keyBindings that match the selector "body" 2013-08-20 12:23:14 -07:00
probablycorey 477ac1768b Rename ApplicationMenu to AtomMenu
This is so all browser process classes start with Atom.*
2013-08-20 12:23:14 -07:00
probablycorey 39ec96021e Listen for application commands using the @command method
This adds application level commands to the command palette.
2013-08-20 12:23:14 -07:00
probablycorey ab397b306c AtomApplication listens for application level events 2013-08-20 12:23:14 -07:00
probablycorey d3575bd45e Remove return value from openPath()
It is not used anywhere
2013-08-20 12:23:13 -07:00
probablycorey f6ad85488c Fix parameter ordering 2013-08-20 12:23:13 -07:00
probablycorey b8406368c6 Add underscore so download update menu item works 2013-08-20 12:23:13 -07:00
probablycorey 6278364ed2 💄 2013-08-20 12:23:13 -07:00
probablycorey 068e656627 Remove unused atom.getVersion method 2013-08-20 12:23:13 -07:00
probablycorey 6d50d05336 Move default menu creation into ApplicationMenu 2013-08-20 12:23:13 -07:00
probablycorey 60d804fb72 Don't intercept non-core commands 2013-08-20 12:23:13 -07:00
probablycorey fb2439f193 Move ApplicationMenu to the AtomApplication
This moves it completely out of the renderer process
2013-08-20 12:23:13 -07:00
probablycorey 4d8b2672ff Rename menu-bar to application-menu
Also move it to the src root in preparation for it's use in the
browser process
2013-08-20 12:23:13 -07:00
probablycorey e057d35048 Create a MenuBar object (instead of treating it like a singleton.) 2013-08-20 12:23:13 -07:00
probablycorey 6e3517dd4a Menu bar does not directly access the keymap anymore
This makes the keyBindingsForCommand methods obsolete
2013-08-20 12:23:12 -07:00
probablycorey 37c17075ea Add keymap.toObject() 2013-08-20 12:23:12 -07:00
probablycorey 1074642e8f Remove unused openWindow method 2013-08-20 12:23:12 -07:00
probablycorey e360379ced Create default menu bar that is shown if atom crashes during launch 2013-08-20 12:23:12 -07:00
probablycorey efb70e0562 Remove specs and methods that are no longer used 2013-08-20 12:23:12 -07:00
probablycorey 9a156c8629 Remove keymap.bindDefaultKeys
No longer needed since default keys are handled in AtomApplication
2013-08-20 12:23:12 -07:00
probablycorey afd1a7419d Menu bar is load by the first created Atom Window 2013-08-20 12:23:12 -07:00
Corey Johnson b3582b2632 Add keymap.keyBindingsForCommand 2013-08-20 12:23:11 -07:00
Corey Johnson e68bc47dc5 💄 2013-08-20 12:23:11 -07:00
Corey Johnson b5f4b8d254 Set devMode option on loadSettings 2013-08-20 12:23:11 -07:00
probablycorey 8803bab816 trigger commands from the browser process on the active.element 2013-08-20 12:23:11 -07:00
Kevin Sawicki b94d22794b Upgrade to bracket-matcher@0.3.0 2013-08-20 12:09:34 -07:00
Kevin Sawicki 27cee3e19c Don't terminate tokenization if stack size changes
Previously Python import blocks were not tokenizing correctly since
the loop was prematurely terminating when a match at the end of the line
was reached and no tokens were generated for it.

This approach was incorrect since the tokenizer may have just popped a rule
and another loop could possibly pop more rules.

Now this early termination is only performed if the stack size hasn't changed.
2013-08-20 11:38:06 -07:00
Ben Ogle b10a01ddc2 fix naming of background colors in default ui colors 2013-08-20 11:25:30 -07:00
Ben Ogle 14b5308bb3 Merge pull request #733 from atom/bo-theme-buttons
Add styled buttons to themes
2013-08-20 11:22:26 -07:00
Ben Ogle 4c0ffe122d Add buttons to the light ui theme 2013-08-20 11:14:07 -07:00
Ben Ogle 7ca2779e56 Fix background highlight colors naming 2013-08-20 11:13:54 -07:00
Ben Ogle 5579551521 add buttons to ui dark theme 2013-08-20 10:47:26 -07:00
Kevin Sawicki d89e95dc54 💄 Move extend under class declaration 2013-08-20 10:15:31 -07:00
Corey Johnson 7ace46d81f Add private beta docs 2013-08-20 09:43:48 -07:00
Kevin Sawicki e13eebdcd2 Remove fontello
This is no longer used now that the octicons include video/audio
on/off icons that are used in the collaboration package.
2013-08-19 21:42:32 -07:00
Kevin Sawicki 3cb3c888ba Upgrade to collaboration@0.5.0 2013-08-19 21:42:28 -07:00
Kevin Sawicki 0947e1cffa Upgrade octicons for mute/unmute icons 2013-08-19 21:40:19 -07:00
Kevin Sawicki 044bcd4053 💄 2013-08-19 21:28:09 -07:00
Kevin Sawicki 805c17d20c Revert "Remove ws dependency now managed in collaboration package"
This reverts commit dc8362cabf.

This is still needed since apm install does not install dev dependencies
of third-party modules.
2013-08-19 21:25:37 -07:00
Kevin Sawicki 77ed5324b1 Move specs from spec/app to spec/ 2013-08-19 21:23:00 -07:00
Kevin Sawicki dc8362cabf Remove ws dependency now managed in collaboration package 2013-08-19 21:08:02 -07:00
Kevin Sawicki 87b859b947 Update links for new repo location under atom org. 2013-08-19 20:50:09 -07:00
Kevin Sawicki f92e61a683 Upgrade to collaboration@0.4.0 2013-08-19 20:36:56 -07:00
Kevin Sawicki 3bd04f8da8 Remove atom-collaboration-server from .gitmodules
This is now reference in the collaboration package repository
2013-08-19 20:33:03 -07:00
Kevin Sawicki d08aa4b9d9 Update telepath submodule URL for new location in atom org. 2013-08-19 20:32:37 -07:00
Kevin Sawicki 38a3adae89 Update apm submodule URL for new location in atom org. 2013-08-19 20:30:32 -07:00
Kevin Sawicki 2f8c9ffa66 Remove src from nof list of directories
It no longer contains any package specs.
2013-08-19 20:20:36 -07:00
Kevin Sawicki a7a1244599 Flatten spec directory 2013-08-19 20:13:58 -07:00
Kevin Sawicki 6ec8b6e26f Update doc tasks for new src layout 2013-08-19 20:13:57 -07:00
Kevin Sawicki 76332c76bd Flatten src directory
* Move src/app to src/
  * Move src/stdlib to src/
  * Remove src/app and src/stdlib from NODE_PATH
2013-08-19 20:13:57 -07:00
Kevin Sawicki 45c11e6fd4 Move src/app/keymaps to repo root 2013-08-19 20:13:57 -07:00
Kevin Sawicki b6785d78e8 Reset themes in afterEach
This ensures they don't bleed over into other specs.
2013-08-19 19:49:52 -07:00
Kevin Sawicki e31cd35ce8 Upgrade apm to fix update command
Closes #726
2013-08-19 19:25:28 -07:00
Kevin Sawicki c80373b11e Upgrade to image-view@0.2.0 2013-08-19 19:15:52 -07:00
Kevin Sawicki & Nathan Sobo cf65945d5c 🐎 Upgrade telepath for performance improvements 2013-08-19 18:07:32 -07:00
Kevin Sawicki & Nathan Sobo f76108fdfd 🐎 Cache tab whitespace regexes in Token 2013-08-19 18:07:32 -07:00
Ben Ogle 8ea8671430 Merge pull request #706 from github/bo-inject-less-vars
Add theme dir(s) to less import paths -> allow package LESS to import from the current theme
2013-08-19 18:03:55 -07:00
Kevin Sawicki & Nathan Sobo f02d05811c Upgrade to collaboration@0.3.0 to fix CI 2013-08-19 16:25:05 -07:00
Kevin Sawicki & Nathan Sobo 0af8c9362b Remove duplicate call to TokenizedBuffer:resetTokenizesLines()
This is already handled in an event listener bound to 'grammar-changed'
which TokenizedBuffer::setGrammar triggers.
2013-08-19 16:20:35 -07:00
Ben Ogle d01cde3358 add another import 2013-08-19 15:55:17 -07:00
Ben Ogle 128543ec7e fix import 2013-08-19 15:55:17 -07:00
Ben Ogle 5de52c59ee Comment 2013-08-19 15:55:17 -07:00
Ben Ogle ea019870fb Add in the fallback ui colors. 2013-08-19 15:55:17 -07:00
Ben Ogle a98b2fd37f Success colors are green! 2013-08-19 15:55:17 -07:00
Ben Ogle c2aefa7616 Change colors in dark ui to match pattern in light ui colors 2013-08-19 15:55:17 -07:00
Ben Ogle 2d12f08375 Update light ui with color system 2013-08-19 15:55:16 -07:00
Ben Ogle 66162902be Pull colors out of the dark-ui theme 2013-08-19 15:55:16 -07:00
Ben Ogle 595f6a975f import the right colors file 2013-08-19 15:55:16 -07:00
Ben Ogle 15085384b9 change name of event to reloaded 2013-08-19 15:55:16 -07:00
Ben Ogle 0eff8deabc remove parens from the list comp 2013-08-19 15:55:16 -07:00
Ben Ogle 72db35d663 rename colors to ui-colors 2013-08-19 15:55:16 -07:00
Ben Ogle 51ec4d3285 Use a few colors in the themes. 2013-08-19 15:55:16 -07:00
Ben Ogle 8b149f63cb Add colors.less files.
Adds one for each theme, and a fallback
2013-08-19 15:55:16 -07:00
Ben Ogle 15a48147b1 Use theme.reload event to reload the theme stylesheets 2013-08-19 15:55:16 -07:00
Ben Ogle 3bc6023a66 Use import paths from themes when loading a less sheet 2013-08-19 15:55:15 -07:00
Ben Ogle b89e58e551 ThemeManager emits a reload event when reloaded 2013-08-19 15:55:15 -07:00
Ben Ogle 6cd003f68e Add reloadStylesheets() to AtomPackage 2013-08-19 15:55:15 -07:00
Ben Ogle 8730638ade Add directory and ImportPaths paths to themes 2013-08-19 15:55:15 -07:00
Kevin Sawicki & Nathan Sobo c3850e4d44 Upgrade to collaboration@0.2.0 for summit branch updates 2013-08-19 15:54:39 -07:00
Kevin Sawicki 0a8ebca67a Use an async waterfall to chain deploy commands 2013-08-19 15:34:25 -07:00
Kevin Sawicki & Nathan Sobo 347801b074 Merge branch 'summit'
Conflicts:
	src/app/config.coffee
	src/atom-application.coffee
	src/main.coffee
2013-08-19 14:01:24 -07:00
Kevin Sawicki & Nathan Sobo fe010eccc7 Update telepath for SharedString::lineForRow speedup 2013-08-19 13:51:59 -07:00
Kevin Sawicki 2959b51afb Upgrade telepath for assumePrimitiveElements optimization 2013-08-19 13:43:43 -07:00
Kevin Sawicki & Nathan Sobo 24e0d8fc03 Add ~/.atom/dev/packages to package load path in dev mode 2013-08-19 09:56:43 -07:00
Kevin Sawicki & Nathan Sobo 42a34c01c9 Add devMode flag to atom.getLoadSettings() 2013-08-19 09:55:11 -07:00
Nathan Sobo cfe5bb1b02 Get benchmark-suite running again 2013-08-18 10:20:20 -06:00
Nathan Sobo f23f23d032 Upgrade telepath for assumePrimitive optimization 2013-08-18 10:19:36 -06:00
Kevin Sawicki 65330a00e3 Special case last row in TextBuffer::suggestedLineEndingForRow
This fixes the TextBuffer specs for changes in the underlying
behavior of SharedString::lineEndingForRow in telepath.
2013-08-16 21:22:06 -07:00
Kevin Sawicki 7f9b057c52 💄 2013-08-16 21:20:47 -07:00
Kevin Sawicki 647b5881a8 Remove TextBuffer::lineEndingForRow spec covered in telepath 2013-08-16 21:16:34 -07:00
Kevin Sawicki 9c76214fe9 Expect undefined instead of null for invalid buffer rows 2013-08-16 21:03:04 -07:00
Kevin Sawicki 3d5516fad9 Default to empty arrays for user and bundled package paths 2013-08-16 20:52:20 -07:00
Kevin Sawicki 338b59dc5f Upgrade telepath for line performance improvements 2013-08-16 20:45:30 -07:00
probablycorey 09c8b2a3a8 Remove the close-without-confirm event
This was not being used anymore.
2013-08-16 15:49:24 -07:00
Kevin Sawicki & Nathan Sobo 1ca7663be4 Upgrade packages for collaboration branch releases 2013-08-16 12:35:05 -07:00
Kevin Sawicki & Nathan Sobo 0e2d6caf94 Upgrade telepath for stack overflow fix 2013-08-16 12:05:15 -07:00
Kevin Sawicki & Nathan Sobo fe2baa18ca Use atom.getAvailablePackageNames() to load package specs 2013-08-16 11:35:43 -07:00
Kevin Sawicki & Nathan Sobo a147dc01d7 Clear undo stack after setting initial buffer text 2013-08-16 11:30:37 -07:00
Kevin Sawicki & Nathan Sobo 2f4555a16f Add config.userPackageDirPaths which includes dev packages in dev mode 2013-08-16 11:18:08 -07:00
Kevin Sawicki & Nathan Sobo 4c121bb084 Upgrade telepath for timestamp fix 2013-08-16 11:18:00 -07:00
Matt Colyer d3130845d1 Adds deploy-docs grunt task 2013-08-16 10:11:14 -07:00
Kevin Sawicki 13a622a853 Upgrade telepath for SharedString transaction fixes 2013-08-16 09:08:58 -07:00
Ben Ogle 1254ceeb6d Merge pull request #715 from github/bo-pane-events
Add a pane:became-inactive event
2013-08-15 18:26:41 -07:00
Ben Ogle eea38a696f add a pane:became-inactive event 2013-08-15 17:28:14 -07:00
Kevin Sawicki & Nathan Sobo 27928a7145 Upgrade telepath for Document::begin/commit/abortTransaction() 2013-08-15 17:17:32 -07:00
Kevin Sawicki 67755ccdc3 Upgrade apm for new link in dev mode command 2013-08-15 08:15:15 -07:00
Kevin Sawicki & Nathan Sobo 6178c64c68 Add ~/.atom/dev/packages to package load path in dev mode 2013-08-14 17:41:32 -07:00
Kevin Sawicki & Nathan Sobo b305a09be3 Add devMode flag to atom.getLoadSettings() 2013-08-14 17:33:58 -07:00
Kevin Sawicki & Nathan Sobo 5313f6cf66 Upgrade telepath for Range.fromPointWithDelta() fix 2013-08-14 16:35:30 -07:00
Kevin Sawicki & Nathan Sobo f00bb58932 TokenizedBuffer constructor now takes an object 2013-08-14 16:35:10 -07:00
Kevin Sawicki & Nathan Sobo ad36b2c6a6 Allow user package specs to override bundled package specs 2013-08-14 15:36:45 -07:00
Kevin Sawicki & Nathan Sobo b3fe63b1b4 Don't return duplicates from atom.getAvailalblePackageNames() 2013-08-14 15:34:47 -07:00
Kevin Sawicki c6d1409151 Merge branch 'master' into summit
Conflicts:
	.pairs
	package.json
	spec/app/tokenized-buffer-spec.coffee
	src/app/edit-session.coffee
	src/app/project.coffee
	src/app/window.coffee
	src/atom-application.coffee
	static/root-view.less
2013-08-14 14:05:35 -07:00
Kevin Sawicki 5235114eed Use fs.readdirSync() for listing package directories
Previously fsUtils.listTreeSync() was used which returns every path
in the tree, not just paths directly underneath the root path.

This speeds up the spec suite require time by not stat'ing the entire
node_modules directory.
2013-08-14 11:29:48 -07:00
Ted Nyman c61d45805d Formatting 2013-08-14 11:01:50 -07:00
Ted Nyman c294c94c02 Update documentation location 2013-08-14 11:01:50 -07:00
Kevin Sawicki b7a8e22d82 Set spec type after all specs in the category are required 2013-08-14 10:58:56 -07:00
Nathan Sobo bd6dda6f0f Don't load buffer contents from disk without an isModified key in state
When we deserialize a replicated buffer, we always want to honor the
current contents of state. If the state was produced by a call to
`getState` instead of `serialize`, it won't have an `isModified` key,
so we should not load from disk.
2013-08-14 11:55:37 -06:00
Nathan Sobo 468034f261 🙊 2013-08-14 11:46:10 -06:00
Nathan Sobo c6a0e385f7 Always include text in serialized buffer state; also include isModified
Previously, we were not including the text when serializing an
unmodified buffer. We would use the absence of the text field to
determine that the buffer was previously unmodified when deserializing.
The problem is that text now stores the markers associated with the
buffer, and we want to retain those across serialization regardless of
the modified status. So now I include the text always, along with an
isModified flag which if true, will tell to reload the buffer if it
has changed since we last serialized it. Reloading a buffer should
probably do a diff-and-patch in the future rather than replacing the
contents outright, so that we always preserve markers as best as we can.
2013-08-14 11:31:17 -06:00
Kevin Sawicki 4781636889 💄 Group dependencies by type 2013-08-14 10:27:12 -07:00
Nathan Sobo fa6ea01bfc Restore assignment of @project ivar in TextBuffer
Because TextBuffers need a reference to `project` during deserialization,
and because the project global deserializes text buffers while it itself
is being deserialized (which happens before the global is actually
assigned), we have to pass a project reference into TextBuffer. This is
really annoying and makes me want to store the references to open buffers 
elsewhere. But for now it's the only way to break the circularity.
2013-08-14 10:49:48 -06:00
Kevin Sawicki f021ce3657 Compile bundled package files in compile task
Any .coffee, .cson, and .less files found in bundled Atom packages
in node_modules are now compiled during the compile task
2013-08-14 09:28:17 -07:00
Kevin Sawicki 71b238fafc Upgrade to command-logger@0.2.0 2013-08-14 08:48:13 -07:00
Kevin Sawicki 63df6c8dcd Upgrade to settings-view@0.3.0 2013-08-14 08:48:13 -07:00
Kevin Sawicki 7fc8cea167 Upgrade to settings-view@0.2.0 2013-08-14 08:48:12 -07:00
Kevin Sawicki 726a60b348 Upgrade to archive-view 0.2 2013-08-14 08:48:12 -07:00
Kevin Sawicki 0429ed09ff Remove humanize-plus dependency 2013-08-14 08:48:12 -07:00
Kevin Sawicki 14df854ea8 Remove keytar dependency 2013-08-14 08:48:12 -07:00
Kevin Sawicki c8727873c7 Remove jqueryui-browser dependency 2013-08-14 08:48:12 -07:00
Kevin Sawicki 3b7e1400c0 Remove roaster dependency 2013-08-14 08:48:12 -07:00
Kevin Sawicki 2ddd77122e Remove config.bundledPackagesDirPath that was src/packages 2013-08-14 08:48:12 -07:00
Kevin Sawicki 41268c67d7 Remove internal packages section from spec reporter 2013-08-14 08:48:12 -07:00
Kevin Sawicki 4777c4c42c Remove mention of src/packages 2013-08-14 08:48:12 -07:00
Kevin Sawicki ced95e7ad9 Remove src/packages from NODE_PATH 2013-08-14 08:48:12 -07:00
Kevin Sawicki 68ddeeef01 Pull out collaboration package into a separate repo 2013-08-14 08:48:12 -07:00
Kevin Sawicki 184e6a14c7 Pull out settings-view package into a separate repo 2013-08-14 08:48:12 -07:00
Kevin Sawicki 25378e9905 Pull out command-panel package into a separate repo 2013-08-14 08:48:12 -07:00
Kevin Sawicki 80a6999af4 Pull out fuzzy-finder package into a separate repo 2013-08-14 08:48:11 -07:00
Kevin Sawicki 257722f82e Pull out command-palette package into a separate repo 2013-08-14 08:48:11 -07:00
Kevin Sawicki 58a938b3f1 Pull out snippets package into a separate repo 2013-08-14 08:48:11 -07:00
Kevin Sawicki 875f187915 Pull out status-bar package into a separate repo 2013-08-14 08:48:11 -07:00
Kevin Sawicki 229e380e28 Pull out tree-view package into a separate repo 2013-08-14 08:48:11 -07:00
Kevin Sawicki 52e8e3aaf3 Pull out autocomplete package into a separate repo 2013-08-14 08:48:11 -07:00
Kevin Sawicki dc775f93ff Pull out tabs package into a separate repo 2013-08-14 08:48:11 -07:00
Kevin Sawicki 63b1546212 Pull out bookmarks package into a separate repo 2013-08-14 08:48:11 -07:00
Kevin Sawicki b9585d1cf2 Pull out package-generator package into a separate repo 2013-08-14 08:48:11 -07:00
Kevin Sawicki 189b9051a9 Pull out whitespace package into a separate repo 2013-08-14 08:48:11 -07:00
Kevin Sawicki f3ef0b77a8 Pull out bracket-matcher package into a separate repo 2013-08-14 08:48:11 -07:00
Kevin Sawicki bdefff6abe Pull out editor-stats package into a separate repo 2013-08-14 08:48:11 -07:00
Kevin Sawicki 235078be8e Pull out github-sign-in package into a separate repo 2013-08-14 08:48:11 -07:00
Kevin Sawicki 02d7668c73 Pull out link package into a separate repo 2013-08-14 08:48:10 -07:00
Kevin Sawicki 7bb41f57b0 Pull out markdown-preview package into a separate repo 2013-08-14 08:48:10 -07:00
Kevin Sawicki c1c50a0b4c Pull out symbols-view package into a separate repo 2013-08-14 08:48:10 -07:00
Kevin Sawicki 7bc135d82e Pull out grammar-selector package into a separate repo 2013-08-14 08:48:10 -07:00
Kevin Sawicki a1847b5355 Pull out go-to-line package into a separate repo 2013-08-14 08:48:10 -07:00
Kevin Sawicki 3686a5b0ba Pull out git-diff package into a separate repo 2013-08-14 08:48:10 -07:00
Kevin Sawicki db82f6bb8b Pull out gists package into a separate repo 2013-08-14 08:48:10 -07:00
Kevin Sawicki d5b5c76485 Pull out gfm package into a separate repo 2013-08-14 08:48:10 -07:00
Kevin Sawicki 6430aefaa8 Pull out toml package into a separate repo 2013-08-14 08:48:10 -07:00
Kevin Sawicki f41ffd6cbf Pull out wrap-guide package into a separate repo 2013-08-14 08:48:10 -07:00
Kevin Sawicki 8a44da49d1 Remove tilde from humanize-plus dependency 2013-08-14 08:48:10 -07:00
Kevin Sawicki 9e50c829a0 Pull out image-view package into separate repo 2013-08-14 08:48:10 -07:00
Kevin Sawicki d2cf652a0b Pull out command-logger package to separate repo 2013-08-14 08:48:09 -07:00
Kevin Sawicki 01fee754f7 Pull out autoflow package to separate repo 2013-08-14 08:48:09 -07:00
Kevin Sawicki 24c304481e Pull out archive-view package to separate repo 2013-08-14 08:48:09 -07:00
Kevin Sawicki d02d42f40e Pull out spell-check package to separate repo 2013-08-14 08:48:09 -07:00
Kevin Sawicki c747e1c686 Separate npm and apm output with an empty line 2013-08-14 08:46:53 -07:00
Corey Johnson & Nathan Sobo 3c166edd26 Start switch to Telepath for undo/redo
Also, TextBuffer spec passes!
2013-08-13 17:34:31 -07:00
Corey Johnson & Nathan Sobo 2d46a98ea2 Update telepath 2013-08-13 17:14:10 -07:00
Cheng Zhao 51a847c820 Merge pull request #697 from github/buffered-node-process
Remove dependency of bundled node
2013-08-13 00:05:17 -07:00
Cheng Zhao 4f7c7568e9 Update apm: No more need of bundled node. 2013-08-13 14:48:40 +08:00
Cheng Zhao 326ee2e5fa 💄 2013-08-13 14:47:28 +08:00
Cheng Zhao 32a0faf068 Don't assume we have a bundled node process in BufferedProcess. 2013-08-13 14:47:27 +08:00
Cheng Zhao 66da13a6ff Add BufferedNodeProcess to execute apm and nak.
On Windows the shebang string is not supported, so we haveto execute apm
and nak as scripts instead of as executables.
2013-08-13 14:47:27 +08:00
Cheng Zhao ebaa6c349f Revert "Downgrade to atom-shell@v0.2.1"
This reverts commit d7cfb757d6.
2013-08-13 14:47:27 +08:00
Kevin Sawicki 063d48c4ab Use ScopeSelector class from first-mate
Begin migrating TextMate helpers out of src/ and into the first-mate
package.
2013-08-12 16:22:18 -07:00
Jessica Lord & Kevin Sawicki 0a53e2f7bb Use getText() instead of val() for username & password 2013-08-12 15:52:28 -07:00
Jessica Lord & Kevin Sawicki 12fbd89e79 Clear username and password when detached 2013-08-12 15:46:01 -07:00
Jessica Lord & Kevin Sawicki 6a16ef0cf8 Listen for buffer changed events to validate sign in view 2013-08-12 15:45:52 -07:00
Jessica Lord & Kevin Sawicki 8d180dd767 Set text security on line elements only
This ensures the disc does not appear when the field is empty
2013-08-12 15:44:57 -07:00
Jessica Lord & Kevin Sawicki 475fefa2fd turned off html clear to show duplicate password disc 2013-08-12 15:01:41 -07:00
Jessica Lord & Kevin Sawicki 86d0fca621 Switch GitHub Sign in to mini-editors
Previously bootstrap <input> fields didn't work with keybindings.
Switched to mini-editors to enable expected keybindings. Edited tabs for
focusing and password text to disc style.
2013-08-12 14:56:47 -07:00
Kevin Sawicki 3056efd351 Remove unused lines variable 2013-08-12 14:41:14 -07:00
Kevin Sawicki 7ba57df6f7 Mention new fixes and additions 2013-08-12 10:10:22 -07:00
Nathan Sobo 5c2f4d939a Move new additions to philosophy section and tone-down the rhetoric 2013-08-12 10:46:46 -06:00
probablycorey 6c9c7b6d92 Fuzzy filter scores files more than 10 directories deep
All files more than 10 directories deep were accidentally being scored as 0.
2013-08-12 09:43:43 -07:00
Nathan Sobo 210dd61d2a Start adding some serious philosophy to the contribution guidelines 2013-08-12 00:18:58 -06:00
Kevin Sawicki aa302cb935 Add -syntax suffix to converted themes 2013-08-11 13:51:07 -07:00
Kevin Sawicki 994e856ccd Tweak error message when theme file is not found 2013-08-11 13:44:33 -07:00
Kevin Sawicki 808f7e6ed3 Add grunt task to convert TextMate themes to Atom themes 2013-08-11 13:42:34 -07:00
Kevin Sawicki 22f7bc8f26 Upgrade to terminal 0.3.0 2013-08-09 17:34:31 -07:00
Kevin Sawicki ab0b2cf12e Bundle atom/terminal package by default 2013-08-09 17:24:11 -07:00
Kevin Sawicki 599a2ad021 Group specs into four sections
1. Core specs located in spec/
2. Internal package specs in src/packages
3. Bundled package specs in node_modules
4. User package specs in ~/.atom/packages
2013-08-09 17:24:07 -07:00
Kevin Sawicki db649798ef Ignore missing symlinks in fsUtils.traverseTreeSync()
These were previously throwing an error from the call to
statSync().

Now statSync() is wrapped in a try block and only performed when
lstatSync() reports a symbolic link.
2013-08-09 17:23:29 -07:00
Jessica Lord & Kevin Sawicki 4f8f8c43a4 Rename event to open-settings from open-config 2013-08-09 13:38:01 -07:00
Jessica Lord & Kevin Sawicki 4491a9302b Forward config menu click event to focused window
Previously the Atom > Preferences... menu just logged an error message.

Now it fires a window:open-config event to the focused window.
2013-08-09 13:29:12 -07:00
Jessica Lord & Kevin Sawicki ce138b56c0 add jlord to pairs file 2013-08-09 13:28:25 -07:00
Kevin Sawicki 2597837ba7 Use ~/.atom/storage instead of ~/.atom/.storage
The serialization format is changing for telepath and this allows a clean
upgrade and the dotted directory does not seem needed since it is already
behind one dotted directory (.atom).
2013-08-09 10:38:57 -07:00
Nathan Sobo 0f14dd9420 Disable pane-splitting spec for now
We'll get it working once this branch gets merged to master.
2013-08-08 11:01:01 -06:00
Kevin Sawicki c22bbf98b8 Remove unused redis dependency 2013-07-28 19:22:45 -07:00
Kevin Sawicki 555611aa1f Prepend new participant views instead of appending 2013-07-27 13:45:21 -07:00
Nathan Sobo 579cfb4a4a Disable audio for self-streams 2013-07-27 13:53:10 -06:00
Kevin Sawicki 9753a63227 Trigger connected event for local media connection to self
Also upgrade atom-collaboration-server
2013-07-27 11:56:04 -07:00
Kevin Sawicki 292815c014 Add participant view for self
This will show your own camera video and which color you appear
as to other session participants.
2013-07-27 11:38:16 -07:00
Kevin Sawicki b38a6f2235 Request avatars to be 420px 2013-07-27 11:10:58 -07:00
Kevin Sawicki 0b6f38118e Add back setting avatar background image to avatar url 2013-07-27 11:02:44 -07:00
Kevin Sawicki 50932bc9e2 Remove unused require 2013-07-27 10:42:25 -07:00
Kevin Sawicki 99ff064072 💄 remove unneeded units 2013-07-27 10:40:50 -07:00
Kevin Sawicki 51899e602c 💄 remove trailing whitespace 2013-07-27 10:40:15 -07:00
Kevin Sawicki bca15a7589 Show avatar until video becomes available 2013-07-27 10:39:24 -07:00
Kevin Sawicki c723dd5406 Exclude remote markers from TextBuffer.serialize() 2013-07-27 10:31:11 -07:00
Kevin Sawicki 891f032def Unfocus collaboration spec 2013-07-27 10:06:04 -07:00
Nathan Sobo 433435743e Log some collaboration events until we're more stable 2013-07-27 09:48:01 -06:00
Ben Ogle 2a010cb00a volume 100%; remove remove link 2013-07-26 17:41:15 -07:00
Ben Ogle d13cc7d96f Merge branch 'summit' of github.com:github/atom into summit 2013-07-26 17:32:07 -07:00
Kevin Sawicki & Matt Colyer 624ca77173 Wrap webkitGetUserMedia in nextTick for reliability 2013-07-26 17:24:37 -07:00
Ben Ogle ac8c95d9a6 Fix padding on connections count 2013-07-26 17:16:47 -07:00
Ben Ogle 492fc46fb8 Add avatar when video hidden 2013-07-26 17:08:52 -07:00
Ben Ogle 86d1990894 Add fontello icons.
Remove this when we have octicons for audio and video
2013-07-26 16:54:35 -07:00
Kevin Sawicki & Nathan Sobo 121ee10f5a Call atom.getWindowState() instead of accessing property directly 2013-07-26 16:17:32 -07:00
Kevin Sawicki & Nathan Sobo c1e6aeece8 Store live reference to root view state in window state instead of clone 2013-07-26 16:17:32 -07:00
Ben Ogle 450caa124a add another color 2013-07-26 16:12:34 -07:00
Ben Ogle 85e90f2c09 Add ParticipantViewContainer
makes the stacking of participant views waaay better
2013-07-26 16:10:04 -07:00
Ben Ogle c6293afc3b Add index to participant view to stack multiple vids 2013-07-26 15:39:03 -07:00
Ben Ogle 87183f52ad comment out the avatar thing 2013-07-26 15:39:03 -07:00
Ben Ogle c49e092082 toggle classes added to participant view 2013-07-26 15:39:03 -07:00
Ben Ogle 100110430a Add toggle states and colors to toggle vid and audio buttons 2013-07-26 15:39:03 -07:00
Kevin Sawicki & Nathan Sobo 9d2756a8ae Rename audio/video configuration keys 2013-07-26 15:28:23 -07:00
Kevin Sawicki & Nathan Sobo 163015517e Create media connection for each other participant 2013-07-26 15:06:16 -07:00
Ben Ogle 5b267f4a3f cursor has site color 2013-07-26 14:44:32 -07:00
Ben Ogle e07f92c4ee Pick colors for the cursors and volume bars 2013-07-26 14:32:36 -07:00
Ben Ogle a7b496f8c1 add site-id class to selection-view 2013-07-26 14:10:11 -07:00
Ben Ogle f562a84bb5 add TODO for the crappy siteId hash usage 2013-07-26 14:01:18 -07:00
Ben Ogle e84065fd9d Better use of participant object 2013-07-26 14:00:53 -07:00
Ben Ogle c6737caae6 add test for clientId -> siteId map 2013-07-26 13:50:02 -07:00
Ben Ogle a0b7b4dd96 use clientIdToSiteId in participant view 2013-07-26 13:50:02 -07:00
Ben Ogle 4fe90900cc add clientIdToSiteId to session's document 2013-07-26 13:48:24 -07:00
Matt Colyer e088daa15b Copy the session id when hosting via the statusbar 2013-07-26 13:43:25 -07:00
Matt Colyer cc9902958e Remove unused github avatar initialization 2013-07-26 13:30:40 -07:00
Matt Colyer b87b4c1089 Reduce size of video stream 2013-07-26 12:22:33 -07:00
Kevin Sawicki & Nathan Sobo c2ec172617 Upgrade telepath to avoid marker update corner case 2013-07-26 13:04:42 -06:00
Kevin Sawicki & Nathan Sobo a60320df3a Add Participant class 2013-07-26 12:25:20 -06:00
Kevin Sawicki & Nathan Sobo 32f75040de Spec 💄 – Move spies to beforeEach and s/host/leader/g 2013-07-26 11:48:42 -06:00
probablycorey c7321a795b Use WsChannel to handle media webrtc handshake 2013-07-26 08:54:07 -07:00
Kevin Sawicki & Nathan Sobo 8493ef092e Add Editor.getRelativePath() that delegates to EditSession 2013-07-26 08:45:41 -07:00
Kevin Sawicki & Nathan Sobo a9edaaba51 Add failing spec for splitting edit sessions 2013-07-26 08:45:13 -07:00
Kevin Sawicki 0e89db68a3 Upgrade to patrick 0.4 2013-07-26 08:40:45 -07:00
Kevin Sawicki 4f6f26735c Upgrade to git-utils 0.24 2013-07-26 08:38:40 -07:00
Kevin Sawicki & Nathan Sobo b4401cf10c Upgrade to patrick 0.3 2013-07-25 19:22:02 -07:00
Kevin Sawicki & Nathan Sobo b55d4364ff Allow audio/video to be disabled via config 2013-07-25 19:18:09 -07:00
Kevin Sawicki & Nathan Sobo 4c65332e55 Log when attempting to open non-session URL 2013-07-25 19:04:16 -07:00
Kevin Sawicki & Nathan Sobo 20f983874a Log the session being joined from the browser process 2013-07-25 19:03:30 -07:00
Kevin Sawicki & Nathan Sobo f859c1e32a Warn if we drop replication events 2013-07-25 19:00:32 -07:00
Ben Ogle eb40100b0f Add action bar to video. 2013-07-25 18:40:42 -07:00
Ben Ogle ad946ea482 Add email title to user. Could be a proper tooltip? 2013-07-25 18:40:42 -07:00
Ben Ogle f547af2896 Add small view by clicking 2013-07-25 18:40:41 -07:00
Ben Ogle 05caa45939 use getOtherParticipants in initial view creation 2013-07-25 18:40:41 -07:00
Ben Ogle b73f020555 remove listening event, add logic to started and stopped events 2013-07-25 18:40:41 -07:00
Ben Ogle b4ee425711 subscribe to participant change events in status bar view 2013-07-25 18:40:41 -07:00
Kevin Sawicki & Nathan Sobo ffb4387aab Upgrade atom-collaboration-server 2013-07-25 18:10:49 -07:00
Kevin Sawicki & Nathan Sobo ba644ea9f1 Add SSL support to session 2013-07-25 17:58:51 -07:00
Ben Ogle & Corey Johnson 602fecefa6 Handle participant exiting 2013-07-25 16:05:48 -07:00
probablycorey d49d3156eb Display audio and video on all sessions 2013-07-25 16:05:48 -07:00
probablycorey 47ee4337ce Add Ben Ogle to pairs file
For the 50th time
2013-07-25 16:05:48 -07:00
probablycorey a8cdf2036d Add isListening to session 2013-07-25 16:05:48 -07:00
probablycorey 0ee9aecbd1 Change isHost to isLeader 2013-07-25 16:05:48 -07:00
probablycorey 34b6c71e8a 💄 2013-07-25 16:05:47 -07:00
Ben Ogle ff73ffcb16 style the video 2013-07-25 16:05:47 -07:00
Ben Ogle cff8833b4c Add status bar icon for sharing.
Also adds participant views to the rootView
2013-07-25 16:05:30 -07:00
Kevin Sawicki & Nathan Sobo 9f8a6598e3 Use avatar url directly 2013-07-25 14:36:32 -07:00
Kevin Sawicki & Nathan Sobo 0771270c0d Remove user from ec2 host 2013-07-25 14:17:25 -07:00
Kevin Sawicki & Nathan Sobo 185f97e3b2 Default session host to ec2 instance 2013-07-25 13:59:23 -07:00
Kevin Sawicki & Nathan Sobo 3685cb3b52 Display participants in host and guest views
Also add back media connection starting in Session
2013-07-25 13:47:55 -07:00
Kevin Sawicki & Nathan Sobo bb3cacf2cd Unify guest and host sessions into single class 2013-07-25 12:56:38 -07:00
Kevin Sawicki & Nathan Sobo 241e787d0f Emit 'participant-exited' events 2013-07-25 12:26:41 -06:00
Kevin Sawicki & Nathan Sobo 4c49b69613 Include participant data in 'participant-entered' event 2013-07-25 12:13:08 -06:00
Kevin Sawicki & Nathan Sobo 954a130f41 Include participants data w/ GuestSession 'started' events 2013-07-25 12:08:33 -06:00
Kevin Sawicki & Nathan Sobo 721bc67389 💄 2013-07-25 11:59:17 -06:00
Kevin Sawicki & Nathan Sobo 1755702e1a Include participants data w/ HostSession 'started' event 2013-07-25 11:51:07 -06:00
Kevin Sawicki & Nathan Sobo a4e1d84ebb Assign clientId to Session from its channel 2013-07-25 11:50:29 -06:00
Kevin Sawicki & Nathan Sobo b9e23b96eb Use atom-collaboration-server directly in specs 2013-07-25 10:38:54 -06:00
Kevin Sawicki & Nathan Sobo a22587d09b Send OAuth token as web socket query param 2013-07-24 19:47:10 -07:00
Kevin Sawicki & Nathan Sobo 50c1fb2e3c Remove redis channel 2013-07-24 18:42:52 -07:00
Kevin Sawicki & Nathan Sobo 1f00254759 Handle presence on server and clean up channel/event names 2013-07-24 19:35:05 -06:00
Kevin Sawicki & Nathan Sobo de403a68c3 Remove Pusher-related code 2013-07-24 19:10:05 -06:00
Kevin Sawicki & Nathan Sobo 6b19cbad44 Replace RedisChannel with WsChannel 2013-07-24 18:59:55 -06:00
Kevin Sawicki & Nathan Sobo 1fc6509a51 Use Redis pub/sub for channels. to @mcolyer for the idea! 2013-07-24 17:20:01 -06:00
Kevin Sawicki & Nathan Sobo 1bfb10bf2b Distribute events with pusher 2013-07-24 15:05:39 -07:00
Kevin Sawicki 71cbcf9c4a Enable peer.js debug flag
This will log messages from the reliable library to try
and debug the packet loss issue.
2013-07-24 08:29:07 -07:00
Kevin Sawicki 40d76d2db9 Replace git global with project.getRepo() 2013-07-23 19:31:32 -07:00
Kevin Sawicki & Nathan Sobo 79fab6602f Don't replicate spell check markers 2013-07-23 18:31:30 -07:00
Kevin Sawicki & Nathan Sobo 672d0051cc Upgrade to peer.js 0.2.8 2013-07-23 18:04:52 -07:00
Kevin Sawicki & Nathan Sobo 865ab16fdf Uncomment essential logging lines 2013-07-23 17:52:05 -07:00
Corey Johnson & Matt Colyer ce2a613858 Remove sharing ivar from Host Session 2013-07-23 17:49:20 -07:00
Corey Johnson & Matt Colyer 087c4c60a1 Don't turn on the web cam until sharing is begun 2013-07-23 17:49:20 -07:00
Corey Johnson & Matt Colyer 77acaf0a1a Refactor Host Session 2013-07-23 17:49:20 -07:00
Corey Johnson & Matt Colyer 12ffff9dde Refactor guest session 2013-07-23 17:49:20 -07:00
Corey Johnson & Matt Colyer 81147c4bc6 Add TURN server support for all WebRTC connections 2013-07-23 17:49:19 -07:00
Matt Colyer 0e3940373d Add user to turn server configuration 2013-07-23 17:49:19 -07:00
Corey Johnson & Matt Colyer 07dea75562 Configure TURN and STUN servers 2013-07-23 17:49:19 -07:00
Kevin Sawicki & Nathan Sobo 1bd9a6bef3 Display cursors from all replicas 2013-07-23 17:49:19 -07:00
Kevin Sawicki & Nathan Sobo 1bf6307480 Display selections from all replicas 2013-07-23 17:49:19 -07:00
Kevin Sawicki & Nathan Sobo b8b9653fc0 💄 2013-07-23 17:49:19 -07:00
Kevin Sawicki & Nathan Sobo 636f81703c Distinguish remote and local selections in EditSession
Also: Add an Environment spec helper class that swaps out global
variables to simulate running code in different environments for the
replication specs.
2013-07-23 17:49:14 -07:00
Kevin Sawicki 5161a71bae Remove unused telepath key from initial data hash 2013-07-23 12:02:59 -07:00
Kevin Sawicki & Nathan Sobo 9c67aa105b Replace createSite with new Site 2013-07-23 11:58:41 -07:00
Kevin Sawicki adbdb1492f DRY up repo URL to project path mapping 2013-07-23 11:56:42 -07:00
Kevin Sawicki 4fff0b9792 Remove project path from state so it doesn't replicate 2013-07-23 11:40:21 -07:00
Kevin Sawicki 4c912f4538 Pretty print window state JSON when serializing to disk 2013-07-23 11:34:03 -07:00
Kevin Sawicki a305e15746 Shrink avatar image/video to 32px 2013-07-23 08:31:32 -07:00
Kevin Sawicki 202492cc4b Trigger started/stopped events based on peer.js open/close events 2013-07-23 08:28:02 -07:00
Kevin Sawicki & Nathan Sobo f3a932bbde Remove unused initialPath load setting
This is now handled inside Project@deserialize
2013-07-22 20:00:15 -07:00
Kevin Sawicki & Nathan Sobo 7aa2084147 💄 2013-07-22 19:59:18 -07:00
Kevin Sawicki & Nathan Sobo 019a0f2b84 Don't deserialize null pane container root 2013-07-22 19:58:59 -07:00
Kevin Sawicki & Nathan Sobo 501a6b7d11 Add site global used to create all telepath documents 2013-07-22 19:58:27 -07:00
Kevin Sawicki & Nathan Sobo 0370eb9236 Default soft wrap to millionth column
This is because peer.js cannot encode Infinity
but it should be ideally controlled via a boolean
flag instead of column number.
2013-07-22 18:40:57 -07:00
Kevin Sawicki & Nathan Sobo 4cba8ab48f Serialize project when editor window is unloaded 2013-07-22 18:39:32 -07:00
Kevin Sawicki & Nathan Sobo f4e7693e70 💩 Put apm back to version we clobbered during merge 2013-07-22 18:47:16 -06:00
Kevin Sawicki & Nathan Sobo 73adc40c4e 💄 use array-shorthand instead of new Range 2013-07-22 18:39:46 -06:00
Kevin Sawicki & Nathan Sobo 844469a9a7 Resolve filePath in Project.buildBuffer 2013-07-22 18:39:22 -06:00
Kevin Sawicki & Nathan Sobo faa8a8d9fc Use absolute path instead of uri when opening save-as dialog 2013-07-22 18:18:42 -06:00
Kevin Sawicki & Nathan Sobo fa59aafffb Relativize buffer paths for replication
TextBuffers now maintain a reference to their containing project to
make it easier to test replication of buffers between environments
without worrying about the value of the `project` global.

We're also starting the process of moving the `git` global into Project
as the `Project.repository` property.
2013-07-22 18:13:01 -06:00
Corey Johnson & Matt Colyer d051cbe0f6 Add video and audio streams to host view 2013-07-22 14:13:58 -07:00
Corey Johnson & Matt Colyer 1f18c0ba02 Stream audio and video feed of host to guest view
Conflicts:
	src/packages/collaboration/lib/session-utils.coffee
2013-07-22 13:58:55 -07:00
Corey Johnson & Matt Colyer 034aaa2927 Assume first message sent by host is a telepath document 2013-07-22 13:57:46 -07:00
probablycorey 7b57c12f59 💄 2013-07-22 13:57:36 -07:00
Kevin Sawicki & Nathan Sobo 642df0924d Merge branch 'master' into shared-buffers
Conflicts:
	vendor/apm
2013-07-22 11:54:51 -07:00
Kevin Sawicki 56a2c79fe1 Merge branch 'collaboration-presence' into shared-buffers
Conflicts:
	src/app/edit-session.coffee
	src/app/project.coffee
	src/app/text-buffer.coffee
	src/app/window.coffee
	src/packages/collaboration/lib/bootstrap.coffee
	src/packages/collaboration/lib/session-utils.coffee
	vendor/telepath
2013-07-22 10:12:45 -07:00
Nathan Sobo d85560e886 💄 2013-07-21 18:38:51 -06:00
Nathan Sobo 25d594e717 Update spell-check package for new telepath-based marker API 2013-07-21 18:00:55 -06:00
Nathan Sobo 383ba80d1e Use EditSession.getSoftTabs instead of .softTabs attr in snippets spec 2013-07-21 17:51:42 -06:00
Nathan Sobo 561e666091 Eliminate EditSession.markersForBufferPosition
We use findMarkers for everything now
2013-07-21 17:51:02 -06:00
Nathan Sobo 071f8a6a84 Use .findMarkers instead of .markersForBufferPosition in snippets 2013-07-21 17:50:12 -06:00
Nathan Sobo da95d26c58 Upgrade telepath to fix markers at end of buffer being invalid 2013-07-21 17:49:51 -06:00
Nathan Sobo 9c4478302e Translate attribute names in DisplayBufferMarker.matchesAttributes 2013-07-21 17:49:15 -06:00
Nathan Sobo 28a0bdaf95 Add TextBuffer.destroyMarker 2013-07-21 17:14:16 -06:00
Nathan Sobo 50ade54c3c Also serialize project in pane specs that remove the pane from the DOM
The project contains the only reference to the buffer that belongs to
the edit session in the serialized pane. If we tear down the pane then
the edit session is destroyed and the buffer is removed. So we have to
serialize and restore the project to its previous state once we finish
tearing down the view.
2013-07-21 16:55:44 -06:00
Nathan Sobo d43f459ad1 Fall back to .serialize() if a pane item has no .getState() method 2013-07-21 16:46:22 -06:00
Nathan Sobo 383985d331 Ensure there is clean serialization of RootView state
Everything from RootView to Pane needs to return a serialized clone of
its state, so we don't accidentally further mutate the serialized state
in tests.
2013-07-20 22:40:40 -06:00
Nathan Sobo 5246d4cd72 Add Project.getState() and make Project.serialize clone state 2013-07-20 21:24:32 -06:00
Nathan Sobo 97c4b9a83a Don't clone state in EditSession.getState() 2013-07-20 21:21:51 -06:00
Nathan Sobo ff9acb50ff Deserialize display buffer when deserializing edit sessions
Previously, we kept display buffer attributes in the edit session's
serialized state, then recreated a fresh display buffer each time when
deserializing edit sessions. Now that DisplayBuffer and TokenizedBuffer
are serializable, we can just include them directly when serializing
the edit session.
2013-07-20 18:21:44 -06:00
Nathan Sobo ca0832e58e Include folds in DisplayBuffer deserialization 2013-07-20 16:41:46 -07:00
Nathan Sobo 503629fdcb 💄 2013-07-20 16:40:38 -07:00
Nathan Sobo eeeb453cf9 Back DisplayBuffer with a telepath document 2013-07-20 16:22:26 -07:00
Nathan Sobo e1f795a352 Back TokenizedBuffer with a telepath document 2013-07-20 15:42:13 -07:00
Nathan Sobo 2b7a294cdd Use new marker attribute API to store/replicate selection goal ranges 2013-07-20 02:24:35 -07:00
Nathan Sobo c85932d46b Preserve folds and all selection attributes when copying EditSessions 2013-07-20 02:23:12 -07:00
Nathan Sobo 75cf1acce1 Honor preserveFolds option when creating a new selection 2013-07-20 02:23:12 -07:00
Nathan Sobo 7f5d71dada 💄 2013-07-20 02:23:12 -07:00
Nathan Sobo 1f8fd3c16c Fix isReversed option name 2013-07-20 02:23:12 -07:00
Nathan Sobo 7ccfd6c94b 💄 2013-07-20 02:23:12 -07:00
Nathan Sobo 1911ef2d80 Fix 'isReversed' option name for marker creation 2013-07-20 02:23:12 -07:00
Nathan Sobo 74347ea874 Upgrade telepath to allow marker attributes to be updated 2013-07-20 02:23:06 -07:00
Nathan Sobo de1b69dbc9 Add DisplayBuffer.copy 2013-07-18 11:34:39 -07:00
Nathan Sobo 8b53b4d749 Add ability to copy display buffer markers 2013-07-18 10:25:03 -07:00
Nathan Sobo c54bb792b2 Make EditSession.copy return a copy with a unique id and markers
We want to be able to use the copy independently, which means we
should not use EditSession@deserialize to create it because that will
tie us to the same selection markers.
2013-07-18 06:23:43 -07:00
Nathan Sobo 804df73e8d Get edit session specs passing with selection based markers 2013-07-17 19:16:42 -07:00
Nathan Sobo a724ef3b40 Tag selection markers with a disambiguating EditSession id
This prevents selection markers created by different edit sessions
from being shared. Otherwise every edit session for a buffer would be
forced to have the same selection/cursor state.
2013-07-17 15:29:21 -07:00
Nathan Sobo ab8c0bbf04 Make DisplayBuffer.getMarkers call down into TextBuffer.getMarkers 2013-07-17 15:00:15 -07:00
Ben Ogle & Nathan Sobo 96f434f276 Set languageMode and softTabs in constructor, not setBuffer
The softTabs option is only in scope in the constructor, and it can
sometimes be needed if we're unable to auto-determine the softTabs
setting from the buffer.
2013-07-17 14:59:46 -07:00
Ben Ogle & Nathan Sobo ba3fa50c6e Add DisplayBufferMarker.getAttributes 2013-07-17 14:58:21 -07:00
Ben Ogle & Nathan Sobo e8d4bbe5e7 💄 Extract setBuffer/buildDisplayBuffer methods 2013-07-17 12:05:18 -07:00
Ben Ogle & Nathan Sobo bb695ec53f Replicate the destruction of selections 2013-07-17 11:53:39 -07:00
Ben Ogle & Nathan Sobo 6079dd4ba3 💄 2013-07-17 11:33:56 -07:00
Ben Ogle & Nathan Sobo 47bfac22c2 Replicate the addition of new selections 2013-07-17 11:12:42 -07:00
Ben Ogle & Nathan Sobo 461e331f58 🙊 2013-07-17 11:12:18 -07:00
Ben Ogle & Nathan Sobo f32e1fc643 Replicate initial EditSession selection state 2013-07-17 10:25:28 -07:00
Ben Ogle & Nathan Sobo baeae2d8d5 Upgrade telepath so we can query 'invalidation' key in findMarkers 2013-07-17 10:25:02 -07:00
Kevin Sawicki 6482e26526 Copy session url to clipboard instead of just id 2013-07-16 09:49:47 -07:00
Kevin Sawicki 0a4e3cec94 Add missing connection prefix to event name 2013-07-16 09:49:47 -07:00
Kevin Sawicki c8accea5dc Synchronize instead of Synchronize 2013-07-16 09:49:47 -07:00
Kevin Sawicki 438b8f6a14 Support launching the app directly with a URL
In this case there will be no paths to open and so editor windows
should be created.

This will allow sessions to be joined when Atom isn't currently running
but a session link is clicked from within another application.
2013-07-16 09:49:47 -07:00
Kevin Sawicki 522768e6c0 Handle opening session urls 2013-07-16 09:49:47 -07:00
Kevin Sawicki 5bb45d4684 Add serialization version to image and archive edit sessions 2013-07-16 09:49:46 -07:00
Kevin Sawicki 3d6fb85152 Upgrade to patrick 2.0 2013-07-16 09:49:46 -07:00
Kevin Sawicki 9ccf9365c3 Make all edit session uri's relative
This allows them to be collaborated without having absolute paths
in the shared document.
2013-07-16 09:49:46 -07:00
Kevin Sawicki a9710e7a63 Ignore session id if empty 2013-07-16 09:49:46 -07:00
Kevin Sawicki f3bb826e8d Remove unused color from dark collaboration theme 2013-07-16 09:49:46 -07:00
Kevin Sawicki 96b91ef36b Add collaboration stylesheet for light theme 2013-07-16 09:49:46 -07:00
Kevin Sawicki ae9ffbb526 Rename buddy-list.less to collaboration.less 2013-07-16 09:49:46 -07:00
Kevin Sawicki 89dba4603c Add progress bar to loading sesion view 2013-07-16 09:49:46 -07:00
Corey Johnson & Kevin Sawicki 8812b6c31d Use patrick to mirror repository state 2013-07-16 09:49:46 -07:00
Corey Johnson & Kevin Sawicki 33f538ebf4 Create new branch if guest has unpushed changes 2013-07-16 09:49:46 -07:00
Corey Johnson & Kevin Sawicki 56b333e7fb 💄
Kevin found this offensive
2013-07-16 09:49:46 -07:00
Corey Johnson & Kevin Sawicki 72d76e511e Begin replication of host repo state 2013-07-16 09:49:45 -07:00
Corey Johnson & Kevin Sawicki 601efa53e6 Only create single host view instance 2013-07-16 09:49:45 -07:00
Corey Johnson & Kevin Sawicki af80327995 Set guest session project path from repo name 2013-07-16 09:49:45 -07:00
Corey Johnson & Kevin Sawicki 3ce520d9de Store participants and repository under collaborationState doc 2013-07-16 09:49:45 -07:00
Corey Johnson & Kevin Sawicki 1836257f0b Show avatars in host and guest views 2013-07-16 09:49:45 -07:00
Kevin Sawicki 98765c7d5c Only display participants that aren't the host 2013-07-16 09:49:45 -07:00
Kevin Sawicki f3ca26e2c9 Trigger participants-changed in guest session 2013-07-16 09:49:45 -07:00
Kevin Sawicki b1ca43ac0f Upgrade telepath 2013-07-16 09:49:45 -07:00
Kevin Sawicki 5ce0cf65c4 Unvendor pusher.js 2013-07-16 09:49:45 -07:00
Corey Johnson & Kevin Sawicki 460a09f9eb Show participants in the session 2013-07-16 09:49:45 -07:00
Corey Johnson & Kevin Sawicki 40d500949b Remove presence from collaboration package. 2013-07-16 09:49:45 -07:00
Corey Johnson & Kevin Sawicki be078b2b41 Add share button to buddy list 2013-07-16 09:49:45 -07:00
Kevin Sawicki 0fd44994ee Trigger status changed for self 2013-07-16 09:49:44 -07:00
Kevin Sawicki 09e73b16fe Show all open windows in buddy list 2013-07-16 09:49:44 -07:00
Kevin Sawicki b55e62f2ab Use fat arrow for callbacks 2013-07-16 09:49:44 -07:00
Kevin Sawicki aab4d7a78b Add avatar to buddy view 2013-07-16 09:49:44 -07:00
Kevin Sawicki 533f91e7ac Remove unused class 2013-07-16 09:49:44 -07:00
Kevin Sawicki aed7d3ed70 Make buddy list a permanent view on the right 2013-07-16 09:49:44 -07:00
Kevin Sawicki 0fdb15f9a6 Move peer.js to vendor directory 2013-07-16 09:49:44 -07:00
Kevin Sawicki 05748cd7dc Display repo and branch in buddy list 2013-07-16 09:49:44 -07:00
Kevin Sawicki b127492c9f Add initial buddy list 2013-07-16 09:49:44 -07:00
Kevin Sawicki 4fde8f0753 Export Pusher class 2013-07-16 09:49:44 -07:00
Kevin Sawicki e7ba9e1c9d Add Git.getConfigValue() 2013-07-16 09:49:44 -07:00
Kevin Sawicki d1812d74d6 Vendor pusher.js 2013-07-16 09:49:44 -07:00
Kevin Sawicki & Nathan Sobo abc20b3a05 Update text buffer to use telepath markers 2013-07-15 17:07:06 -07:00
Kevin Sawicki 010fa219aa Move Point and Range specs to telepath 2013-07-05 12:53:51 -07:00
Kevin Sawicki cdbbb114f6 Use PeerServer ☁️ instead of EC2 2013-07-05 12:53:51 -07:00
Kevin Sawicki b8bd9b6ec6 Compare site id using site from original event
Previously the site was being looked for in a copy of the event where
only the range and text keys were picked and so it was always missing.
2013-07-05 12:53:51 -07:00
Kevin Sawicki & Nathan Sobo 5a26fa838f Emit markers-updated event for remote buffer changes
This is temporary until markers are a part of telepath.
2013-07-05 12:53:51 -07:00
Kevin Sawicki & Nathan Sobo bffe361151 Upgrade telepath 2013-07-05 12:53:51 -07:00
Kevin Sawicki & Nathan Sobo bf45beedbe Swap parameter order for Document.deserialize() 2013-07-05 12:53:51 -07:00
Kevin Sawicki & Nathan Sobo e82170efcb Serialize EditSession's buffer's id instead of its path 2013-07-05 12:53:50 -07:00
Kevin Sawicki & Nathan Sobo 9b22ca4825 Serialize window state in telepath format 2013-07-05 12:53:50 -07:00
Kevin Sawicki & Nathan Sobo 85cc81851f Replicate insertion and removal of project buffers
Buffers are now destroyed when removed from the project if they
haven't been destroyed already.
2013-07-05 12:53:50 -07:00
Kevin Sawicki & Nathan Sobo 30273c6a66 Add serialization version to TextBuffer 2013-07-05 12:53:50 -07:00
Kevin Sawicki & Nathan Sobo e01ac96b66 Guard against a null pending changed event
Previously TextBuffer would emit change events even when the change
was empty. SharedString does not emit empty change events and so a
pending event may no longer be present when a marker-updated event
fires.
2013-07-05 12:53:50 -07:00
Kevin Sawicki & Nathan Sobo 2ff282011b 💄 2013-07-05 12:53:50 -07:00
Kevin Sawicki f766bbbb38 Remove Point and Range classes now provided by telepath 2013-07-05 12:53:50 -07:00
Kevin Sawicki e5ef23dc5a Expect null instead of undefined for invalid line rows 2013-07-05 12:53:50 -07:00
Kevin Sawicki fddcbae4eb Clip range specified to change() 2013-07-05 12:53:50 -07:00
Kevin Sawicki 2d313e07ff Clip position in characterIndexForPosition() 2013-07-05 12:53:50 -07:00
Kevin Sawicki 1efa480b4e Upgrade telepath 2013-07-05 12:53:50 -07:00
Kevin Sawicki & Nathan Sobo 05a3f35512 Normalize line endings in TextBuffer.change() 2013-07-05 12:53:50 -07:00
Kevin Sawicki & Nathan Sobo 72f9af4d00 Replicate buffer changes
Still some failures due to line endings
2013-07-05 12:53:49 -07:00
Kevin Sawicki & Nathan Sobo dd0f7a032f Start basing Buffer's text on a replicable string 2013-07-05 12:53:49 -07:00
Kevin Sawicki & Nathan Sobo 010c3435da Add Project serialization version 2013-07-05 12:53:49 -07:00
Kevin Sawicki & Nathan Sobo da3a89fc27 Don't show pane items that can't be deserialized 2013-07-05 12:53:49 -07:00
Nathan Sobo 30e4531a8f Store buffer paths instead of serialized buffers in EditSession state
Since there can be multiple edit sessions per buffer, it doesn't make
sense to serialize the buffer multiple times. Previously, we were
de-duplicating buffers in the deserialize method itself, but this won't
work now that we want to replicate buffers.
2013-07-05 12:53:49 -07:00
430 arquivos alterados com 5242 adições e 21748 exclusões
+1 -1
Ver Arquivo
@@ -7,4 +7,4 @@ node_modules
npm-debug.log
/tags
/atom-shell/
docs/api
docs/output
+1 -4
Ver Arquivo
@@ -3,7 +3,4 @@
url = https://github.com/twbs/bootstrap
[submodule "vendor/apm"]
path = vendor/apm
url = https://github.com/github/apm.git
[submodule "vendor/telepath"]
path = vendor/telepath
url = https://github.com/github/telepath.git
url = https://github.com/atom/apm.git
+2
Ver Arquivo
@@ -8,7 +8,9 @@ pairs:
jp: Justin Palmer; justin
gt: Garen Torikian; garen
mc: Matt Colyer; mcolyer
bo: Ben Ogle; benogle
jr: Jason Rudolph; jasonrudolph
jl: Jessica Lord; jlord
email:
domain: github.com
#global: true
+7
Ver Arquivo
@@ -1,3 +1,10 @@
* Added: Soft wrap and tab length can now be set in the settings view
* Fixed: Python import statements not syntax highlighting correctly
* Added: Terminal package now bundled by default, open with ctrl-`
* Fixed: Fuzzy finder not showing results for files at a certain depth
* Fixed: Atom > Preferences... menu not opening settings in focused window
* Fixed: Atom failing to launch if the theme being used was not found
* Improved: Theme changes now immediately take effect
+36 -1
Ver Arquivo
@@ -1,5 +1,6 @@
# :rotating_light: Contributing to Atom :rotating_light:
## Issues
* Include screenshots and animated GIFs whenever possible, they are immensely
helpful
@@ -17,12 +18,46 @@
specs
* Style new elements in both the light and dark default themes when
appropriate
* New packages go in `src/packages/`
* Add 3rd-party packages as a `package.json` dependency
* Commit messages are in the present tense
* Commit messages that improve the format of the code start with :lipstick:
* Commit messages that improve the performance start with :racehorse:
* Commit messages that remove memory leaks start with :non-potable_water:
* Files end with a newline
* Class variables and methods should be in the following order:
* Class variables (variables starting with a `@`)
* Class methods (methods starting with a `@`)
* Instance variables
* Instance methods
## Philosophy
### Write Beautiful Code
Once you get something working, take the time to consider whether you can achieve it in a more elegant way. We're planning on open-sourcing Atom, so let's put our best foot forward.
### When in doubt, pair-up
Pairing can be an effective and fun way to pass on culture, knowledge, and taste. If you can find the time, we encourage you to work synchronously with other community members of all experience levels to help the knowledge-mulching process. It doesn't have to be all the time; a little pairing goes a long way.
### Write tests, and write them first
The test suite keeps protects our codebase from the ravages of entropy, but it only works when we have thorough coverage. Before you write implementation code, write a failing test proving that it's needed.
### Leave the test suite better than you found it
Consider how the specs you are adding fit into the spec-file as a whole. Is this the right place for your spec? Does the spec need to be reorganized now that you're adding this extra dimension? Specs are only as useful as the next person's ability to understand them.
### Solve today's problem
Avoid adding flexibility that isn't needed *today*. Nothing is ever set in stone, and we can always go back and add flexibility later. Adding it early just means we have to pay for complexity that we might not end up using.
### Favor clarity over brevity or cleverness.
Three lines that someone else can read are better than one line that's tricky.
### Don't be defensive
Only catch exceptions that are truly exceptional. Assume that components we control will honor their contracts. If they don't, the solution is to find and fix the problem in code rather than cluttering the code with attempts to foresee all potential issues at runtime.
### Don't be afraid to add classes and methods
Code rarely suffers from too many methods and classes, and often suffers from too few. Err on the side of numerous short, well-named methods. Pull out classes with well-defined roles.
### Rip shit out
Don't be afraid to delete code. Don't be afraid to rewrite something that needs to be refreshed. If it's in version control, we can always resurrect it.
### Maintain a consistent level of abstraction
Every line in a method should read at the same basic level of abstraction. If there's a section of a method that goes into a lot more detail than the rest of the method, consider extracting a new method and giving it a clear name.
+101 -38
Ver Arquivo
@@ -1,58 +1,80 @@
fs = require 'fs'
path = require 'path'
fm = require 'json-front-matter'
_ = require 'underscore'
packageJson = require './package.json'
module.exports = (grunt) ->
appName = 'Atom.app'
[major, minor, patch] = packageJson.version.split('.')
buildDir = grunt.option('build-dir') ? '/tmp/atom-build'
shellAppDir = path.join(buildDir, appName)
contentsDir = path.join(shellAppDir, 'Contents')
appDir = path.join(contentsDir, 'Resources', 'app')
installDir = path.join('/Applications', appName)
coffeeConfig =
options:
sourceMap: true
glob_to_multiple:
expand: true
src: [
'src/**/*.coffee'
'static/**/*.coffee'
]
dest: appDir
ext: '.js'
lessConfig =
options:
paths: [
'static'
'vendor'
]
glob_to_multiple:
expand: true
src: [
'src/**/*.less'
'static/**/*.less'
'themes/**/*.less'
]
dest: appDir
ext: '.css'
csonConfig =
options:
rootObject: true
glob_to_multiple:
expand: true
src: [
'keymaps/*.cson'
'src/**/*.cson'
'static/**/*.cson'
'themes/**/*.cson'
]
dest: appDir
ext: '.json'
for child in fs.readdirSync('node_modules') when child isnt '.bin'
directory = path.join('node_modules', child)
{engines} = grunt.file.readJSON(path.join(directory, 'package.json'))
if engines?.atom?
coffeeConfig.glob_to_multiple.src.push("#{directory}/**/*.coffee")
lessConfig.glob_to_multiple.src.push("#{directory}/**/*.less")
csonConfig.glob_to_multiple.src.push("#{directory}/**/*.cson")
grunt.initConfig
pkg: grunt.file.readJSON('package.json')
atom: {appDir, appName, buildDir, contentsDir, installDir, shellAppDir}
coffee:
options:
sourceMap: true
glob_to_multiple:
expand: true
src: [
'src/**/*.coffee'
'static/**/*.coffee'
]
dest: appDir
ext: '.js'
coffee: coffeeConfig
less:
options:
paths: [
'static'
'vendor'
]
glob_to_multiple:
expand: true
src: [
'src/**/*.less'
'static/**/*.less'
'themes/**/*.less'
]
dest: appDir
ext: '.css'
less: lessConfig
cson:
options:
rootObject: true
glob_to_multiple:
expand: true
src: [
'src/**/*.cson'
'static/**/*.cson'
'themes/**/*.cson'
]
dest: appDir
ext: '.json'
cson: csonConfig
coffeelint:
options:
@@ -103,16 +125,57 @@ module.exports = (grunt) ->
'themes/**/*.less'
]
markdown:
guides:
files: [
expand: true
cwd: 'docs'
src: '**/*.md'
dest: 'docs/output/'
ext: '.html'
]
options:
template: 'docs/template.jst'
templateContext:
tag: "v#{major}.#{minor}"
markdownOptions:
gfm: true
preCompile: (src, context) ->
parsed = fm.parse(src)
_.extend(context, parsed.attributes)
parsed.body
shell:
'kill-atom':
command: 'pkill Atom'
options:
stdout: false
stderr: false
failOnError: false
test:
command: "#{path.join(contentsDir, 'MacOS', 'Atom')} --test --resource-path=#{__dirname}"
options:
stdout: true
stderr: true
callback: (error, stdout, stderr, callback) ->
grunt.warn('Specs failed') if error?
callback()
grunt.loadNpmTasks('grunt-coffeelint')
grunt.loadNpmTasks('grunt-lesslint')
grunt.loadNpmTasks('grunt-cson')
grunt.loadNpmTasks('grunt-contrib-csslint')
grunt.loadNpmTasks('grunt-contrib-coffee')
grunt.loadNpmTasks('grunt-contrib-less')
grunt.loadNpmTasks('grunt-markdown')
grunt.loadNpmTasks('grunt-shell')
grunt.loadTasks('tasks')
grunt.registerTask('compile', ['coffee', 'less', 'cson'])
grunt.registerTask('lint', ['coffeelint', 'csslint', 'lesslint'])
grunt.registerTask('test', ['shell:kill-atom', 'shell:test'])
grunt.registerTask('ci', ['lint', 'partial-clean', 'update-atom-shell', 'build', 'set-development-version', 'test'])
grunt.registerTask('deploy', ['partial-clean', 'update-atom-shell', 'build', 'codesign'])
grunt.registerTask('docs', ['markdown:guides', 'build-docs'])
grunt.registerTask('default', ['update-atom-shell', 'build', 'set-development-version', 'install'])
+1 -1
Ver Arquivo
@@ -2,7 +2,7 @@
![atom](https://s3.amazonaws.com/speakeasy/apps/icons/27/medium/7db16e44-ba57-11e2-8c6f-981faf658e00.png)
Check out our [documentation on the docs tab](https://github.com/github/atom/docs).
Check out our [guides](https://atom-docs.githubapp.com/v20.0/index.html) and [API documentation](https://atom-docs.githubapp.com/v20.0/api/index.html).
## Installing
+1 -1
Ver Arquivo
@@ -1,7 +1,7 @@
rule "" do |t|
puts <<-HELP
Atom now uses grunt instead of Rake.
See https://github.com/github/atom/pull/596 for more info.
See https://github.com/atom/atom/pull/596 for more info.
tl;dr
-----
-2
Ver Arquivo
@@ -1,2 +0,0 @@
coffee -c -o /Applications/Atom.app/Contents/Resources/app/src/ src/main.coffee src/atom-application.coffee src/atom-window.coffee &&
/Applications/Atom.app/Contents/MacOS/Atom --resource-path=$(pwd) --executed-from=$(pwd) $@
+3 -3
Ver Arquivo
@@ -9,14 +9,14 @@ if [ ! -d $ATOM_PATH ]; then
exit 1
fi
while getopts ":whv-:" opt; do
while getopts ":whvft-:" opt; do
case "$opt" in
-)
case "${OPTARG}" in
wait)
WAIT=1
;;
help|version)
help|version|foreground|test)
EXPECT_OUTPUT=1
;;
esac
@@ -24,7 +24,7 @@ while getopts ":whv-:" opt; do
w)
WAIT=1
;;
h|v)
h|v|f|t)
EXPECT_OUTPUT=1
;;
esac
+12 -26
Ver Arquivo
@@ -1,30 +1,11 @@
nakedLoad 'jasmine-jquery'
require '../spec/spec-helper'
$ = require 'jquery'
_ = require 'underscore'
Keymap = require 'keymap'
Point = require 'point'
Config = require 'config'
{Point} = require 'telepath'
Project = require 'project'
require 'window'
requireStylesheet "jasmine.less"
# Load TextMate bundles, which specs rely on (but not other packages)
atom.loadTextMatePackages()
beforeEach ->
# reset config after each benchmark; don't load or save from/to `config.json`
window.config = new Config()
spyOn(config, 'load')
spyOn(config, 'save')
keymap = new Keymap
keymap.bindDefaultKeys()
$(window).on 'keydown', (e) -> keymap.handleKeyEvent(e)
keymap.bindKeys '*',
'meta-w': 'close'
'alt-meta-i': 'show-console'
$(document).on 'close', -> window.close()
fsUtils = require 'fs-utils'
TokenizedBuffer = require 'tokenized-buffer'
defaultCount = 100
window.pbenchmark = (args...) -> window.benchmark(args..., profile: true)
@@ -32,7 +13,13 @@ window.fbenchmark = (args...) -> window.benchmark(args..., focused: true)
window.fpbenchmark = (args...) -> window.benchmark(args..., profile: true, focused: true)
window.pfbenchmark = window.fpbenchmark
window.benchmarkFixturesProject = new Project(require.resolve 'benchmark/fixtures')
window.benchmarkFixturesProject = new Project(fsUtils.resolveOnLoadPath('benchmark/fixtures'))
beforeEach ->
window.project = window.benchmarkFixturesProject
jasmine.unspy(window, 'setTimeout')
jasmine.unspy(window, 'clearTimeout')
jasmine.unspy(TokenizedBuffer::, 'tokenizeInBackground')
window.benchmark = (args...) ->
description = args.shift()
@@ -43,7 +30,6 @@ window.benchmark = (args...) ->
[fn, options] = args
{ profile, focused } = (options ? {})
atom.showDevTools() if profile
method = if focused then fit else it
method description, ->
total = measure ->
+6 -9
Ver Arquivo
@@ -1,31 +1,28 @@
require 'benchmark-helper'
require './benchmark-helper'
$ = require 'jquery'
_ = require 'underscore'
TokenizedBuffer = require 'tokenized-buffer'
RootView = require 'root-view'
describe "editor.", ->
editor = null
beforeEach ->
window.rootViewParentSelector = '#jasmine-content'
window.attachRootView(require.resolve('benchmark/fixtures'))
window.rootView = new RootView
window.rootView.attachToDom()
rootView.width(1024)
rootView.height(768)
rootView.open() # open blank editor
editor = rootView.getActiveEditor()
editor = rootView.getActiveView()
afterEach ->
if editor.pendingDisplayUpdate
waitsFor "editor to finish rendering", (done) ->
editor.on 'editor:display-updated', done
runs ->
projectPath = project.getPath()
$(window).off 'beforeunload'
window.shutdown()
atom.setRootViewStateForPath(projectPath, null)
describe "keymap.", ->
event = null
-29
Ver Arquivo
@@ -1,29 +0,0 @@
## Command Panel
The command panel contains a partial implementation of the [Sam command language](http://man.cat-v.org/plan_9/1/sam).
In addition, packages are free to design and define any scoped command.
Pop open the command line by hitting .
You can get a list of commands available to Atom (including any keybindings) by hitting `meta-p`.
## Examples
`,` selects the entire file
`1,4` selects lines 1-4 in the current file
`/pattern` selects the first match after the cursor/selection
`s/pattern/replacement` replaces the first text matching pattern in current selection
`s/pattern/replacement/g` replaces all text matching pattern in current selection
`,s/pattern/replacement/g` replaces all text matching pattern in file
`1,4s/pattern/replacement` replaces all text matching pattern in lines 1-4
`x/pattern` selects all matches in the current selections
`,x/pattern` selects all matches in the file
`,x/pattern1/ x/pattern2` "structural regex" - selects all matches of pattern2 inside matches of pattern1
-3
Ver Arquivo
@@ -1,3 +0,0 @@
# Built-In Packages
Atom ships with several optional built-in packages.
-7
Ver Arquivo
@@ -1,7 +0,0 @@
## Markdown Preview
The `markdown-preview` extension displays the rendered HTML for the markdown
in the current editor.
It can be activated from the editor using the `ctrl-m` key-binding and is
currently enabled for `.markdown`, `.md`, `.mkd`, `.mkdown`, and `.ron` files.
-33
Ver Arquivo
@@ -1,33 +0,0 @@
## Wrap Guide
The `wrap-guide` extension places a vertical line in each editor at a certain
column to guide your formatting, so lines do not exceed a certain width.
By default, the wrap-guide is placed at the 80th column.
### Configuration
You can customize where the column is placed using the `wrapGuide.columns`
config option:
```coffeescript
"wrap-guide":
columns: [
{ pattern: "\.mm$", column: 200 },
{ pattern: "\.cc$", column: 120 }
]
```
The above config example would place the guide at the 200th column for paths
that end with `.mm` and place the guide at the 120th column for paths that end
with `.cc`.
You can configure the color and/or width of the line by adding the following
CSS to a custom stylesheet:
```css
.wrap-guide {
width: 10px;
background-color: red;
}
```
+492
Ver Arquivo
@@ -0,0 +1,492 @@
{{{
"title": "Creating a Package"
}}}
# Authoring Packages
Packages are at the core of Atom. Nearly everything outside of the main editor manipulation
is handled by a package. That includes "core" pieces like the command panel, status bar,
file tree, and more.
A package can contain a variety of different resource types to change Atom's
behavior. The basic package layout is as follows (though not every package will
have all of these directories):
```text
my-package/
lib/
stylesheets/
keymaps/
snippets/
grammars/
spec/
package.json
index.coffee
```
## package.json
Similar to [npm packages][npm], Atom packages
can contain a _package.json_ file in their top-level directory. This file contains metadata
about the package, such as the path to its "main" module, library dependencies,
and manifests specifying the order in which its resources should be loaded.
In addition to the regular [npm package.json keys](https://npmjs.org/doc/json.html)
available, Atom package.json files have their own additions.
- `main` (**Required**): the path to the CoffeeScript file that's the entry point
to your package
- `stylesheets` (**Optional**): an Array of Strings identifying the order of the
stylesheets your package needs to load. If not specified, stylesheets in the _stylesheets_
directory are added alphabetically.
- `keymaps`(**Optional**): an Array of Strings identifying the order of the
key mappings your package needs to load. If not specified, mappings in the _keymaps_
directory are added alphabetically.
- `snippets` (**Optional**): an Array of Strings identifying the order of the
snippets your package needs to load. If not specified, snippets in the _snippets_
directory are added alphabetically.
- `activationEvents` (**Optional**): an Array of Strings identifying events that
trigger your package's activation. You can delay the loading of your package until
one of these events is trigged.
## Source Code
If you want to extend Atom's behavior, your package should contain a single
top-level module, which you export from _index.coffee_ (or whichever file is
indicated by the `main` key in your _package.json_ file). The remainder of your
code should be placed in the `lib` directory, and required from your top-level
file.
Your package's top-level module is a singleton object that manages the lifecycle
of your extensions to Atom. Even if your package creates ten different views and
appends them to different parts of the DOM, it's all managed from your top-level
object.
Your package's top-level module should implement the following methods:
- `activate(rootView, state)`: This **required** method is called when your
package is loaded. It is always passed the window's global `rootView`, and is
sometimes passed state data if the window has been reloaded and your module
implements the `serialize` method. Use this to do initialization work when your
package is started (like setting up DOM elements or binding events).
- `serialize()`: This **optional** method is called when the window is shutting
down, allowing you to return JSON to represent the state of your component. When
the window is later restored, the data you returned is passed to your
module's `activate` method so you can restore your view to where the user left
off.
- `deactivate()`: This **optional** method is called when the window is shutting
down. If your package is watching any files or holding external resources in any
other way, release them here. If you're just subscribing to things on window,
you don't need to worry because that's getting torn down anyway.
### Simple Package Code
```text
my-package/
package.json # optional
index.coffee
lib/
my-package.coffee
```
`index.coffee`:
```coffeescript
module.exports = require "./lib/my-package"
```
`my-package/my-package.coffee`:
```coffeescript
module.exports =
activate: (rootView, state) -> # ...
deactivate: -> # ...
serialize: -> # ...
```
Beyond this simple contract, your package has full access to Atom's internal
API. Anything we call internally, you can call as well. Be aware that since we
are early in development, APIs are subject to change and we have not yet
established clear boundaries between what is public and what is private. Also,
please collaborate with us if you need an API that doesn't exist. Our goal is
to build out Atom's API organically based on the needs of package authors like
you.
See [Atom's built-in packages](https://github.com/atom/atom/)
for examples of Atom's API in action.
## Stylesheets
Stylesheets for your package should be placed in the _stylesheets_ directory.
Any stylesheets in this directory will be loaded and attached to the DOM when
your package is activated. Stylesheets can be written as CSS or LESS.
An optional `stylesheets` array in your _package.json_ can list the stylesheets by
name to specify a loading order; otherwise, stylesheets are loaded alphabetically.
## Keymaps
Keymaps are placed in the _keymaps_ subdirectory. It's a good idea to provide
default keymaps for your extension, especially if you're also adding a new command.
By default, all keymaps are loaded in alphabetical order. An optional `keymaps`
array in your _package.json_ can specify which keymaps to load and in what order.
See the [main keymaps documentation](../internals/keymaps.md) for more information on
how keymaps work.
## Snippets
An extension can supply language snippets in the _snippets_ directory. These can
be `.cson` or `.json` files. Here's an example:
```coffeescript
".source.coffee .specs":
"Expect":
prefix: "ex"
body: "expect($1).to$2"
"Describe":
prefix: "de"
body: """
describe "${1:description}", ->
${2:body}
"""
```
A snippets file contains scope selectors at its top level (`.source.coffee .spec`).
Each scope selector contains a hash of snippets keyed by their name (`Expect`, `Describe`).
Each snippet also specifies a `prefix` and a `body` key. The `prefix` represents
the first few letters to type before hitting the `tab` key to autocomplete. The
`body` defines the autofilled text. You can use placeholders like `$1`, `$2`, to indicate
regions in the body the user can navigate to every time they hit `tab`.
All files in the directory are automatically loaded, unless the
_package.json_ supplies a `snippets` key. As with all scoped
items, snippets loaded later take precedence over earlier snippets when two
snippets match a scope with the same specificity.
## Language Grammars
If you're developing a new language grammar, you'll want to place your file in
the _grammars_ directory. Each grammar is a pairing of two keys, `match` and
`captures`. `match` is a regular expression identifying the pattern to highlight,
while `captures` is a JSON representing what to do with each matching group.
For example:
```json
{
'match': '(?:^|\\s)(__[^_]+__)'
'captures':
'1': 'name': 'markup.bold.gfm'
}
```
This indicates that the first matching capture (`(__[^_]+__)`) should have the
`markup.bold.gfm` token applied to it.
To capture a single group, simply use the `name` key instead:
```json
{
'match': '^#{1,6}\\s+.+$'
'name': 'markup.heading.gfm'
}
```
This indicates that Markdown header lines (`#`, `##`, `###`) should be applied with
the `markup.heading.gfm` token.
More information about the significance of these tokens can be found in
[section 12.4 of the TextMate Manual](http://manual.macromates.com/en/language_grammars.html).
Your grammar should also include a `filetypes` array, which is a list of file extensions
your grammar supports:
```
'fileTypes': [
'markdown'
'md'
'mkd'
'mkdown'
'ron'
]
```
## Writing Tests
Your package **should** have tests, and if they're placed in the _spec_ directory,
they can be run by Atom.
Under the hood, [Jasmine](https://github.com/pivotal/jasmine) is being used to run
to execute the tests, so you can assume that any DSL available there is available
to your package as well.
# Full Example
Let's take a look at creating our first package.
Atom has a command you can enter that'll create a package for you:
`package-generator:generate`. Otherwise, you can hit `cmd-p`, and start typing
"Package Generator." Once you activate this package, it'll ask you for a name for
your new package. Let's call ours _changer_.
Now, _changer_ is going to have a default set of folders and files created for us.
Hit `cmd-r` to reload Atom, then hit `cmd-p` and start typing "Changer." You'll
see a new `Changer:Toggle` command which, if selected, pops up a new message. So
far, so good!
In order to demonstrate the capabilities of Atom and its API, our Changer plugin
is going to do two things:
1. It'll show only modified files in the file tree
2. It'll append a new pane to the editor with some information about the modified
files
Let's get started!
## Changing Keybindings and Commands
Since Changer is primarily concerned with the file tree, let's write a keybinding
that works only when the tree is focused. Instead of using the default `toggle`,
our keybinding executes a new command called `magic`.
_keymaps/changer.cson_ can easily become this:
```cson
'.tree-view-scroller':
'ctrl-V': 'changer:magic'
```
Notice that the keybinding is called `ctrl-V`--that's actually `ctrl-shift-v`.
You can use capital letters to denote using `shift` for your binding.
`.tree-view-scroller` represents the parent container for the tree view. Keybindings
only work within the context of where they're entered. For example, hitting `ctrl-V`
anywhere other than tree won't do anything. You can map to `body` if you want
to scope to anywhere in Atom, or just `.editor` for the editor portion.
To bind keybindings to a command, we'll use the `rootView.command` method. This
takes a command name and executes a function in the code. For example:
```coffeescript
rootView.command "changer:magic", => @magic()
```
It's common practice to namespace your commands with your package name, and separate
it with a colon (`:`). Rename the existing `toggle` method to `magic` to get the
binding to work.
Reload the editor, click on the tree, hit your keybinding, and...nothing happens! What the heck?!
Open up the _package.json_ file, and notice the key that says `activationEvents`.
Basically, this tells Atom to not load a package until it hears a certain event.
Let's change the event to `changer:magic` and reload the editor.
Hitting the key binding on the tree now works!
## Working with styles
The next step is to hide elements in the tree that aren't modified. To do that,
we'll first try and get a list of files that have not changed.
All packages are able to use jQuery in their code. In fact, we have [a list of
some of the bundled libraries Atom provides by default](#included-libraries).
Let's bring in jQuery:
```coffeescript
$ = require 'jquery'
```
Now, we can query the tree to get us a list of every file that _wasn't_ modified:
```coffeescript
magic: ->
$('ol.entries li').each (i, el) ->
if !$(el).hasClass("modified")
console.log el
```
You can access the dev console by hitting `alt-cmd-i`. When we execute the
`changer:magic` command, the browser console lists the items that are not being
modified. Let's add a class to each of these elements called `hide-me`:
```coffeescript
magic: ->
$('ol.entries li').each (i, el) ->
if !$(el).hasClass("modified")
$(el).addClass("hide-me")
```
With our newly added class, we can manipulate the visibility of the elements
with a simple stylesheet. Open up _changer.css_ in the _stylesheets_ directory,
and add a single entry:
```css
ol.entries .hide-me {
display: none;
}
```
Refresh atom, and run the `changer` command. You'll see all the non-changed files
disappear from the tree. There are a number of ways you can get the list back;
let's just naively iterate over the same elements and remove the class:
```coffeescript
magic: ->
$('ol.entries li').each (i, el) ->
if !$(el).hasClass("modified")
if !$(el).hasClass("hide-me")
$(el).addClass("hide-me")
else
$(el).removeClass("hide-me")
```
## Creating a New Pane
The next goal of this package is to append a pane to the Atom editor that lists
some information about the modified files.
To do that, we're going to first create a new class method called `content`. Every
package that extends from the `View` class can provide an optional class method
called `content`. The `content` method constructs the DOM that your package uses
as its UI. The principals of `content` are built entirely on [SpacePen](https://github.com/nathansobo/space-pen),
which we'll touch upon only briefly here.
Our display will simply be an unordered list of the file names, and their
modified times. Let's start by carving out a `div` to hold the filenames:
```coffeescript
@content: ->
@div class: 'modified-files-container', =>
@ul class: 'modified-files-list', outlet: 'modifiedFilesList', =>
@li 'Test'
@li 'Test2'
```
You can add any HTML5 attribute you like. `outlet` names the variable
your package can uses to manipulate the element directly. The fat pipe (`=>`) indicates
that the next set are nested children.
We'll add one more line to `magic` to make this pane appear:
```coffeescript
rootView.vertical.append(this)
```
If you hit the key command, you'll see a box appear right underneath the editor.
Success!
Before we populate this, let's apply some logic to toggle the pane off and on, just
like we did with the tree view:
```coffeescript
# toggles the pane
if @hasParent()
rootView.vertical.children().last().remove()
else
rootView.vertical.append(this)
```
There are about a hundred different ways to toggle a pane on and off, and this
might not be the most efficient one. If you know your package needs to be toggled
on and off more freely, it might be better to draw the UI during the initialization,
then immediately call `hide()` on the element to remove it from the view. You can
then swap between `show()` and `hide()`, and instead of forcing Atom to add and remove
the element as we're doing here, it'll just set a CSS property to control your package's
visibility.
You might have noticed that our two `li` elements aren't showing up. Let's set
a color on them so that they pop. Open up `changer.css` and add this CSS:
```css
ul.modified-files-list {
color: white;
}
```
Refresh Atom, hit the key combo, and see your brilliantly white test list.
## Calling Node.js Code
Since Atom is built on top of Node.js, you can call any of its libraries, including
other modules that your package requires.
We'll iterate through our resulting tree, and construct the path to our modified
file based on its depth in the tree:
```coffeescript
path = require 'path'
# ...
modifiedFiles = []
# for each single entry...
$('ol.entries li.file.modified span.name').each (i, el) ->
filePath = []
# ...grab its name...
filePath.unshift($(el).text())
# ... then find its parent directories, and grab their names
parents = $(el).parents('.directory.modified')
parents.each (i, el) ->
filePath.unshift($(el).find('div.header span.name').eq(0).text())
modifiedFilePath = path.join(project.rootDirectory.path, filePath.join(path.sep))
modifiedFiles.push modifiedFilePath
```
`modifiedFiles` is an array containing a list of our modified files. We're also using
the node.js [`path` library](http://nodejs.org/docs/latest/api/path.html) to get
the proper directory separator for our system.
Let's remove the two `@li` elements we added in `@content`, so that we can populate
our `modifiedFilesList` with real information. We'll do that by iterating over
`modifiedFiles`, accessing a file's last modified time, and appending it to
`modifiedFilesList`:
```coffeescript
# toggles the pane
if @hasParent()
rootView.vertical.children().last().remove()
else
for file in modifiedFiles
stat = fs.lstatSync(file)
mtime = stat.mtime
@modifiedFilesList.append("<li>#{file} - Modified at #{mtime}")
rootView.vertical.append(this)
```
When you toggle the modified files list, your pane is now populated with the filenames
and modified times of files in your project. You might notice that subsequent calls
to this command reduplicate information. We could provide an elegant way of rechecking
files already in the list, but for this demonstration, we'll just clear the `modifiedFilesList`
each time it's closed:
```coffeescript
# toggles the pane
if @hasParent()
@modifiedFilesList.empty()
rootView.vertical.children().last().remove()
else
for file in modifiedFiles
stat = fs.lstatSync(file)
mtime = stat.mtime
@modifiedFilesList.append("<li>#{file} - Modified at #{mtime}")
rootView.vertical.append(this)
```
# Included Libraries
In addition to core node.js modules, all packages can `require` the following popular
libraries into their packages:
* [SpacePen](https://github.com/nathansobo/space-pen) (as `require 'space-pen'`)
* [jQuery](http://jquery.com/) (as `require 'jquery'`)
* [Underscore](http://underscorejs.org/) (as `require 'underscore'`)
Additional libraries can be found by browsing Atom's _node_modules_ folder.
[npm]: http://en.wikipedia.org/wiki/Npm_(software)
+5
Ver Arquivo
@@ -0,0 +1,5 @@
{{{
"title": "Creating a Theme"
}}}
# Authoring Themes (Not Yet Implemented)
@@ -1,9 +1,13 @@
{{{
"title": "Customizing Atom"
}}}
# Configuration Settings
## Your .atom Directory
When you install Atom, an _.atom_ directory is created in your home directory.
If you press `meta-,`, that directory is opened in a new window. For the
If you press `cmd-,`, that directory is opened in a new window. For the
time being, this serves as the primary interface for adjusting configuration
settings, adding and changing key bindings, tweaking styles, etc.
@@ -81,36 +85,17 @@ keymaps or third-party packages.
Atom comes bundled with two themes `atom-dark-*` and `atom-light-*`.
Because Atom themes are based on CSS, it's possible to have multiple themes
active at the same time. For example, you'll usually select a theme for the UI
and another theme for syntax highlighting. You can select themes by specifying
them in the `core.themes` array in your `config.cson`:
active at the same time.
```coffee-script
core:
themes: ["atom-light-ui", "atom-light-syntax"]
# or, if the sun is going down:
# themes: ["atom-dark-ui", "atom-dark-syntax"]
```
For example, you'll usually select a theme for the UI and another theme for
syntax highlighting. You can change themes from the preferences pane.
You install new themes by placing them in the _~/.atom/themes_ directory. A
theme can be a CSS file, a directory containing multiple CSS files, or a
TextMate theme (either _.tmTheme_ or _.plist_).
theme can be a single LESS file or a directory containing multiple LESS files.
## Installing Packages
## Installing Packages (Partially Implemented)
To install a package, clone it into the _~/.atom/packages_ directory. Atom will
also load grammars and snippets from TextMate bundles. If you want to disable a
package without removing it from the packages directory, insert its name into
_config.core.disabledPackages_:
```coffeescript
core:
disabledPackages: [
"fuzzy-finder",
"tree-view"
]
```
FIXME: Rewrite for the new dialog.
## Quick Personal Hacks
@@ -122,17 +107,19 @@ make customizations. You have full access to Atom's API from code in this file.
Please refer to the [Atom Internals Guide](./internals/intro,md) for more information. If your
customizations become extensive, consider [creating a package](./packages/creating_packages.md).
### user.css
### user.less
If you want to apply quick-and-dirty personal styling changes without creating
an entire theme that you intend to distribute, you can add styles to
_user.css_ in your _~/.atom_ directory.
_user.less_ in your _~/.atom_ directory.
For example, to change the color of the highlighted line number for the line that
contains the cursor, you could add the following style to _user.css_:
contains the cursor, you could add the following style to _user.less_:
```less
@highlight-color: pink;
```css
.editor .line-number.cursor-line {
color: pink;
color: @highlight-color;
}
```
+47 -216
Ver Arquivo
@@ -1,63 +1,46 @@
{{{
"title": "Getting Started"
}}}
# Getting Started
Welcome to Atom. This documentation provides a basic introduction to being
productive with this editor. We'll then delve into more details about configuring,
theming, and extending Atom.
Welcome to Atom! This guide provides a quick introduction so you can be
productive as quickly as possible. There are also guides which cover
[configuring][configuring], [theming][theming], and [extending][extending] Atom.
## The Command Palette
If there's one key-command you must remember in Atom, it should be `meta-p` (`meta` is
synonymous with the ⌘ key). You can always hit `meta-p` to bring up a list of
commands that are relevant to the currently focused UI element. If there is a
key binding for a given command, it is also displayed. This is a great way to
explore the system and get to know the key commands interactively. If you'd like
to learn about adding or changing a binding for a command, refer to the [key
bindings](#customizing-key-bindings) section.
If there's one key-command you must remember in Atom, it should be `cmd-p`. You
can always hit `cmd-p` to bring up a list of commands that are relevant to the
currently focused UI element. If there is a key binding for a given command, it
is also displayed. This is a great way to explore the system and get to know the
key commands interactively. If you'd like to learn about adding or changing a
binding for a command, refer to the [key bindings](#customizing-key-bindings)
section below.
![Command Palette](http://f.cl.ly/items/32041o3w471F3C0F0V2O/Screen%20Shot%202013-02-13%20at%207.27.41%20PM.png)
## Basic Key Bindings
You can always use `meta-p` to explore available commands and their
bindings, but here's a list of a few useful commands.
- `meta-o` : open a file or directory
- `meta-shift-n` : open new window
- `meta-r` : reload the current window
- `meta-alt-ctrl-s` : run test specs
- `meta-t` : open file finder to navigate files in your project
- `meta-;` : open command prompt
- `meta-f` : open command prompt with `/` for a local file search
- `meta-g` : repeat the last local search
- `meta-shift-f` : open command prompt with `Xx/` for a project-wide search
- `meta-\` : focus/open tree view, or close it when it is focused
- `meta-|` : open tree view with the current file selected
- `ctrl-w v`, `ctrl-|` : split screen vertically
- `ctrl-w s`, `ctrl--` : split screen horizontally
- `meta-l` : go to line
## Usage Basics
### If You See A Rendering Bug
Things are pretty stable, but we think we have a couple rendering bugs lurking
that are hard to reproduce. If you see one, please hit `meta-p` and type
"save debug snapshot". Run that command to save a snapshot of the misbehaving
editor and send it to us, along with a screenshot and your best description of
how you produced the bug. Refreshing with `meta-r` should usually resolve the
issue so you can keep working.
## The Basics
### Working With Files
Atom windows are scoped to the directory in which they're opened from. So if
you launch Atom from the command line, everything will be relative to the
current directory. This means that the tree view on the left will only show files
contained within that directory.
This can be a useful way to organize multiple projects, as each project will be
contained within it's own window and it's state will be unique to that window.
#### Finding Files
The fastest way to find a file in your project is to use the fuzzy finder. Just
hit `meta-t` and start typing the name of the file you're looking for. If you
already have the file open as a tab and want to jump to it, hit `meta-b` to bring
hit `cmd-t` and start typing the name of the file you're looking for. If you
already have the file open as a tab and want to jump to it, hit `cmd-b` to bring
up a searchable list of open buffers.
You can also use the tree view to navigate to a file. To open or move focus to
the tree view, hit `meta-\`. You can then navigate to a file and select it with
the tree view, hit `cmd-\`. You can then navigate to a file and select it with
`return`.
#### Adding, Moving, Deleting Files
@@ -70,49 +53,21 @@ needed.
To move or rename a file or directory, select it in the tree view and hit `m`.
To delete a file, select it in the tree view and hit `delete`.
### Searching For Stuff
### Searching
#### Using the Command Line
#### Find and Replace
Atom has a command line similar to old-school editors such as emacs and vim. Nearly
every command has a key binding which you can discover with `meta-p`.
The command line is also (currently) the only place you can perform a search. Hitting
`meta-f` opens the command line and prepopulates it with the `/` command. This finds
text in the current buffer, starting at the location of the cursor. Pressing `meta-g`
repeats the search. Hitting `meta-shift-f` opens the command line and prepopulates
it with `Xx/`, which is a composite command that performs a global search. The results
of the search appear in the operation preview list, which you can focus
with `meta-:`.
Atom's command language is still under construction, and is loosely based on
the [Sam editor](http://doc.cat-v.org/bell_labs/sam_lang_tutorial/) from the
Plan 9 operating system. It's similar to Ex mode in vim, but is selection-based
rather than line-based. It allows you to compose commands together in
interesting ways.
FIXME: Describe https://github.com/atom/find-and-replace
#### Navigating By Symbols
If you want to jump to a method, you can use the ctags-based symbols package.
The `meta-j` binding opens a list of all symbols in the current file. The
`meta-shift-j` binding opens a list of all symbols for the current project
based on a tags file. `meta-.` jumps to the tag for the word currently
under the cursor.
If you want to jump to a method, the `cmd-j` binding opens a list of all symbols
in the current file. `cmd-.` jumps to the tag for the word currently under the cursor.
Make sure you have a tags file generated for the project for
the latter of these two bindings to work. Also, if you're editing CoffeeScript,
it's a good idea to update your `~/.ctags` file to understand the language. Here
is [a good example](https://github.com/kevinsawicki/dotfiles/blob/master/.ctags).
### Replacing Stuff
To perform a replacement, open up the command line with `meta-;` and use the `s`
command, as follows: `s/foo/bar/g`. Note that if you have a selection, the
replacement will only occur inside the selected text. An empty selection will
cause the replacement to occur across the whole buffer. If you want to run the
command on the whole buffer even if you have a selection, precede your
substitution with the `,` address; this indicates that the following command should
run on the whole buffer.
To search for symbols across your project use `cmd-shift-j`, but you'll need to
make sure you have a tags file generated for the project Also, if you're editing
CoffeeScript, it's a good idea to update your `~/.ctags` file to understand the
language. Here is [a good example](https://github.com/kevinsawicki/dotfiles/blob/master/.ctags).
### Split Panes
@@ -130,148 +85,24 @@ planning to improve it soon.
### Soft-Wrap
If you want to toggle soft wrap, trigger the command from the command palette.
Hit `meta-p` to open the palette, then type "wrap" to find the correct
Hit `cmd-p` to open the palette, then type "wrap" to find the correct
command.
## Your .atom Directory
## Configuration
When you install Atom, an `.atom` directory is created in your home directory.
If you press `meta-,`, that directory will be opened in a new window. For the
time being, this will serve as the primary interface for adjusting configuration
If you press `cmd-,`, a configuration panel will appear in the currently focused
pane. This will serve as the primary interface for adjusting configuration
settings, adding and changing key bindings, tweaking styles, etc.
## Configuration Settings
For more advanced configuration see the [customization guide][customization].
Atom loads configuration settings from the `config.cson` file in your `~/.atom`
directory, which contains CoffeeScript-style JSON:
## Installing Packages
```coffeescript
'editor':
'fontSize': 16
'core':
'themes': [
'atom-dark-ui'
'atom-dark-syntax'
]
```
To install a package, open the configuration panel and select the packages tab.
Configuration is broken into namespaces, which are defined by the config hash's
top-level keys. In addition to Atom's core components, each package may define
its own namespace.
FIXME: Needs more details.
### Glossary of Config Keys
- core
- disabledPackages: An array of package names to disable
- hideGitIgnoredFiles: Whether files in the .gitignore should be hidden
- ignoredNames: File names to ignore across all of atom (not fully implemented)
- themes: An array of theme names to load, in cascading order
- autosave: Save a resource when its view loses focus
- editor
- autoIndent: Enable/disable basic auto-indent (defaults to true)
- autoIndentOnPaste: Enable/disable auto-indented pasted text (defaults to false)
- nonWordCharacters: A string of non-word characters to define word boundaries
- fontSize
- fontFamily
- invisibles: Specify characters that Atom renders for invisibles in this hash
- tab: Hard tab characters
- cr: Carriage return (For Microsoft-style line endings)
- eol: `\n` characters
- space: Leading and trailing space characters
- preferredLineLength: Packages such as autoflow use this (defaults to 80)
- showInvisibles: Whether to render placeholders for invisible characters (defaults to false)
- fuzzyFinder
- ignoredNames: Files to ignore *only* in the fuzzy-finder
- whitespace
- ensureSingleTrailingNewline: Whether to reduce multiple newlines to one at the end of files
- wrapGuide
- columns: Array of hashes with a `pattern` and `column` key to match the
the path of the current editor to a column position.
## Customizing Key Bindings
Atom keymaps work similarly to stylesheets. Just as stylesheets use selectors
to apply styles to elements, Atom keymaps use selectors to associate keystrokes
with events in specific contexts. Here's a small example, excerpted from Atom's
built-in keymaps:
```coffeescript
'.editor':
'enter': 'editor:newline'
'.select-list .editor.mini':
'enter': 'core:confirm'
```
This keymap defines the meaning of `enter` in two different contexts. In a
normal editor, pressing `enter` emits the `editor:newline` event, which causes
the editor to insert a newline. But if the same keystroke occurs inside of a
select list's mini-editor, it instead emits the `core:confirm` event based on
the binding in the more-specific selector.
By default, any keymap files in your `~/.atom/keymaps` directory will be loaded
in alphabetical order when Atom is started. They will always be loaded last,
giving you the chance to override bindings that are defined by Atom's core
keymaps or third-party packages.
## Changing The Theme
Atom comes bundles with two themes `atom-dark-*` and `atom-light-*`.
Because Atom themes are based on CSS, it's possible to have multiple themes
active at the same time. For example, you'll usually select a theme for the UI
and another theme for syntax highlighting. You can select themes by specifying
them in the `core.themes` array in your `config.cson`:
```coffeescript
core:
themes: ["atom-light-ui", "atom-light-syntax"]
# or, if the sun is going down:
# themes: ["atom-dark-ui", "atom-dark-syntax"]
```
You install new themes by placing them in the `~/.atom/themes` directory. A
theme can be a CSS file, a directory containing multiple CSS files, or a
TextMate theme (either `.tmTheme` or `.plist`).
## Installing Packages (Partially Implemented)
To install a package, clone it into the `~/.atom/packages` directory. Atom will
also load grammars and snippets from TextMate bundles. If you want to disable a
package without removing it from the packages directory, insert its name into
`config.core.disabledPackages`:
config.cson:
```coffeescript
core:
disabledPackages: [
"fuzzy-finder",
"tree-view"
]
```
## Quick Personal Hacks
### user.coffee
When Atom finishes loading, it will evaluate `user.coffee` in your `~/.atom`
directory, giving you a chance to run arbitrary personal CoffeeScript code to
make customizations. You have full access to Atom's API from code in this file.
Please refer to the Atom Internals Guide for more information. If your
customizations become extensive, consider creating a package.
### user.css
If you want to apply quick-and-dirty personal styling changes without creating
an entire theme that you intend to distribute, you can add styles to
`user.css` in your `~/.atom` directory.
For example to change the color of the highlighted line number for the line that
contains the cursor, you could add the following style to `user.css`:
```css
.editor .line-number.cursor-line {
color: pink;
}
```
[configuring]: customizing-atom.html
[theming]: creating-a-theme.html
[extending]: creating-a-package.html
[customization]: customizing-atom.html
+16
Ver Arquivo
@@ -0,0 +1,16 @@
{{{
"title": "Guides"
}}}
## Guides
* [Getting Started](getting-started.html)
* [Customizing Atom](customizing-atom.html)
* [Creating a Package](creating-a-package.html)
* [Creating a Theme](creating-a-theme.html)
### Advanced Topics
* [Configuration](internals/configuration.html)
* [Keymaps](internals/keymaps.html)
* [Serialization](internals/serialization.html)
* [View System](internals/view-system.html)
-6
Ver Arquivo
@@ -1,6 +0,0 @@
# Atom Internals
To extend Atom effectively, you'll need to understand how it works internally.
This system is evolving fast and it's unlikely that these docs will cover all
of it any time soon, so view this as a jumping-off point. To really understand
how things work, use the web inspector or dive into the code.
+3 -3
Ver Arquivo
@@ -15,7 +15,7 @@ Note that the last example describes multiple keystrokes in succession:
- `p`
- `2`
- `ctrl-p`
- `ctrl-alt-meta-p`
- `ctrl-alt-cmd-p`
- `tab`
- `escape`
- `enter`
@@ -23,12 +23,12 @@ Note that the last example describes multiple keystrokes in succession:
A semantic event is the name of the custom event that will be triggered on the
target of the keydown event when a key binding matches. You can use the command
palette (bound to `meta-p`), to get a list of relevant events and their bindings
palette (bound to `cmd-p`), to get a list of relevant events and their bindings
in any focused context in Atom.
### Rules for Mapping A Keydown Event to A Semantic Event
A keymap's job is to translate a physical keystroke event (like `meta-D`) into a
A keymap's job is to translate a physical keystroke event (like `cmd-D`) into a
semantic event (like `editor:duplicate-line`). Whenever a keydown event occurs
on a focused element, it bubbles up the DOM as usual. As soon as an element on
the bubble path matches a key binding for the keystroke, the binding's semantic
+2 -2
Ver Arquivo
@@ -33,10 +33,10 @@ for more details.
### RootView
The root of Atom's view hiererchy is a global called `rootView`, which is a
The root of Atom's view hierarchy is a global called `rootView`, which is a
singleton instance of the `RootView` view class. The root view fills the entire
window, and contains every other view. If you open Atom's inspector with
`alt-meta-i`, you can see the internal structure of `RootView`:
`alt-cmd-i`, you can see the internal structure of `RootView`:
![RootView in the inspector](http://f.cl.ly/items/2n0s3m0I2d223p3s3W01/root-view-inspector.png)
-15
Ver Arquivo
@@ -1,15 +0,0 @@
getting-started.md
configuring-atom.md
built-in-packages/intro.md
built-in-packages/command-panel.md
built-in-packages/markdown-preview.md
built-in-packages/wrap-guide.md
packages/authoring-packages.md
packages/creating_a_package.md
packages/included_libraries.md
packages/package_json.md
themes/authoring-themes.md
internals/intro.md
internals/configuration.md
internals/keymaps.md
internals/view-system.md
-211
Ver Arquivo
@@ -1,211 +0,0 @@
# Authoring Packages
Packages are at the core of Atom. Nearly everything outside of the main editor manipulation
is handled by a package. That includes "core" pieces like the command panel, status bar,
file tree, and more.
A package can contain a variety of different resource types to change Atom's
behavior. The basic package layout is as follows (though not every package will
have all of these directories):
```text
my-package/
lib/
stylesheets/
keymaps/
snippets/
grammars/
spec/
package.json
index.coffee
```
**NOTE:** NPM behavior is partially implemented until we get a working Node.js
API built into Atom. The goal is to make Atom packages be a superset of NPM
packages.
Below, we'll break down each directory. There's also [a tutorial](./creating_a_package.md)
on creating your first package.
## package.json
Similar to [npm packages](http://en.wikipedia.org/wiki/Npm_(software\)), Atom packages
can contain a _package.json_ file in their top-level directory. This file contains metadata
about the package, such as the path to its "main" module, library dependencies,
and manifests specifying the order in which its resources should be loaded.
In addition to the regular [npm package.json keys](https://npmjs.org/doc/json.html)
available, Atom package.json files [have their own additions](./package_json.md).
## Source Code
If you want to extend Atom's behavior, your package should contain a single
top-level module, which you export from _index.coffee_ (or whichever file is
indicated by the `main` key in your _package.json_ file). The remainder of your
code should be placed in the `lib` directory, and required from your top-level
file.
Your package's top-level module is a singleton object that manages the lifecycle
of your extensions to Atom. Even if your package creates ten different views and
appends them to different parts of the DOM, it's all managed from your top-level
object.
Your package's top-level module should implement the following methods:
- `activate(rootView, state)`: This **required** method is called when your
package is loaded. It is always passed the window's global `rootView`, and is
sometimes passed state data if the window has been reloaded and your module
implements the `serialize` method. Use this to do initialization work when your
package is started (like setting up DOM elements or binding events).
- `serialize()`: This **optional** method is called when the window is shutting
down, allowing you to return JSON to represent the state of your component. When
the window is later restored, the data you returned is passed to your
module's `activate` method so you can restore your view to where the user left
off.
- `deactivate()`: This **optional** method is called when the window is shutting
down. If your package is watching any files or holding external resources in any
other way, release them here. If you're just subscribing to things on window,
you don't need to worry because that's getting torn down anyway.
### Simple Package Code
```text
my-package/
package.json # optional
index.coffee
lib/
my-package.coffee
```
`index.coffee`:
```coffeescript
module.exports = require "./lib/my-package"
```
`my-package/my-package.coffee`:
```coffeescript
module.exports =
activate: (rootView, state) -> # ...
deactivate: -> # ...
serialize: -> # ...
```
Beyond this simple contract, your package has full access to Atom's internal
API. Anything we call internally, you can call as well. Be aware that since we
are early in development, APIs are subject to change and we have not yet
established clear boundaries between what is public and what is private. Also,
please collaborate with us if you need an API that doesn't exist. Our goal is
to build out Atom's API organically based on the needs of package authors like
you.
See [Atom's built-in packages](https://github.com/github/atom/tree/master/src/packages)
for examples of Atom's API in action.
## Stylesheets
Stylesheets for your package should be placed in the _stylesheets_ directory.
Any stylesheets in this directory will be loaded and attached to the DOM when
your package is activated. Stylesheets can be written as CSS or LESS.
An optional `stylesheets` array in your _package.json_ can list the stylesheets by
name to specify a loading order; otherwise, stylesheets are loaded alphabetically.
## Keymaps
Keymaps are placed in the _keymaps_ subdirectory. It's a good idea to provide
default keymaps for your extension, especially if you're also adding a new command.
By default, all keymaps are loaded in alphabetical order. An optional `keymaps`
array in your _package.json_ can specify which keymaps to load and in what order.
See the [main keymaps documentation](../internals/keymaps.md) for more information on
how keymaps work.
## Snippets
An extension can supply language snippets in the _snippets_ directory. These can
be `.cson` or `.json` files. Here's an example:
```coffeescript
".source.coffee .specs":
"Expect":
prefix: "ex"
body: "expect($1).to$2"
"Describe":
prefix: "de"
body: """
describe "${1:description}", ->
${2:body}
"""
```
A snippets file contains scope selectors at its top level (`.source.coffee .spec`).
Each scope selector contains a hash of snippets keyed by their name (`Expect`, `Describe`).
Each snippet also specifies a `prefix` and a `body` key. The `prefix` represents
the first few letters to type before hitting the `tab` key to autocomplete. The
`body` defines the autofilled text. You can use placeholders like `$1`, `$2`, to indicate
regions in the body the user can navigate to every time they hit `tab`.
All files in the directory are automatically loaded, unless the
_package.json_ supplies a `snippets` key. As with all scoped
items, snippets loaded later take precedence over earlier snippets when two
snippets match a scope with the same specificity.
## Language Grammars
If you're developing a new language grammar, you'll want to place your file in
the _grammars_ directory. Each grammar is a pairing of two keys, `match` and
`captures`. `match` is a regular expression identifying the pattern to highlight,
while `captures` is a JSON representing what to do with each matching group.
For example:
```json
{
'match': '(?:^|\\s)(__[^_]+__)'
'captures':
'1': 'name': 'markup.bold.gfm'
}
```
This indicates that the first matching capture (`(__[^_]+__)`) should have the
`markup.bold.gfm` token applied to it.
To capture a single group, simply use the `name` key instead:
```json
{
'match': '^#{1,6}\\s+.+$'
'name': 'markup.heading.gfm'
}
```
This indicates that Markdown header lines (`#`, `##`, `###`) should be applied with
the `markup.heading.gfm` token.
More information about the significance of these tokens can be found in
[section 12.4 of the TextMate Manual](http://manual.macromates.com/en/language_grammars.html).
Your grammar should also include a `filetypes` array, which is a list of file extensions
your grammar supports:
```
'fileTypes': [
'markdown'
'md'
'mkd'
'mkdown'
'ron'
]
```
## Writing Tests
Your package **should** have tests, and if they're placed in the _spec_ directory,
they can be run by Atom.
Under the hood, [Jasmine](https://github.com/pivotal/jasmine) is being used to run
to execute the tests, so you can assume that any DSL available there is available
to your package as well.
-254
Ver Arquivo
@@ -1,254 +0,0 @@
# Creating Packages
Let's take a look at creating our first package.
Atom has a command you can enter that'll create a package for you:
`package-generator:generate`. Otherwise, you can hit `meta-p`, and start typing
"Package Generator." Once you activate this package, it'll ask you for a name for
your new package. Let's call ours _changer_.
Now, _changer_ is going to have a default set of folders and files created for us.
Hit `meta-R` to reload Atom, then hit `meta-p` and start typing "Changer." You'll
see a new `Changer:Toggle` command which, if selected, pops up a new message. So
far, so good!
In order to demonstrate the capabilities of Atom and its API, our Changer plugin
is going to do two things:
1. It'll show only modified files in the file tree
2. It'll append a new pane to the editor with some information about the modified
files
Let's get started!
## Changing Keybindings and Commands
Since Changer is primarily concerned with the file tree, let's write a keybinding
that works only when the tree is focused. Instead of using the default `toggle`,
our keybinding executes a new command called `magic`.
_keymaps/changer.cson_ can easily become this:
```cson
'.tree-view-scroller':
'ctrl-V': 'changer:magic'
```
Notice that the keybinding is called `ctrl-V`--that's actually `ctrl-shift-v`.
You can use capital letters to denote using `shift` for your binding.
`.tree-view-scroller` represents the parent container for the tree view. Keybindings
only work within the context of where they're entered. For example, hitting `ctrl-V`
anywhere other than tree won't do anything. You can map to `body` if you want
to scope to anywhere in Atom, or just `.editor` for the editor portion.
To bind keybindings to a command, we'll use the `rootView.command` method. This
takes a command name and executes a function in the code. For example:
```coffeescript
rootView.command "changer:magic", => @magic()
```
It's common practice to namespace your commands with your package name, and separate
it with a colon (`:`). Rename the existing `toggle` method to `magic` to get the
binding to work.
Reload the editor, click on the tree, hit your keybinding, and...nothing happens! What the heck?!
Open up the _package.json_ file, and notice the key that says `activationEvents`.
Basically, this tells Atom to not load a package until it hears a certain event.
Let's change the event to `changer:magic` and reload the editor.
Hitting the key binding on the tree now works!
## Working with styles
The next step is to hide elements in the tree that aren't modified. To do that,
we'll first try and get a list of files that have not changed.
All packages are able to use jQuery in their code. In fact, we have [a list of
some of the bundled libraries Atom provides by default](./included_libraries.md).
Let's bring in jQuery:
```coffeescript
$ = require 'jquery'
```
Now, we can query the tree to get us a list of every file that _wasn't_ modified:
```coffeescript
magic: ->
$('ol.entries li').each (i, el) ->
if !$(el).hasClass("modified")
console.log el
```
You can access the dev console by hitting `alt-meta-i`. When we execute the
`changer:magic` command, the browser console lists the items that are not being
modified. Let's add a class to each of these elements called `hide-me`:
```coffeescript
magic: ->
$('ol.entries li').each (i, el) ->
if !$(el).hasClass("modified")
$(el).addClass("hide-me")
```
With our newly added class, we can manipulate the visibility of the elements
with a simple stylesheet. Open up _changer.css_ in the _stylesheets_ directory,
and add a single entry:
```css
ol.entries .hide-me {
display: none;
}
```
Refresh atom, and run the `changer` command. You'll see all the non-changed files
disappear from the tree. There are a number of ways you can get the list back;
let's just naively iterate over the same elements and remove the class:
```coffeescript
magic: ->
$('ol.entries li').each (i, el) ->
if !$(el).hasClass("modified")
if !$(el).hasClass("hide-me")
$(el).addClass("hide-me")
else
$(el).removeClass("hide-me")
```
## Creating a New Pane
The next goal of this package is to append a pane to the Atom editor that lists
some information about the modified files.
To do that, we're going to first create a new class method called `content`. Every
package that extends from the `View` class can provide an optional class method
called `content`. The `content` method constructs the DOM that your package uses
as its UI. The principals of `content` are built entirely on [SpacePen](https://github.com/nathansobo/space-pen),
which we'll touch upon only briefly here.
Our display will simply be an unordered list of the file names, and their
modified times. Let's start by carving out a `div` to hold the filenames:
```coffeescript
@content: ->
@div class: 'modified-files-container', =>
@ul class: 'modified-files-list', outlet: 'modifiedFilesList', =>
@li 'Test'
@li 'Test2'
```
You can add any HTML5 attribute you like. `outlet` names the variable
your package can uses to manipulate the element directly. The fat pipe (`=>`) indicates
that the next set are nested children.
We'll add one more line to `magic` to make this pane appear:
```coffeescript
rootView.vertical.append(this)
```
If you hit the key command, you'll see a box appear right underneath the editor.
Success!
Before we populate this, let's apply some logic to toggle the pane off and on, just
like we did with the tree view:
```coffeescript
# toggles the pane
if @hasParent()
rootView.vertical.children().last().remove()
else
rootView.vertical.append(this)
```
There are about a hundred different ways to toggle a pane on and off, and this
might not be the most efficient one. If you know your package needs to be toggled
on and off more freely, it might be better to draw the UI during the initialization,
then immediately call `hide()` on the element to remove it from the view. You can
then swap between `show()` and `hide()`, and instead of forcing Atom to add and remove
the element as we're doing here, it'll just set a CSS property to control your package's
visibility.
You might have noticed that our two `li` elements aren't showing up. Let's set
a color on them so that they pop. Open up `changer.css` and add this CSS:
```css
ul.modified-files-list {
color: white;
}
```
Refresh Atom, hit the key combo, and see your brilliantly white test list.
## Calling Node.js Code
Since Atom is built on top of Node.js, you can call any of its libraries, including
other modules that your package requires.
We'll iterate through our resulting tree, and construct the path to our modified
file based on its depth in the tree:
```coffeescript
path = require 'path'
# ...
modifiedFiles = []
# for each single entry...
$('ol.entries li.file.modified span.name').each (i, el) ->
filePath = []
# ...grab its name...
filePath.unshift($(el).text())
# ... then find its parent directories, and grab their names
parents = $(el).parents('.directory.modified')
parents.each (i, el) ->
filePath.unshift($(el).find('div.header span.name').eq(0).text())
modifiedFilePath = path.join(project.rootDirectory.path, filePath.join(path.sep))
modifiedFiles.push modifiedFilePath
```
`modifiedFiles` is an array containing a list of our modified files. We're also using
the node.js [`path` library](http://nodejs.org/docs/latest/api/path.html) to get
the proper directory separator for our system.
Let's remove the two `@li` elements we added in `@content`, so that we can populate
our `modifiedFilesList` with real information. We'll do that by iterating over
`modifiedFiles`, accessing a file's last modified time, and appending it to
`modifiedFilesList`:
```coffeescript
# toggles the pane
if @hasParent()
rootView.vertical.children().last().remove()
else
for file in modifiedFiles
stat = fs.lstatSync(file)
mtime = stat.mtime
@modifiedFilesList.append("<li>#{file} - Modified at #{mtime}")
rootView.vertical.append(this)
```
When you toggle the modified files list, your pane is now populated with the filenames
and modified times of files in your project. You might notice that subsequent calls
to this command reduplicate information. We could provide an elegant way of rechecking
files already in the list, but for this demonstration, we'll just clear the `modifiedFilesList`
each time it's closed:
```coffeescript
# toggles the pane
if @hasParent()
@modifiedFilesList.empty()
rootView.vertical.children().last().remove()
else
for file in modifiedFiles
stat = fs.lstatSync(file)
mtime = stat.mtime
@modifiedFilesList.append("<li>#{file} - Modified at #{mtime}")
rootView.vertical.append(this)
```
-10
Ver Arquivo
@@ -1,10 +0,0 @@
# Included Libraries
In addition to core node.js modules, all packages can `require` the following popular
libraries into their packages:
* [SpacePen](https://github.com/nathansobo/space-pen) (as `require 'space-pen'`)
* [jQuery](http://jquery.com/) (as `require 'jquery'`)
* [Underscore](http://underscorejs.org/) (as `require 'underscore'`)
Additional libraries can be found by browsing Atom's _node_modules_ folder.
-18
Ver Arquivo
@@ -1,18 +0,0 @@
# package.json format
The following keys are available to your package's _package.json_ manifest file:
- `main` (**Required**): the path to the CoffeeScript file that's the entry point
to your package
- `stylesheets` (**Optional**): an Array of Strings identifying the order of the
stylesheets your package needs to load. If not specified, stylesheets in the _stylesheets_
directory are added alphabetically.
- `keymaps`(**Optional**): an Array of Strings identifying the order of the
key mappings your package needs to load. If not specified, mappings in the _keymaps_
directory are added alphabetically.
- `snippets` (**Optional**): an Array of Strings identifying the order of the
snippets your package needs to load. If not specified, snippets in the _snippets_
directory are added alphabetically.
- `activationEvents` (**Optional**): an Array of Strings identifying events that
trigger your package's activation. You can delay the loading of your package until
one of these events is trigged.
+70
Ver Arquivo
@@ -0,0 +1,70 @@
**Polish the user experience**
First and foremost, Atom is a **product**. Atom needs to feel familiar and
inviting. This includes a solid introductory experience and parity with the most
important features of Sublime Text.
* First launch UI and flow (actions below should be easily discoverable)
* Create a new file
* Open a project and edit an existing file
* Install a package
* Change settings (adjust theme, change key bindings, set config options)
* How to use command P
* Use collaboration internally
* How and where to edit keyBinding should be obvious to new users
* Finish find and replace in buffer/project
* Atom should start < 300ms
* Match Sublime's multiple selection functionality (#523)
* Fix softwrap bugs
* Menus & Context menus
* Track usage/engagement of our users (make this opted in?)
* Windows support
* Reliably and securely auto-update and list what's new
* Secure access to the keychain (don't give every package access to the keychain)
* Secure access to GitHub (each package can ask to have it's own oauth token)
* Don't crash when opening/editing large (> 10Mb) files
* Send js and native crash reports to a remote server
**Lay solid groundwork for a package and theme ecosystem**
Extensibility is one of Atom's key value propositions, so a smooth experience
for creating and maintaining packages is just as important as the user
experience. The package development, dependency and publishing workflow needs to
be solid. We also want to have a mechanism for clearly communicating with
package authors about breaking API changes.
* Finish APM backend (integrate with GitHub Releases)
* Streamline Dev workflow
* `apm create` - create package scaffolding
* `apm test` - so users can run focused package tests
* `apm publish` - should integrate release best practices (ie npm version)
* Determine which classes and methods should be included in the public API
* Users can find/install/update/fork existing packages and themes
**Tighten up the view layer**
Our current approach to the view layer need some improvement. We want to
actively promote the use of the M-V-VM design pattern, provide some declarative
event binding mechanisms in the view layer, and improve the performance of the
typical package specs. We don't want the current approach to be used as an
example in a bunch of new packages, so it's important to improve it now.
* Add marker view API
**Get atom.io online with some exciting articles and documentation**
We'd love to send our private alpha candidates to a nice site with information
about what Atom is, the philosophies and technologies behind it, and guidance
for how to get started.
* Design and create www.atom.io
* Guides
* Theme & Package creation guide
* Full API per release tag
* Changelog per release
* Explanation of features
* Explain Semver and general plans for the future (reassure developers we care about them)
* General Values/Goals
* Make docs accessible from Atom
* Community/contribution guidelines
* Is all communication to be done through issues?
* When should you publish a plugin?
* Do we need to vet plugins from a security perspective?
+16
Ver Arquivo
@@ -0,0 +1,16 @@
## Proposed Timeline
1. **October 30st** - Internal launch - persuade as many githubers to switch as
possible.
1. Triage bugs and identify what needs to be fixed before private alpha. Maybe
talk to @chrissiebrodigan about doing a UX study.
1. **November 22st** - Private alpha launch
1. Trickle out invites as people ask/we need more testers.
1. If our usage metrics/engagement metrics decrease, stop, identify the issue
and fix it before continuing.
1. Launch
+151
Ver Arquivo
@@ -0,0 +1,151 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<link href="//netdna.bootstrapcdn.com/bootstrap/3.0.0/css/bootstrap.min.css" rel="stylesheet">
<link rel="stylesheet" href="//netdna.bootstrapcdn.com/bootstrap/3.0.0/css/bootstrap-theme.min.css">
<!-- HTML5 shim and Respond.js IE8 support of HTML5 elements and media queries -->
<!--[if lt IE 9]>
<script src="../../assets/js/html5shiv.js"></script>
<script src="../../assets/js/respond.min.js"></script>
<![endif]-->
<title>Atom - <%= title %></title>
<style>
/*github.com style (c) Vasily Polovnyov <vast@whiteants.net>*/
pre code {
display: block; padding: 0.5em;
color: #333;
background: #f8f8ff
}
pre .comment,
pre .template_comment,
pre .diff .header,
pre .javadoc {
color: #998;
font-style: italic
}
pre .keyword,
pre .css .rule .keyword,
pre .winutils,
pre .javascript .title,
pre .nginx .title,
pre .subst,
pre .request,
pre .status {
color: #333;
font-weight: bold
}
pre .number,
pre .hexcolor,
pre .ruby .constant {
color: #099;
}
pre .string,
pre .tag .value,
pre .phpdoc,
pre .tex .formula {
color: #d14
}
pre .title,
pre .id {
color: #900;
font-weight: bold
}
pre .javascript .title,
pre .lisp .title,
pre .clojure .title,
pre .subst {
font-weight: normal
}
pre .class .title,
pre .haskell .type,
pre .vhdl .literal,
pre .tex .command {
color: #458;
font-weight: bold
}
pre .tag,
pre .tag .title,
pre .rules .property,
pre .django .tag .keyword {
color: #000080;
font-weight: normal
}
pre .attribute,
pre .variable,
pre .lisp .body {
color: #008080
}
pre .regexp {
color: #009926
}
pre .class {
color: #458;
font-weight: bold
}
pre .symbol,
pre .ruby .symbol .string,
pre .lisp .keyword,
pre .tex .special,
pre .prompt {
color: #990073
}
pre .built_in,
pre .lisp .title,
pre .clojure .built_in {
color: #0086b3
}
pre .preprocessor,
pre .pi,
pre .doctype,
pre .shebang,
pre .cdata {
color: #999;
font-weight: bold
}
pre .deletion {
background: #fdd
}
pre .addition {
background: #dfd
}
pre .diff .change {
background: #0086b3
}
pre .chunk {
color: #aaa
}
body {
padding-top: 50px;
}
</style>
</head>
<body>
<div class="navbar navbar-inverse navbar-fixed-top">
<div class="container">
<div class="navbar-header">
<button type="button" class="navbar-toggle" data-toggle="collapse" data-target=".navbar-collapse">
<span class="icon-bar"></span>
<span class="icon-bar"></span>
<span class="icon-bar"></span>
</button>
<a class="navbar-brand" href="/<%= tag %>/index.html">Atom Documentation</a>
</div>
<div class="collapse navbar-collapse">
<ul class="nav navbar-nav">
<li><a href="/<%= tag %>/index.html">Guides</a></li>
<li><a href="/<%= tag %>/api/index.html">API</a></li>
</ul>
</div><!--/.nav-collapse -->
</div>
</div>
<div class="container">
<%= content %>
</div>
</body>
</html>
-55
Ver Arquivo
@@ -1,55 +0,0 @@
# Authoring Themes
If you understand CSS, you can write an Atom theme easily. Your theme can style
Atom's user interface, specify the appearance of syntax-highlighted code, or
both. For making a syntax highlighting theme, refer to
[section 12.4 of the TextMate Manual](http://manual.macromates.com/en/language_grammars.html)
for a list of the common scopes used by TextMate grammars. You'll just need to
translate scope names to CSS classes. To theme Atom's user interface, take a
look at the existing light and dark themes for an example. Pressing `alt-meta-i`
and inspecting the Atom's markup directly can also be helpful.
The most basic theme is just a _.css_ file. More complex themes occupy their own
folder, which can contain multiple stylesheets along with an optional
_package.cson_ file containing a manifest to control their load-order:
```text
~/.atom/themes/
rockstar.css
rainbow/
package.json
core.css
editor.css
tree-view.css
```
package.cson:
```coffee-script
stylesheets: ["core.css", "editor.less", "tree-view.css"]
```
The `package.cson` file specifies which stylesheets to load and in what order
with the `stylesheets` key. If no manifest is specified, all stylesheets are
loaded in alphabetical order when the user selects the theme.
## Theme Extensions (Not Yet Implemented)
A theme may need to be extended to cover DOM elements that are introduced by a
third-party Atom package. When a package is loaded, stylesheets with the same
name as the package will automatically be loaded from the `packages` directory
of active themes:
```text
~/.atom/themes/
midnight/midnight.less
midnight/packages/terminal.less
midnight/packages/tree-view.less
```
In the example above, if the `midnight` theme is active, its `terminal` and
`tree-view` stylesheets will be loaded automatically if and when those packages
are activated. If you author an extension to a theme consider sending its author
a pull request to have it included in the theme by default. Package-specific
theme stylesheets need not be listed in the theme's `package.json` because they
will be loaded automatically when the package is loaded.
@@ -17,3 +17,5 @@
'meta-backspace': 'editor:backspace-to-beginning-of-line'
'alt-delete': 'editor:delete-to-end-of-word'
'ctrl-t': 'editor:transpose'
'ctrl-A': 'editor:select-to-first-character-of-line'
'ctrl-E': 'editor:select-to-end-of-line'
+15 -9
Ver Arquivo
@@ -1,4 +1,16 @@
'body':
'meta-q': 'application:quit'
'meta-h': 'application:hide'
'meta-H': 'application:hide-other-applications'
'meta-n': 'application:new-file'
'meta-N': 'application:new-window'
'meta-o': 'application:open'
'meta-O': 'application:open-dev'
'meta-m': 'application:minimize'
'meta-,': 'application:show-settings'
'alt-meta-ctrl-m': 'application:zoom'
'meta-alt-ctrl-s': 'application:run-all-specs'
'meta-s': 'core:save'
'meta-S': 'core:save-as'
'enter': 'core:confirm'
@@ -26,12 +38,14 @@
'meta-alt-s': 'window:save-all'
'meta-W': 'window:close'
'meta-r': 'window:reload'
'meta-+': 'window:increase-font-size'
'meta--': 'window:decrease-font-size'
'ctrl-w w': 'window:focus-next-pane'
'ctrl-tab': 'window:focus-next-pane'
'ctrl-meta-f': 'window:toggle-full-screen'
'meta-r': 'window:reload'
'alt-meta-i': 'window:toggle-dev-tools'
'meta-alt-ctrl-p': 'window:run-package-specs'
'ctrl-|': 'pane:split-right'
'ctrl-w v': 'pane:split-right'
@@ -55,14 +69,6 @@
'alt-meta-w': 'pane:close-other-items'
'meta-P': 'pane:close'
'meta-n': 'new-editor'
'meta-N': 'new-window'
'meta-,': 'open-user-configuration'
'meta-o': 'open'
'meta-O': 'open-dev'
'meta-w': 'core:close'
'alt-meta-i': 'toggle-dev-tools'
'.tool-panel':
'meta-escape': 'tool-panel:unfocus'
'escape': 'core:close'
+4
Ver Arquivo
@@ -0,0 +1,4 @@
'.select-list .mini.editor':
'enter': 'core:confirm'
'escape': 'core:cancel'
'meta-w': 'core:cancel'
+73 -35
Ver Arquivo
@@ -1,41 +1,74 @@
{
"name": "atom",
"version": "0.0.0",
"version": "21.0.0",
"main": "./src/main.js",
"repository": {
"type": "git",
"url": "https://github.com/github/atom.git"
"url": "https://github.com/atom/atom.git"
},
"bugs": {
"url": "https://github.com/atom/atom/issues"
},
"dependencies": {
"coffee-script": "1.6.2",
"ctags": "0.5.0",
"oniguruma": "0.16.0",
"mkdirp": "0.3.5",
"git-utils": "0.19.0",
"underscore": "1.4.4",
"d3": "3.0.8",
"coffee-cache": "0.1.0",
"pegjs": "0.7.0",
"async": "0.2.6",
"nak": "0.2.16",
"spellchecker": "0.6.0",
"pathwatcher": "0.5.0",
"keytar": "0.9.0",
"ls-archive": "0.9.0",
"temp": "0.5.0",
"rimraf": "2.1.4",
"plist": "git://github.com/nathansobo/node-plist.git",
"space-pen": "1.2.0",
"less": "git://github.com/nathansobo/less.js.git",
"roaster": "0.0.7",
"jqueryui-browser": "1.10.2-1",
"optimist": "0.4.0",
"season": "0.10.0",
"humanize-plus": "1.1.0",
"semver": "1.1.4",
"guid": "0.0.10",
"tantamount": "0.3.0",
"coffee-cache": "0.1.0",
"coffee-script": "1.6.2",
"coffeestack": "0.4.0",
"first-mate": "0.1.0",
"git-utils": "0.24.0",
"guid": "0.0.10",
"mkdirp": "0.3.5",
"less": "git://github.com/nathansobo/less.js.git",
"nak": "0.2.16",
"nslog": "0.1.0",
"oniguruma": "0.16.0",
"optimist": "0.4.0",
"pathwatcher": "0.5.0",
"patrick": "0.4.0",
"pegjs": "0.7.0",
"plist": "git://github.com/nathansobo/node-plist.git",
"rimraf": "2.1.4",
"season": "0.10.0",
"semver": "1.1.4",
"space-pen": "1.2.0",
"tantamount": "0.3.0",
"telepath": "0.1.2",
"temp": "0.5.0",
"underscore": "1.4.4",
"archive-view": "0.3.0",
"autocomplete": "0.4.0",
"autoflow": "0.1.0",
"bookmarks": "0.2.0",
"bracket-matcher": "0.3.0",
"collaboration": "0.8.0",
"command-logger": "0.2.0",
"command-panel": "0.2.0",
"command-palette": "0.1.0",
"fuzzy-finder": "0.3.0",
"editor-stats": "0.1.0",
"gfm": "0.2.0",
"git-diff": "0.2.0",
"gists": "0.1.0",
"github-sign-in": "0.1.0",
"go-to-line": "0.2.0",
"grammar-selector": "0.2.0",
"image-view": "0.3.0",
"link": "0.1.0",
"markdown-preview": "0.1.0",
"package-generator": "0.2.0",
"settings-view": "0.8.0",
"snippets": "0.2.0",
"spell-check": "0.3.0",
"status-bar": "0.3.0",
"symbols-view": "0.4.0",
"tabs": "0.1.0",
"terminal": "0.6.0",
"toml": "0.1.0",
"tree-view": "0.2.0",
"whitespace": "0.1.0",
"wrap-guide": "0.1.0",
"c-tmbundle": "1.0.0",
"coffee-script-tmbundle": "4.0.0",
"css-tmbundle": "1.0.0",
@@ -66,11 +99,10 @@
"textmate-clojure": "1.0.0",
"todo-tmbundle": "1.0.0",
"xml-tmbundle": "1.0.0",
"yaml-tmbundle": "1.0.0",
"nslog": "0.1.0"
"yaml-tmbundle": "1.0.0"
},
"devDependencies": {
"biscotto": "0.0.12",
"biscotto": "0.0.14",
"grunt": "~0.4.1",
"grunt-cli": "~0.1.9",
"grunt-coffeelint": "0.0.6",
@@ -79,12 +111,18 @@
"grunt-contrib-csslint": "~0.1.2",
"grunt-contrib-coffee": "~0.7.0",
"grunt-contrib-less": "~0.6.4",
"jasmine-focused": "~0.7.0",
"jasmine-focused": "~0.12.0",
"walkdir": "0.0.7",
"js-yaml": "~2.1.0"
"ws": "0.4.27",
"js-yaml": "~2.1.0",
"grunt-markdown": "~0.4.0",
"json-front-matter": "~0.1.3",
"grunt-shell": "~0.3.1",
"jasmine-node": "git://github.com/kevinsawicki/jasmine-node.git#short-stacks"
},
"private": true,
"scripts": {
"preinstall": "true"
"preinstall": "true",
"test": "grunt test"
}
}
+1
Ver Arquivo
@@ -18,4 +18,5 @@ git submodule --quiet update --recursive --init
(cd vendor/apm && npm install .)
npm install --silent vendor/apm
echo ""
./node_modules/.bin/apm install --silent
+1 -1
Ver Arquivo
@@ -5,7 +5,7 @@ cd "$(dirname "${BASH_SOURCE[0]}" )/.."
TARGET=${1:-atom-shell}
DISTURL="https://gh-contractor-zcbenz.s3.amazonaws.com/atom-shell"
CURRENT_VERSION=$(cat "${TARGET}/version" 2>&1)
LATEST_VERSION=ea1f81aa5260fe2d4a844f18e0251278fbadc093 # v0.2.1
LATEST_VERSION=$(curl -fsSkL $DISTURL/version)
if [ -z "${LATEST_VERSION}" ] ; then
echo "Could determine lastest version of atom-shell" >&2
+3
Ver Arquivo
@@ -0,0 +1,3 @@
#!/bin/sh
coffee -c -o /Applications/Atom.app/Contents/Resources/app/src/ src/main.coffee
@@ -1,26 +0,0 @@
{createSite} = require 'telepath'
Editor = require 'editor'
describe "EditSession replication", ->
[editSession1, editSession2] = []
beforeEach ->
editSession1 = project.open('sample.js')
doc1 = editSession1.getState()
doc2 = doc1.clone(createSite(2))
doc1.connect(doc2)
editSession2 = deserialize(doc2)
it "replicates the scroll position", ->
editor1 = new Editor(editSession1)
editor2 = new Editor(editSession2)
editor1.attachToDom().width(50).height(50)
editor2.attachToDom().width(50).height(50)
editor1.scrollTop(10)
expect(editor1.scrollTop()).toBe 10
expect(editor2.scrollTop()).toBe 10
editor2.scrollLeft(20)
expect(editor2.scrollLeft()).toBe 20
expect(editor1.scrollLeft()).toBe 20
-33
Ver Arquivo
@@ -1,33 +0,0 @@
Point = require 'point'
describe "Point", ->
describe ".isEqual(value)", ->
describe "when given value is a Point", ->
it "returns true when the rows and columns match", ->
expect(new Point(1,2)).toEqual new Point(1,2)
expect(new Point(2,1)).not.toEqual new Point(1,2)
describe "when given value is an Array", ->
it "returns true only when index zero matches row and index one matches column", ->
expect(new Point(1,2)).toEqual [1,2]
expect(new Point(2,1)).not.toEqual [1,2]
describe "when one of the points has a row or column that is NaN", ->
it "returns false", ->
expect(new Point(1, 3)).not.toEqual new Point(NaN, 3)
expect(new Point(1, 3)).not.toEqual new Point(1, NaN)
describe "compare", ->
it "returns 1, 0, or -1 based on whether the given point precedes, equals, or follows the receivers location in the buffer", ->
expect(new Point(5, 0).compare(new Point(5, 0))).toBe 0
expect(new Point(5, 0).compare(new Point(6, 0))).toBe -1
expect(new Point(5, 0).compare(new Point(5, 1))).toBe -1
expect(new Point(5, 0).compare(new Point(6, 1))).toBe -1
expect(new Point(5, 5).compare(new Point(4, 1))).toBe 1
expect(new Point(5, 5).compare(new Point(5, 3))).toBe 1
describe ".translate(other)", ->
it "returns a translated point", ->
expect(new Point(1,2).translate([2,4])).toEqual [3,6]
expect(new Point(1,2).translate([-1])).toEqual [0,2]
expect(new Point(1,2).translate([0,-2])).toEqual [1,0]
-47
Ver Arquivo
@@ -1,47 +0,0 @@
Range = require 'range'
Point = require 'point'
describe "Range", ->
describe "constructor", ->
it "ensures that @start <= @end", ->
range1 = new Range(new Point(0, 1), new Point(0, 4))
expect(range1.start).toEqual(row: 0, column: 1)
range2 = new Range(new Point(1, 4), new Point(0, 1))
expect(range2.start).toEqual(row: 0, column: 1)
describe ".isEmpty()", ->
it "returns true if @start equals @end", ->
expect(new Range(new Point(1, 1), new Point(1, 1)).isEmpty()).toBeTruthy()
expect(new Range(new Point(1, 1), new Point(1, 2)).isEmpty()).toBeFalsy()
describe ".intersectsWith(otherRange)", ->
it "returns true if the ranges intersect or share an endpoint", ->
expect(new Range([1, 1], [2, 10]).intersectsWith(new Range([2, 1], [3, 10]))).toBeTruthy()
expect(new Range([2, 1], [3, 10]).intersectsWith(new Range([1, 1], [2, 10]))).toBeTruthy()
expect(new Range([2, 1], [3, 10]).intersectsWith(new Range([2, 5], [3, 1]))).toBeTruthy()
expect(new Range([2, 5], [3, 1]).intersectsWith(new Range([2, 1], [3, 10]))).toBeTruthy()
expect(new Range([2, 5], [3, 1]).intersectsWith(new Range([3, 1], [3, 10]))).toBeTruthy()
expect(new Range([3, 1], [3, 10]).intersectsWith(new Range([2, 5], [3, 1]))).toBeTruthy()
expect(new Range([2, 5], [3, 1]).intersectsWith(new Range([3, 2], [3, 10]))).toBeFalsy()
expect(new Range([3, 2], [3, 10]).intersectsWith(new Range([2, 5], [3, 1]))).toBeFalsy()
describe ".union(otherRange)", ->
it "returns the union of the two ranges", ->
expect(new Range([1, 1], [2, 10]).union(new Range([2, 1], [3, 10]))).toEqual [[1, 1], [3, 10]]
expect(new Range([2, 1], [3, 10]).union(new Range([1, 1], [2, 10]))).toEqual [[1, 1], [3, 10]]
expect(new Range([2, 1], [3, 10]).union(new Range([2, 5], [3, 1]))).toEqual [[2, 1], [3, 10]]
expect(new Range([2, 5], [3, 1]).union(new Range([2, 1], [3, 10]))).toEqual [[2, 1], [3, 10]]
describe ".compare(otherRange)", ->
it "sorts earlier ranges first, and larger ranges first if both ranges start at the same place", ->
expect(new Range([1, 1], [2, 10]).compare(new Range([2, 1], [3, 10]))).toBe -1
expect(new Range([2, 1], [3, 10]).compare(new Range([1, 1], [2, 10]))).toBe 1
expect(new Range([1, 1], [3, 10]).compare(new Range([1, 1], [2, 10]))).toBe -1
expect(new Range([1, 1], [2, 10]).compare(new Range([1, 1], [3, 10]))).toBe 1
expect(new Range([1, 1], [3, 10]).compare(new Range([1, 1], [3, 10]))).toBe 0
describe ".translate(startPoint, endPoint)", ->
it "returns a range translates by the specified start and end points", ->
expect(new Range([1, 1], [2, 10]).translate([1])).toEqual [[2, 1], [3, 10]]
expect(new Range([1, 1], [2, 10]).translate([1,2], [3,4])).toEqual [[2, 3], [5, 14]]
@@ -1,79 +0,0 @@
TextMateScopeSelector = require 'text-mate-scope-selector'
describe "TextMateScopeSelector", ->
describe ".matches(scopes)", ->
it "matches the asterix", ->
expect(new TextMateScopeSelector('*').matches(['a'])).toBeTruthy()
expect(new TextMateScopeSelector('*').matches(['b', 'c'])).toBeTruthy()
expect(new TextMateScopeSelector('a.*.c').matches(['a.b.c'])).toBeTruthy()
expect(new TextMateScopeSelector('a.*.c').matches(['a.b.c.d'])).toBeTruthy()
expect(new TextMateScopeSelector('a.*.c').matches(['a.b.d.c'])).toBeFalsy()
it "matches prefixes", ->
expect(new TextMateScopeSelector('a').matches(['a'])).toBeTruthy()
expect(new TextMateScopeSelector('a').matches(['a.b'])).toBeTruthy()
expect(new TextMateScopeSelector('a.b').matches(['a.b.c'])).toBeTruthy()
expect(new TextMateScopeSelector('a').matches(['abc'])).toBeFalsy()
expect(new TextMateScopeSelector('a.b-c').matches(['a.b-c.d'])).toBeTruthy()
expect(new TextMateScopeSelector('a.b').matches(['a.b-d'])).toBeFalsy()
expect(new TextMateScopeSelector('c++').matches(['c++'])).toBeTruthy()
expect(new TextMateScopeSelector('c++').matches(['c'])).toBeFalsy()
expect(new TextMateScopeSelector('a_b_c').matches(['a_b_c'])).toBeTruthy()
expect(new TextMateScopeSelector('a_b_c').matches(['a_b'])).toBeFalsy()
it "matches filters", ->
expect(new TextMateScopeSelector('R:g').matches(['g'])).toBeTruthy()
it "matches disjunction", ->
expect(new TextMateScopeSelector('a | b').matches(['b'])).toBeTruthy()
expect(new TextMateScopeSelector('a|b|c').matches(['c'])).toBeTruthy()
expect(new TextMateScopeSelector('a|b|c').matches(['d'])).toBeFalsy()
it "matches negation", ->
expect(new TextMateScopeSelector('a - c').matches(['a', 'b'])).toBeTruthy()
expect(new TextMateScopeSelector('a - c').matches(['a'])).toBeTruthy()
expect(new TextMateScopeSelector('-c').matches(['b'])).toBeTruthy()
expect(new TextMateScopeSelector('-c').matches(['c', 'b'])).toBeFalsy()
expect(new TextMateScopeSelector('a-b').matches(['a', 'b'])).toBeFalsy()
expect(new TextMateScopeSelector('a -b').matches(['a', 'b'])).toBeFalsy()
expect(new TextMateScopeSelector('a -c').matches(['a', 'b'])).toBeTruthy()
expect(new TextMateScopeSelector('a-c').matches(['a', 'b'])).toBeFalsy()
it "matches conjunction", ->
expect(new TextMateScopeSelector('a & b').matches(['b', 'a'])).toBeTruthy()
expect(new TextMateScopeSelector('a&b&c').matches(['c'])).toBeFalsy()
expect(new TextMateScopeSelector('a&b&c').matches(['a', 'b', 'd'])).toBeFalsy()
expect(new TextMateScopeSelector('a & -b').matches(['a', 'b', 'd'])).toBeFalsy()
expect(new TextMateScopeSelector('a & -b').matches(['a', 'd'])).toBeTruthy()
it "matches composites", ->
expect(new TextMateScopeSelector('a,b,c').matches(['b', 'c'])).toBeTruthy()
expect(new TextMateScopeSelector('a, b, c').matches(['d', 'e'])).toBeFalsy()
expect(new TextMateScopeSelector('a, b, c').matches(['d', 'c.e'])).toBeTruthy()
expect(new TextMateScopeSelector('a,').matches(['a', 'c'])).toBeTruthy()
expect(new TextMateScopeSelector('a,').matches(['b', 'c'])).toBeFalsy()
it "matches groups", ->
expect(new TextMateScopeSelector('(a,b) | (c, d)').matches(['a'])).toBeTruthy()
expect(new TextMateScopeSelector('(a,b) | (c, d)').matches(['b'])).toBeTruthy()
expect(new TextMateScopeSelector('(a,b) | (c, d)').matches(['c'])).toBeTruthy()
expect(new TextMateScopeSelector('(a,b) | (c, d)').matches(['d'])).toBeTruthy()
expect(new TextMateScopeSelector('(a,b) | (c, d)').matches(['e'])).toBeFalsy()
it "matches paths", ->
expect(new TextMateScopeSelector('a b').matches(['a', 'b'])).toBeTruthy()
expect(new TextMateScopeSelector('a b').matches(['b', 'a'])).toBeFalsy()
expect(new TextMateScopeSelector('a c').matches(['a', 'b', 'c', 'd', 'e'])).toBeTruthy()
expect(new TextMateScopeSelector('a b e').matches(['a', 'b', 'c', 'd', 'e'])).toBeTruthy()
describe ".toCssSelector()", ->
it "converts the TextMate scope selector to a CSS selector", ->
expect(new TextMateScopeSelector('a b c').toCssSelector()).toBe '.a .b .c'
expect(new TextMateScopeSelector('a.b.c').toCssSelector()).toBe '.a.b.c'
expect(new TextMateScopeSelector('*').toCssSelector()).toBe '*'
expect(new TextMateScopeSelector('a - b').toCssSelector()).toBe '.a:not(.b)'
expect(new TextMateScopeSelector('a & b').toCssSelector()).toBe '.a .b'
expect(new TextMateScopeSelector('a & -b').toCssSelector()).toBe '.a:not(.b)'
expect(new TextMateScopeSelector('a | b').toCssSelector()).toBe '.a, .b'
expect(new TextMateScopeSelector('a - (b.c d)').toCssSelector()).toBe '.a:not(.b.c .d)'
expect(new TextMateScopeSelector('a, b').toCssSelector()).toBe '.a, .b'
-163
Ver Arquivo
@@ -1,163 +0,0 @@
UndoManager = require 'undo-manager'
Buffer = require 'text-buffer'
Range = require 'range'
describe "UndoManager", ->
[buffer, undoManager] = []
beforeEach ->
buffer = new Buffer(require.resolve('fixtures/sample.js'))
undoManager = buffer.undoManager
afterEach ->
buffer.destroy()
describe ".undo()", ->
it "undoes the last change", ->
buffer.change(new Range([0, 5], [0, 9]), '')
buffer.insert([0, 6], 'h')
buffer.insert([0, 10], 'y')
expect(buffer.lineForRow(0)).toContain 'qshorty'
undoManager.undo()
expect(buffer.lineForRow(0)).toContain 'qshort'
expect(buffer.lineForRow(0)).not.toContain 'qshorty'
undoManager.undo()
expect(buffer.lineForRow(0)).toContain 'qsort'
undoManager.undo()
expect(buffer.lineForRow(0)).toContain 'quicksort'
it "does not throw an exception when there is nothing to undo", ->
undoManager.undo()
describe ".redo()", ->
beforeEach ->
buffer.change(new Range([0, 5], [0, 9]), '')
buffer.insert([0, 6], 'h')
buffer.insert([0, 10], 'y')
undoManager.undo()
undoManager.undo()
expect(buffer.lineForRow(0)).toContain 'qsort'
it "redoes the last undone change", ->
undoManager.redo()
expect(buffer.lineForRow(0)).toContain 'qshort'
undoManager.redo()
expect(buffer.lineForRow(0)).toContain 'qshorty'
undoManager.undo()
expect(buffer.lineForRow(0)).toContain 'qshort'
it "does not throw an exception when there is nothing to redo", ->
undoManager.redo()
undoManager.redo()
undoManager.redo()
it "discards the redo history when there is a new change following an undo", ->
buffer.insert([0, 6], 'p')
expect(buffer.getText()).toContain 'qsport'
undoManager.redo()
expect(buffer.getText()).toContain 'qsport'
describe "transaction methods", ->
describe "transact()", ->
beforeEach ->
buffer.setText('')
it "starts a transaction that can be committed later", ->
buffer.append('1')
undoManager.transact()
buffer.append('2')
buffer.append('3')
undoManager.commit()
buffer.append('4')
expect(buffer.getText()).toBe '1234'
undoManager.undo()
expect(buffer.getText()).toBe '123'
undoManager.undo()
expect(buffer.getText()).toBe '1'
undoManager.redo()
expect(buffer.getText()).toBe '123'
it "starts a transaction that can be aborted later", ->
buffer.append('1')
buffer.append('2')
undoManager.transact()
buffer.append('3')
buffer.append('4')
expect(buffer.getText()).toBe '1234'
undoManager.abort()
expect(buffer.getText()).toBe '12'
undoManager.undo()
expect(buffer.getText()).toBe '1'
undoManager.redo()
expect(buffer.getText()).toBe '12'
undoManager.redo()
expect(buffer.getText()).toBe '12'
describe "commit", ->
it "throws an exception if there is no current transaction", ->
expect(-> buffer.commit()).toThrow()
it "does not record empty transactions", ->
buffer.insert([0,0], "foo")
undoManager.transact()
undoManager.commit()
undoManager.undo()
expect(buffer.lineForRow(0)).not.toContain("foo")
describe "abort", ->
it "does not affect the undo stack when the current transaction is empty", ->
buffer.setText('')
buffer.append('1')
buffer.transact()
buffer.abort()
expect(buffer.getText()).toBe '1'
buffer.undo()
expect(buffer.getText()).toBe ''
it "throws an exception if there is no current transaction", ->
expect(-> buffer.abort()).toThrow()
describe "exception handling", ->
describe "when a `do` operation throws an exception", ->
it "clears the stack", ->
spyOn(console, 'error')
buffer.setText("word")
buffer.insert([0,0], "1")
expect(->
undoManager.pushOperation(do: -> throw new Error("I'm a bad do operation"))
).toThrow("I'm a bad do operation")
undoManager.undo()
expect(buffer.lineForRow(0)).toBe "1word"
describe "when an `undo` operation throws an exception", ->
it "clears the stack", ->
spyOn(console, 'error')
buffer.setText("word")
buffer.insert([0,0], "1")
undoManager.pushOperation(undo: -> throw new Error("I'm a bad undo operation"))
expect(-> undoManager.undo()).toThrow("I'm a bad undo operation")
expect(buffer.lineForRow(0)).toBe "1word"
describe "when an `redo` operation throws an exception", ->
it "clears the stack", ->
spyOn(console, 'error')
buffer.setText("word")
buffer.insert([0,0], "1")
undoManager.pushOperation(redo: -> throw new Error("I'm a bad redo operation"))
undoManager.undo()
expect(-> undoManager.redo()).toThrow("I'm a bad redo operation")
expect(buffer.lineForRow(0)).toBe "1word"
+38 -18
Ver Arquivo
@@ -21,10 +21,15 @@ class AtomReporter extends View
@div id: 'HTMLReporter', class: 'jasmine_reporter', =>
@div outlet: 'specPopup', class: "spec-popup"
@div outlet: "suites"
@div outlet: 'coreHeader', class: 'symbolHeader'
@ul outlet: 'coreSummary', class: 'symbolSummary list-unstyled'
@div outlet: 'packagesHeader', class: 'symbolHeader'
@ul outlet: 'packagesSummary', class: 'symbolSummary list-unstyled'
@div outlet: 'coreArea', =>
@div outlet: 'coreHeader', class: 'symbolHeader'
@ul outlet: 'coreSummary', class: 'symbolSummary list-unstyled'
@div outlet: 'bundledArea', =>
@div outlet: 'bundledHeader', class: 'symbolHeader'
@ul outlet: 'bundledSummary', class: 'symbolSummary list-unstyled'
@div outlet: 'userArea', =>
@div outlet: 'userHeader', class: 'symbolHeader'
@ul outlet: 'userSummary', class: 'symbolSummary list-unstyled'
@div outlet: "status", class: 'status', =>
@div outlet: "time", class: 'time'
@div outlet: "specCount", class: 'spec-count'
@@ -122,24 +127,39 @@ class AtomReporter extends View
addSpecs: (specs) ->
coreSpecs = 0
packageSpecs = 0
bundledPackageSpecs = 0
userPackageSpecs = 0
for spec in specs
symbol = $$ -> @li class: "spec-summary pending spec-summary-#{spec.id}"
if spec.coreSpec
coreSpecs++
@coreSummary.append symbol
else
packageSpecs++
@packagesSummary.append symbol
symbol = $$ -> @li id: "spec-summary-#{spec.id}", class: "spec-summary pending"
switch spec.specType
when 'core'
coreSpecs++
@coreSummary.append symbol
when 'bundled'
bundledPackageSpecs++
@bundledSummary.append symbol
when 'user'
userPackageSpecs++
@userSummary.append symbol
@coreHeader.text("Core Specs (#{coreSpecs}):")
@packagesHeader.text("Package Specs (#{packageSpecs}):")
if coreSpecs > 0
@coreHeader.text("Core Specs (#{coreSpecs}):")
else
@coreArea.hide()
if bundledPackageSpecs > 0
@bundledHeader.text("Bundled Package Specs (#{bundledPackageSpecs}):")
else
@bundledArea.hide()
if userPackageSpecs > 0
@userHeader.text("User Package Specs (#{userPackageSpecs}):")
else
@userArea.hide()
specStarted: (spec) ->
@runningSpecCount++
specComplete: (spec) ->
specSummaryElement = $(".spec-summary-#{spec.id}")
specSummaryElement = $("#spec-summary-#{spec.id}")
specSummaryElement.removeClass('pending')
specSummaryElement.data("description", spec.getFullName())
@@ -165,7 +185,7 @@ class SuiteResultView extends View
suite: null
initialize: (@suite) ->
@addClass("suite-view-#{@suite.id}")
@attr('id', "suite-view-#{@suite.id}")
@description.html @suite.description
attach: ->
@@ -174,7 +194,7 @@ class SuiteResultView extends View
parentSuiteView: ->
return unless @suite.parentSuite
if not suiteView = $(".suite-view-#{@suite.parentSuite.id}").view()
if not suiteView = $("#suite-view-#{@suite.parentSuite.id}").view()
suiteView = new SuiteResultView(@suite.parentSuite)
suiteView.attach()
@@ -202,7 +222,7 @@ class SpecResultView extends View
@parentSuiteView().append this
parentSuiteView: ->
if not suiteView = $(".suite-view-#{@spec.suite.id}").view()
if not suiteView = $("#suite-view-#{@spec.suite.id}").view()
suiteView = new SuiteResultView(@spec.suite)
suiteView.attach()
@@ -219,7 +219,7 @@ describe "the `atom` global", ->
describe ".deactivatePackage(id)", ->
describe "atom packages", ->
it "calls `deactivate` on the package's main module", ->
it "calls `deactivate` on the package's main module if activate was successful", ->
pack = atom.activatePackage("package-with-deactivate")
expect(atom.isPackageActive("package-with-deactivate")).toBeTruthy()
spyOn(pack.mainModule, 'deactivate').andCallThrough()
@@ -228,6 +228,23 @@ describe "the `atom` global", ->
expect(pack.mainModule.deactivate).toHaveBeenCalled()
expect(atom.isPackageActive("package-with-module")).toBeFalsy()
spyOn(console, 'warn')
badPack = atom.activatePackage("package-that-throws-on-activate")
expect(atom.isPackageActive("package-that-throws-on-activate")).toBeTruthy()
spyOn(badPack.mainModule, 'deactivate').andCallThrough()
atom.deactivatePackage("package-that-throws-on-activate")
expect(badPack.mainModule.deactivate).not.toHaveBeenCalled()
expect(atom.isPackageActive("package-that-throws-on-activate")).toBeFalsy()
it "does not serialize packages that have not been activated called on their main module", ->
spyOn(console, 'warn')
badPack = atom.activatePackage("package-that-throws-on-activate")
spyOn(badPack.mainModule, 'serialize').andCallThrough()
atom.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", ->
spyOn(console, 'error')
atom.activatePackage('package-with-serialize-error', immediate: true)
@@ -265,7 +282,7 @@ describe "the `atom` global", ->
atom.deactivatePackage("package-with-scoped-properties")
expect(syntax.getProperty ['.source.omg'], 'editor.increaseIndentPattern').toBeUndefined()
describe "texmate packages", ->
describe "textmate packages", ->
it "removes the package's grammars", ->
expect(syntax.selectGrammar("file.rb").name).toBe "Null Grammar"
atom.activatePackage('ruby-tmbundle', sync: true)
@@ -277,7 +294,3 @@ describe "the `atom` global", ->
atom.activatePackage('ruby-tmbundle', sync: true)
atom.deactivatePackage('ruby-tmbundle')
expect(syntax.getProperty(['.source.ruby'], 'editor.commentStart')).toBeUndefined()
describe ".getVersion", ->
it "returns the current version number", ->
expect(typeof atom.getVersion()).toBe 'string'
@@ -8,13 +8,49 @@ describe "DisplayBuffer", ->
tabLength = 2
atom.activatePackage('javascript-tmbundle', sync: true)
buffer = project.bufferForPath('sample.js')
displayBuffer = new DisplayBuffer(buffer, { tabLength })
displayBuffer.on 'changed', changeHandler = jasmine.createSpy 'changeHandler'
displayBuffer = new DisplayBuffer({buffer, tabLength})
changeHandler = jasmine.createSpy 'changeHandler'
displayBuffer.on 'changed', changeHandler
afterEach ->
displayBuffer.destroy()
buffer.release()
describe "@deserialize(state)", ->
it "constructs a display buffer with the same buffer, folds, editorWidthInChars, and tabLength", ->
displayBuffer.setTabLength(4)
displayBuffer.setEditorWidthInChars(64)
displayBuffer.createFold(2, 4)
displayBuffer2 = deserialize(displayBuffer.serialize())
expect(displayBuffer2.id).toBe displayBuffer.id
expect(displayBuffer2.buffer).toBe displayBuffer.buffer
expect(displayBuffer2.tokenizedBuffer.buffer).toBe displayBuffer.tokenizedBuffer.buffer
expect(displayBuffer2.isFoldedAtBufferRow(2)).toBeTruthy()
expect(displayBuffer2.getSoftWrapColumn()).toBe displayBuffer.getSoftWrapColumn()
expect(displayBuffer2.getTabLength()).toBe displayBuffer.getTabLength()
describe ".copy()", ->
it "creates a new DisplayBuffer with the same initial state", ->
marker1 = displayBuffer.markBufferRange([[1, 2], [3, 4]], id: 1)
marker2 = displayBuffer.markBufferRange([[2, 3], [4, 5]], isReversed: true, id: 2)
marker3 = displayBuffer.markBufferPosition([5, 6], id: 3)
displayBuffer.createFold(3, 5)
displayBuffer2 = displayBuffer.copy()
expect(displayBuffer2.id).not.toBe displayBuffer.id
expect(displayBuffer2.buffer).toBe displayBuffer.buffer
expect(displayBuffer2.getTabLength()).toBe displayBuffer.getTabLength()
expect(displayBuffer2.getMarkerCount()).toEqual displayBuffer.getMarkerCount()
expect(displayBuffer2.findMarker(id: 1)).toEqual marker1
expect(displayBuffer2.findMarker(id: 2)).toEqual marker2
expect(displayBuffer2.findMarker(id: 3)).toEqual marker3
expect(displayBuffer2.isFoldedAtBufferRow(3)).toBeTruthy()
# can diverge from origin
displayBuffer2.destroyFoldsContainingBufferRow(3)
expect(displayBuffer2.isFoldedAtBufferRow(3)).not.toBe displayBuffer.isFoldedAtBufferRow(3)
describe "when the buffer changes", ->
it "renders line numbers correctly", ->
originalLineCount = displayBuffer.getLineCount()
@@ -24,10 +60,23 @@ describe "DisplayBuffer", ->
describe "soft wrapping", ->
beforeEach ->
displayBuffer.setSoftWrapColumn(50)
displayBuffer.setSoftWrap(true)
displayBuffer.setEditorWidthInChars(50)
changeHandler.reset()
describe "rendering of soft-wrapped lines", ->
describe "when editor.softWrapAtPreferredLineLength is set", ->
it "uses the preferred line length as the soft wrap column when it is less than the configured soft wrap column", ->
config.set('editor.preferredLineLength', 100)
config.set('editor.softWrapAtPreferredLineLength', true)
expect(displayBuffer.lineForRow(10).text).toBe ' return '
config.set('editor.preferredLineLength', 5)
expect(displayBuffer.lineForRow(10).text).toBe 'funct'
config.set('editor.softWrapAtPreferredLineLength', false)
expect(displayBuffer.lineForRow(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)
@@ -45,7 +94,7 @@ describe "DisplayBuffer", ->
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.change([[0, 0], [1, 0]], 'abcdefghijklmnopqrstuvwxyz\n')
displayBuffer.setSoftWrapColumn(10)
displayBuffer.setEditorWidthInChars(10)
expect(displayBuffer.lineForRow(0).text).toBe 'abcdefghij'
expect(displayBuffer.lineForRow(1).text).toBe 'klmnopqrst'
expect(displayBuffer.lineForRow(2).text).toBe 'uvwxyz'
@@ -104,6 +153,20 @@ describe "DisplayBuffer", ->
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 = project.buildBuffer(null, '')
displayBuffer = new DisplayBuffer({buffer, tabLength, editorWidthInChars: 30, softWrap: 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 ""
describe "position translation", ->
it "translates positions accounting for wrapped lines", ->
# before any wrapped lines
@@ -132,9 +195,9 @@ describe "DisplayBuffer", ->
expect(displayBuffer.bufferPositionForScreenPosition([3, -5])).toEqual([3, 0])
expect(displayBuffer.bufferPositionForScreenPosition([3, Infinity])).toEqual([3, 50])
describe ".setSoftWrapColumn(length)", ->
describe ".setEditorWidthInChars(length)", ->
it "changes the length at which lines are wrapped and emits a change event for all screen lines", ->
displayBuffer.setSoftWrapColumn(40)
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'
@@ -145,13 +208,14 @@ describe "DisplayBuffer", ->
displayBuffer.destroy()
buffer.release()
buffer = project.bufferForPath('two-hundred.txt')
displayBuffer = new DisplayBuffer(buffer, { tabLength })
displayBuffer = new DisplayBuffer({buffer, tabLength})
displayBuffer.on 'changed', changeHandler
describe "when folds are created and destroyed", ->
describe "when a fold spans multiple lines", ->
it "replaces the lines spanned by the fold with a placeholder that references the fold object", ->
fold = displayBuffer.createFold(4, 7)
expect(fold).toBeDefined()
[line4, line5] = displayBuffer.linesForRows(4, 5)
expect(line4.fold).toBe fold
@@ -250,7 +314,7 @@ describe "DisplayBuffer", ->
describe "when there is another display buffer pointing to the same buffer", ->
it "does not create folds in the other display buffer", ->
otherDisplayBuffer = new DisplayBuffer(buffer, { tabLength })
otherDisplayBuffer = new DisplayBuffer({buffer, tabLength})
displayBuffer.createFold(2, 4)
expect(otherDisplayBuffer.foldsStartingAtBufferRow(2).length).toBe 0
@@ -274,7 +338,7 @@ describe "DisplayBuffer", ->
expect(changeHandler).toHaveBeenCalledWith(start: 1, end: 3, screenDelta: -2, bufferDelta: -4)
describe "when the changes is subsequently undone", ->
it "restores destroyed folds", ->
xit "restores destroyed folds", ->
buffer.undo()
expect(displayBuffer.lineForRow(2).text).toBe '2'
expect(displayBuffer.lineForRow(2).fold).toBe fold1
@@ -454,7 +518,8 @@ describe "DisplayBuffer", ->
describe ".clipScreenPosition(screenPosition, wrapBeyondNewlines: false, wrapAtSoftNewlines: false, skipAtomicTokens: false)", ->
beforeEach ->
displayBuffer.setSoftWrapColumn(50)
displayBuffer.setSoftWrap(true)
displayBuffer.setEditorWidthInChars(50)
it "allows valid positions", ->
expect(displayBuffer.clipScreenPosition([4, 5])).toEqual [4, 5]
@@ -601,8 +666,8 @@ describe "DisplayBuffer", ->
oldTailBufferPosition: [8, 4]
newTailScreenPosition: [5, 4]
newTailBufferPosition: [8, 4]
bufferChanged: false
valid: true
textChanged: false
isValid: true
}
markerChangedHandler.reset()
@@ -617,8 +682,8 @@ describe "DisplayBuffer", ->
oldTailBufferPosition: [8, 4]
newTailScreenPosition: [5, 4]
newTailBufferPosition: [8, 4]
bufferChanged: true
valid: true
textChanged: true
isValid: true
}
markerChangedHandler.reset()
@@ -633,8 +698,8 @@ describe "DisplayBuffer", ->
oldTailBufferPosition: [8, 4]
newTailScreenPosition: [8, 4]
newTailBufferPosition: [8, 4]
bufferChanged: false
valid: true
textChanged: false
isValid: true
}
markerChangedHandler.reset()
@@ -649,8 +714,8 @@ describe "DisplayBuffer", ->
oldTailBufferPosition: [8, 4]
newTailScreenPosition: [5, 4]
newTailBufferPosition: [8, 4]
bufferChanged: false
valid: true
textChanged: false
isValid: true
}
it "triggers the 'changed' event whenever the marker tail's position changes in the buffer or on screen", ->
@@ -665,8 +730,8 @@ describe "DisplayBuffer", ->
oldTailBufferPosition: [8, 4]
newTailScreenPosition: [8, 20]
newTailBufferPosition: [11, 20]
bufferChanged: false
valid: true
textChanged: false
isValid: true
}
markerChangedHandler.reset()
@@ -681,24 +746,24 @@ describe "DisplayBuffer", ->
oldTailBufferPosition: [11, 20]
newTailScreenPosition: [8, 23]
newTailBufferPosition: [11, 23]
bufferChanged: true
valid: true
textChanged: true
isValid: true
}
it "triggers the 'changed' event whenever the marker is invalidated or revalidated", ->
xit "triggers the 'changed' event whenever the marker is invalidated or revalidated", ->
buffer.deleteRow(8)
expect(markerChangedHandler).toHaveBeenCalled()
expect(markerChangedHandler.argsForCall[0][0]).toEqual {
oldHeadScreenPosition: [5, 10]
oldHeadBufferPosition: [8, 10]
newHeadScreenPosition: [5, 10]
newHeadBufferPosition: [8, 10]
newHeadBufferPosition: [8, 0]
oldTailScreenPosition: [5, 4]
oldTailBufferPosition: [8, 4]
newTailScreenPosition: [5, 4]
newTailBufferPosition: [8, 4]
bufferChanged: true
valid: false
newTailBufferPosition: [8, 0]
textChanged: true
isValid: false
}
markerChangedHandler.reset()
@@ -714,15 +779,15 @@ describe "DisplayBuffer", ->
oldTailBufferPosition: [8, 4]
newTailScreenPosition: [5, 4]
newTailBufferPosition: [8, 4]
bufferChanged: true
valid: true
textChanged: true
isValid: true
}
it "does not call the callback for screen changes that don't change the position of the marker", ->
displayBuffer.createFold(10, 11)
expect(markerChangedHandler).not.toHaveBeenCalled()
it "updates markers before emitting buffer change events, but does not notify their observers until the change event", ->
xit "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()
@@ -839,3 +904,15 @@ describe "DisplayBuffer", ->
marker2.on 'destroyed', destroyedHandler
buffer.getMarker(marker2.id).destroy()
expect(destroyedHandler).toHaveBeenCalled()
describe "DisplayBufferMarker.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)
expect(displayBuffer.getMarkerCount()).toBe initialMarkerCount + 1
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
+62
Ver Arquivo
@@ -0,0 +1,62 @@
{Site} = require 'telepath'
Environment = require 'environment'
describe "EditSession replication", ->
[env1, env2, editSession1, editSession2] = []
beforeEach ->
env1 = new Environment(siteId: 1)
env2 = env1.clone(siteId: 2)
envConnection = env1.connect(env2)
doc2 = null
env1.run ->
editSession1 = project.open('sample.js')
editSession1.setScrollTop(5)
editSession1.setScrollLeft(5)
editSession1.setCursorScreenPosition([0, 5])
editSession1.addSelectionForBufferRange([[1, 2], [3, 4]])
doc1 = editSession1.getState()
doc2 = doc1.clone(env2.site)
envConnection.connect(doc1, doc2)
env2.run ->
editSession2 = deserialize(doc2)
afterEach ->
env1.destroy()
env2.destroy()
it "replicates the selections of existing replicas", ->
expect(editSession2.getRemoteSelectedBufferRanges()).toEqual editSession1.getSelectedBufferRanges()
editSession1.getLastSelection().setBufferRange([[2, 3], [4, 5]])
expect(editSession2.getRemoteSelectedBufferRanges()).toEqual editSession1.getSelectedBufferRanges()
editSession1.addCursorAtBufferPosition([5, 6])
expect(editSession2.getRemoteSelectedBufferRanges()).toEqual editSession1.getSelectedBufferRanges()
editSession1.consolidateSelections()
expect(editSession2.getRemoteSelectedBufferRanges()).toEqual editSession1.getSelectedBufferRanges()
it "introduces a local cursor for a new replica at the position of the last remote cursor", ->
expect(editSession2.getCursors().length).toBe 1
expect(editSession2.getSelections().length).toBe 1
expect(editSession2.getCursorBufferPosition()).toEqual [3, 4]
expect(editSession2.getSelectedBufferRanges()).toEqual [[[3, 4], [3, 4]]]
expect(editSession1.getRemoteCursors().length).toBe 1
expect(editSession1.getRemoteSelections().length).toBe 1
[cursor] = editSession1.getRemoteCursors()
[selection] = editSession1.getRemoteSelections()
expect(cursor.getBufferPosition()).toEqual [3, 4]
expect(selection.getBufferRange()).toEqual [[3, 4], [3, 4]]
it "replicates the scroll position", ->
expect(editSession2.getScrollTop()).toBe editSession1.getScrollTop()
expect(editSession2.getScrollLeft()).toBe editSession1.getScrollLeft()
editSession1.setScrollTop(10)
expect(editSession2.getScrollTop()).toBe 10
editSession2.setScrollLeft(20)
expect(editSession1.getScrollLeft()).toBe 20
@@ -15,6 +15,58 @@ describe "EditSession", ->
buffer = editSession.buffer
lineLengths = buffer.getLines().map (line) -> line.length
describe "@deserialize(state)", ->
it "restores selections and folds based on markers in the buffer", ->
editSession.setSelectedBufferRange([[1, 2], [3, 4]])
editSession.addSelectionForBufferRange([[5, 6], [7, 5]], isReversed: true)
editSession.foldBufferRow(4)
expect(editSession.isFoldedAtBufferRow(4)).toBeTruthy()
editSession2 = deserialize(editSession.serialize())
expect(editSession2.id).toBe editSession.id
expect(editSession2.getBuffer().getPath()).toBe editSession.getBuffer().getPath()
expect(editSession2.getSelectedBufferRanges()).toEqual [[[1, 2], [3, 4]], [[5, 6], [7, 5]]]
expect(editSession2.getSelection(1).isReversed()).toBeTruthy()
expect(editSession2.isFoldedAtBufferRow(4)).toBeTruthy()
describe ".copy()", ->
it "returns a different edit session with the same initial state", ->
editSession.setSelectedBufferRange([[1, 2], [3, 4]])
editSession.addSelectionForBufferRange([[5, 6], [7, 8]], isReversed: true)
editSession.foldBufferRow(4)
expect(editSession.isFoldedAtBufferRow(4)).toBeTruthy()
editSession2 = editSession.copy()
expect(editSession2.id).not.toBe editSession.id
expect(editSession2.getSelectedBufferRanges()).toEqual editSession.getSelectedBufferRanges()
expect(editSession2.getSelection(1).isReversed()).toBeTruthy()
expect(editSession2.isFoldedAtBufferRow(4)).toBeTruthy()
# editSession2 can now diverge from its origin edit session
editSession2.getSelection().setBufferRange([[2, 1], [4, 3]])
expect(editSession2.getSelectedBufferRanges()).not.toEqual editSession.getSelectedBufferRanges()
editSession2.unfoldBufferRow(4)
expect(editSession2.isFoldedAtBufferRow(4)).not.toBe editSession.isFoldedAtBufferRow(4)
describe "config defaults", ->
it "uses the `editor.tabLength`, `editor.softWrap`, and `editor.softTabs` config values", ->
config.set('editor.tabLength', 4)
config.set('editor.softWrap', true)
config.set('editor.softTabs', false)
editSession1 = project.open('a')
expect(editSession1.getTabLength()).toBe 4
expect(editSession1.getSoftWrap()).toBe true
expect(editSession1.getSoftTabs()).toBe false
config.set('editor.tabLength', 100)
config.set('editor.softWrap', false)
config.set('editor.softTabs', true)
editSession2 = project.open('b')
expect(editSession2.getTabLength()).toBe 100
expect(editSession2.getSoftWrap()).toBe false
expect(editSession2.getSoftTabs()).toBe true
describe "title", ->
describe ".getTitle()", ->
it "uses the basename of the buffer's path as its title, or 'untitled' if the path is undefined", ->
@@ -68,7 +120,8 @@ describe "EditSession", ->
describe "when soft-wrap is enabled and code is folded", ->
beforeEach ->
editSession.setSoftWrapColumn(50)
editSession.setSoftWrap(true)
editSession.setEditorWidthInChars(50)
editSession.createFold(2, 3)
it "positions the cursor at the buffer position that corresponds to the given screen position", ->
@@ -291,7 +344,8 @@ describe "EditSession", ->
describe ".moveCursorToBeginningOfLine()", ->
describe "when soft wrap is on", ->
it "moves cursor to the beginning of the screen line", ->
editSession.setSoftWrapColumn(10)
editSession.setSoftWrap(true)
editSession.setEditorWidthInChars(10)
editSession.setCursorScreenPosition([1, 2])
editSession.moveCursorToBeginningOfLine()
cursor = editSession.getCursor()
@@ -310,7 +364,8 @@ describe "EditSession", ->
describe ".moveCursorToEndOfLine()", ->
describe "when soft wrap is on", ->
it "moves cursor to the beginning of the screen line", ->
editSession.setSoftWrapColumn(10)
editSession.setSoftWrap(true)
editSession.setEditorWidthInChars(10)
editSession.setCursorScreenPosition([1, 2])
editSession.moveCursorToEndOfLine()
cursor = editSession.getCursor()
@@ -329,7 +384,8 @@ describe "EditSession", ->
describe ".moveCursorToFirstCharacterOfLine()", ->
describe "when soft wrap is on", ->
it "moves to the first character of the current screen line or the beginning of the screen line if it's already on the first character", ->
editSession.setSoftWrapColumn(10)
editSession.setSoftWrap(true)
editSession.setEditorWidthInChars(10)
editSession.setCursorScreenPosition [2,5]
editSession.addCursorAtScreenPosition [8,7]
@@ -342,7 +398,7 @@ describe "EditSession", ->
expect(cursor1.getScreenPosition()).toEqual [2,0]
expect(cursor2.getScreenPosition()).toEqual [8,0]
describe "when soft wrap is of", ->
describe "when soft wrap is off", ->
it "moves to the first character of the current line or the beginning of the line if it's already on the first character", ->
editSession.setCursorScreenPosition [0,5]
editSession.addCursorAtScreenPosition [1,7]
@@ -526,7 +582,7 @@ describe "EditSession", ->
oldScreenPosition: [6, 0]
newBufferPosition: [9, 3]
newScreenPosition: [6, 3]
bufferChanged: true
textChanged: true
)
describe "when the position of the associated selection's tail changes, but not the cursor's position", ->
@@ -586,16 +642,18 @@ describe "EditSession", ->
expect(selection1.isReversed()).toBeFalsy()
it "merges selections when they intersect when moving up", ->
editSession.setSelectedBufferRanges([[[0,9], [0,13]], [[1,10], [1,20]]], reverse: true)
editSession.setSelectedBufferRanges([[[0,9], [0,13]], [[1,10], [1,20]]], isReversed: true)
[selection1, selection2] = editSession.getSelections()
editSession.selectUp()
expect(editSession.getSelections().length).toBe 1
expect(editSession.getSelections()).toEqual [selection1]
expect(selection1.getScreenRange()).toEqual([[0, 0], [1, 20]])
expect(selection1.isReversed()).toBeTruthy()
it "merges selections when they intersect when moving left", ->
editSession.setSelectedBufferRanges([[[0,9], [0,13]], [[0,14], [1,20]]], reverse: true)
editSession.setSelectedBufferRanges([[[0,9], [0,13]], [[0,14], [1,20]]], isReversed: true)
[selection1, selection2] = editSession.getSelections()
editSession.selectLeft()
@@ -914,8 +972,10 @@ describe "EditSession", ->
it "does not remove folds that contain the selections", ->
editSession.setSelectedBufferRange([[0,0], [0,0]])
editSession.createFold(1, 4)
editSession.setSelectedBufferRanges([[[2, 2], [3, 3]]], preserveFolds: true)
expect(editSession.lineForScreenRow(1).fold).toBeDefined()
editSession.createFold(6, 8)
editSession.setSelectedBufferRanges([[[2, 2], [3, 3]], [[6, 0], [6, 1]]], preserveFolds: true)
expect(editSession.isFoldedAtBufferRow(1)).toBeTruthy()
expect(editSession.isFoldedAtBufferRow(6)).toBeTruthy()
describe ".selectMarker(marker)", ->
describe "if the marker is valid", ->
@@ -1117,6 +1177,12 @@ describe "EditSession", ->
editSession.setCursorScreenPosition([3, 3])
expect(selection.isEmpty()).toBeTruthy()
it "does not share selections between different edit sessions for the same buffer", ->
editSession2 = project.open('sample.js')
editSession.setSelectedBufferRanges([[[1, 2], [3, 4]], [[5, 6], [7, 8]]])
editSession2.setSelectedBufferRanges([[[8, 7], [6, 5]], [[4, 3], [2, 1]]])
expect(editSession2.getSelectedBufferRanges()).not.toEqual editSession.getSelectedBufferRanges()
describe "buffer manipulation", ->
describe ".insertText(text)", ->
describe "when there are multiple empty selections", ->
@@ -1254,7 +1320,7 @@ describe "EditSession", ->
expect(cursor2.getBufferPosition()).toEqual [8,0]
describe ".insertNewlineBelow()", ->
describe "when the operation is undone", ->
xdescribe "when the operation is undone", ->
it "places the cursor back at the previous location", ->
editSession.setCursorBufferPosition([0,2])
editSession.insertNewlineBelow()
@@ -1651,7 +1717,7 @@ describe "EditSession", ->
describe "if 'softTabs' is false", ->
it "insert a \t into the buffer", ->
editSession.softTabs = false
editSession.setSoftTabs(false)
expect(buffer.lineForRow(0)).not.toMatch(/^\t/)
editSession.indent()
expect(buffer.lineForRow(0)).toMatch(/^\t/)
@@ -1670,7 +1736,7 @@ describe "EditSession", ->
describe "when 'softTabs' is false", ->
it "moves the cursor to the end of the leading whitespace and inserts enough tabs to bring the line to the suggested level of indentaion", ->
convertToHardTabs(buffer)
editSession.softTabs = false
editSession.setSoftTabs(false)
buffer.insert([5, 0], "\t\n")
editSession.setCursorBufferPosition [5, 0]
editSession.indent(autoIndent: true)
@@ -1690,7 +1756,7 @@ describe "EditSession", ->
describe "when 'softTabs' is false", ->
it "moves the cursor to the end of the leading whitespace and inserts \t into the buffer", ->
convertToHardTabs(buffer)
editSession.softTabs = false
editSession.setSoftTabs(false)
buffer.insert([7, 0], "\t\t\t\n")
editSession.setCursorBufferPosition [7, 1]
editSession.indent(autoIndent: true)
@@ -1734,7 +1800,8 @@ describe "EditSession", ->
describe ".cutToEndOfLine()", ->
describe "when soft wrap is on", ->
it "cuts up to the end of the line", ->
editSession.setSoftWrapColumn(10)
editSession.setSoftWrap(true)
editSession.setEditorWidthInChars(10)
editSession.setCursorScreenPosition([2, 2])
editSession.cutToEndOfLine()
expect(editSession.lineForScreenRow(2).text).toBe '= () {'
@@ -1785,7 +1852,7 @@ describe "EditSession", ->
describe "when softTabs is disabled", ->
it "indents line and retains selection", ->
convertToHardTabs(buffer)
editSession.softTabs = false
editSession.setSoftTabs(false)
editSession.setSelectedBufferRange([[0,3], [0,3]])
editSession.indentSelectedRows()
expect(buffer.lineForRow(0)).toBe "\tvar quicksort = function () {"
@@ -1802,7 +1869,7 @@ describe "EditSession", ->
describe "when softTabs is disabled", ->
it "indents line and retains selection", ->
convertToHardTabs(buffer)
editSession.softTabs = false
editSession.setSoftTabs(false)
editSession.setSelectedBufferRange([[0,4], [0,14]])
editSession.indentSelectedRows()
expect(buffer.lineForRow(0)).toBe "\tvar quicksort = function () {"
@@ -1829,7 +1896,7 @@ describe "EditSession", ->
describe "when softTabs is disabled", ->
it "indents selected lines (that are not empty) and retains selection", ->
convertToHardTabs(buffer)
editSession.softTabs = false
editSession.setSoftTabs(false)
editSession.setSelectedBufferRange([[9,1], [11,15]])
editSession.indentSelectedRows()
expect(buffer.lineForRow(9)).toBe "\t\t};"
@@ -1989,7 +2056,7 @@ describe "EditSession", ->
editSession.toggleLineCommentsInSelection()
expect(buffer.lineForRow(10)).toBe " "
describe ".undo() and .redo()", ->
xdescribe ".undo() and .redo()", ->
it "undoes/redoes the last change", ->
editSession.insertText("foo")
editSession.undo()
@@ -2060,7 +2127,7 @@ describe "EditSession", ->
expect(editSession.isFoldedAtBufferRow(1)).toBeFalsy()
expect(editSession.isFoldedAtBufferRow(2)).toBeTruthy()
describe ".transact([fn])", ->
xdescribe ".transact([fn])", ->
describe "when called without a function", ->
it "restores the selection when the transaction is undone/redone", ->
buffer.setText('1234')
@@ -2190,7 +2257,8 @@ describe "EditSession", ->
describe "when soft wrap is enabled", ->
it "deletes the entire line that the cursor is on", ->
editSession.setSoftWrapColumn(10)
editSession.setSoftWrap(true)
editSession.setEditorWidthInChars(10)
editSession.setCursorBufferPosition([6])
line7 = buffer.lineForRow(7)
@@ -2200,7 +2268,7 @@ describe "EditSession", ->
expect(buffer.lineForRow(6)).toBe(line7)
expect(buffer.getLineCount()).toBe(count - 1)
describe "when the line being deleted preceeds a fold, and the command is undone", ->
xdescribe "when the line being deleted preceeds a fold, and the command is undone", ->
it "restores the line and preserves the fold", ->
editSession.setCursorBufferPosition([4])
editSession.foldCurrentRow()
@@ -2281,15 +2349,15 @@ describe "EditSession", ->
expect(editSession.getSelectedBufferRange()).toEqual [[0, 0], [0, 2]]
describe "soft-tabs detection", ->
it "assign soft / hard tabs based on the contents of the buffer, or uses the default if unknown", ->
it "assigns soft / hard tabs based on the contents of the buffer, or uses the default if unknown", ->
editSession = project.open('sample.js', softTabs: false)
expect(editSession.softTabs).toBeTruthy()
expect(editSession.getSoftTabs()).toBeTruthy()
editSession = project.open('sample-with-tabs.coffee', softTabs: true)
expect(editSession.softTabs).toBeFalsy()
expect(editSession.getSoftTabs()).toBeFalsy()
editSession = project.open(null, softTabs: false)
expect(editSession.softTabs).toBeFalsy()
expect(editSession.getSoftTabs()).toBeFalsy()
describe ".indentLevelForLine(line)", ->
it "returns the indent level when the line has only leading whitespace", ->
+37
Ver Arquivo
@@ -0,0 +1,37 @@
{Site} = require 'telepath'
Editor = require 'editor'
Environment = require 'environment'
describe "Editor replication", ->
[env1, env2, editSession1, editSession2, editor1, editor2] = []
beforeEach ->
env1 = new Environment(siteId: 1)
env2 = env1.clone(siteId: 2)
envConnection = env1.connect(env2)
doc2 = null
env1.run ->
editSession1 = project.open('sample.js')
editSession1.setSelectedBufferRange([[1, 2], [3, 4]])
doc1 = editSession1.getState()
doc2 = doc1.clone(env2.site)
envConnection.connect(doc1, doc2)
editor1 = new Editor(editSession1)
editor1.attachToDom()
env2.run ->
editSession2 = deserialize(doc2)
editor2 = new Editor(editSession2)
editor2.attachToDom()
afterEach ->
env1.destroy()
env2.destroy()
it "displays the cursors and selections from all replicas", ->
expect(editor1.getSelectionViews().length).toBe 2
expect(editor2.getSelectionViews().length).toBe 2
expect(editor1.getCursorViews().length).toBe 2
expect(editor2.getCursorViews().length).toBe 2
@@ -2,7 +2,7 @@ RootView = require 'root-view'
EditSession = require 'edit-session'
Buffer = require 'text-buffer'
Editor = require 'editor'
Range = require 'range'
{Range} = require 'telepath'
Project = require 'project'
$ = require 'jquery'
{$$} = require 'space-pen'
@@ -1013,7 +1013,7 @@ describe "Editor", ->
describe "when soft-wrap is enabled", ->
beforeEach ->
editor.setSoftWrap(true)
editSession.setSoftWrap(true)
it "does not scroll the buffer horizontally", ->
editor.width(charWidth * 30)
@@ -1479,10 +1479,13 @@ describe "Editor", ->
expect(editor.renderedLines.find('.line:first').text()).toBe "a line that ends with a carriage return#{cr}#{eol}"
describe "when wrapping is on", ->
beforeEach ->
editSession.setSoftWrap(true)
it "doesn't show the end of line invisible at the end of lines broken due to wrapping", ->
editor.setSoftWrapColumn(6)
editor.setText "a line that wraps"
editor.attachToDom()
editor.setWidthInChars(6)
config.set "editor.showInvisibles", true
space = editor.invisibles?.space
expect(space).toBeTruthy()
@@ -1492,9 +1495,9 @@ describe "Editor", ->
expect(editor.renderedLines.find('.line:last').text()).toBe "wraps#{eol}"
it "displays trailing carriage return using a visible non-empty value", ->
editor.setSoftWrapColumn(6)
editor.setText "a line that\r\n"
editor.attachToDom()
editor.setWidthInChars(6)
config.set "editor.showInvisibles", true
space = editor.invisibles?.space
expect(space).toBeTruthy()
@@ -1628,11 +1631,11 @@ describe "Editor", ->
describe "when soft-wrap is enabled", ->
beforeEach ->
editSession.setSoftWrap(true)
editor.attachToDom()
setEditorHeightInLines(editor, 20)
setEditorWidthInChars(editor, 50)
editor.setSoftWrap(true)
expect(editor.activeEditSession.softWrapColumn).toBe 50
expect(editor.activeEditSession.getSoftWrapColumn()).toBe 50
it "wraps lines that are too long to fit within the editor's width, adjusting cursor positioning accordingly", ->
expect(editor.renderedLines.find('.line').length).toBe 16
@@ -1670,14 +1673,10 @@ describe "Editor", ->
editor.edit(otherEditSession)
expect(editor.renderedLines.find('.line').length).toBe(1)
it "unwraps lines and cancels window resize listener when softwrap is disabled", ->
it "unwraps lines when softwrap is disabled", ->
editor.toggleSoftWrap()
expect(editor.renderedLines.find('.line:eq(3)').text()).toBe ' var pivot = items.shift(), current, left = [], right = [];'
spyOn(editor, 'setSoftWrapColumn')
$(window).trigger 'resize'
expect(editor.setSoftWrapColumn).not.toHaveBeenCalled()
it "allows the cursor to move down to the last line", ->
_.times editor.getLastScreenRow(), -> editor.moveCursorDown()
expect(editor.getCursorScreenPosition()).toEqual [editor.getLastScreenRow(), 0]
@@ -1700,15 +1699,15 @@ describe "Editor", ->
editor.moveCursorRight()
expect(editor.getCursorScreenPosition()).toEqual [11, 0]
it "calls .setSoftWrapColumn() when the editor is attached because now its dimensions are available to calculate it", ->
it "calls .setWidthInChars() when the editor is attached because now its dimensions are available to calculate it", ->
otherEditor = new Editor(editSession: project.open('sample.js'))
spyOn(otherEditor, 'setSoftWrapColumn')
spyOn(otherEditor, 'setWidthInChars')
otherEditor.setSoftWrap(true)
expect(otherEditor.setSoftWrapColumn).not.toHaveBeenCalled()
otherEditor.activeEditSession.setSoftWrap(true)
expect(otherEditor.setWidthInChars).not.toHaveBeenCalled()
otherEditor.simulateDomAttachment()
expect(otherEditor.setSoftWrapColumn).toHaveBeenCalled()
expect(otherEditor.setWidthInChars).toHaveBeenCalled()
otherEditor.remove()
describe "gutter rendering", ->
@@ -1744,7 +1743,8 @@ describe "Editor", ->
describe "when wrapping is on", ->
it "renders a • instead of line number for wrapped portions of lines", ->
editor.setSoftWrapColumn(50)
editSession.setSoftWrap(true)
editor.setWidthInChars(50)
expect(editor.gutter.find('.line-number').length).toEqual(8)
expect(editor.gutter.find('.line-number:eq(3)').intValue()).toBe 4
expect(editor.gutter.find('.line-number:eq(4)').html()).toBe '&nbsp;•'
@@ -1883,7 +1883,7 @@ describe "Editor", ->
describe "when there is wrapping", ->
beforeEach ->
editor.attachToDom(30)
editor.setSoftWrap(true)
editSession.setSoftWrap(true)
setEditorWidthInChars(editor, 20)
it "highlights the line where the initial cursor position is", ->
@@ -1946,7 +1946,7 @@ describe "Editor", ->
describe "when there is wrapping", ->
beforeEach ->
editor.setSoftWrap(true)
editSession.setSoftWrap(true)
setEditorWidthInChars(editor, 20)
it "highlights the line where the initial cursor position is", ->
@@ -2024,7 +2024,7 @@ describe "Editor", ->
it "adds/removes the 'selected' class to the fold's line element and hides the cursor if it is on the fold line", ->
editor.createFold(2, 4)
editor.setSelectedBufferRange([[1, 0], [2, 0]], preserveFolds: true, reverse: true)
editor.setSelectedBufferRange([[1, 0], [2, 0]], preserveFolds: true, isReversed: true)
expect(editor.lineElementForScreenRow(2)).toMatchSelector('.fold.selected')
editor.setSelectedBufferRange([[1, 0], [1, 1]], preserveFolds: true)
@@ -2670,3 +2670,12 @@ describe "Editor", ->
for rowNumber in [1..5]
expect(editor.lineElementForScreenRow(rowNumber).text()).toBe buffer.lineForRow(rowNumber)
describe "when the window is resized", ->
it "updates the active edit session with the current soft wrap column", ->
editor.attachToDom()
setEditorWidthInChars(editor, 50)
expect(editor.activeEditSession.getSoftWrapColumn()).toBe 50
setEditorWidthInChars(editor, 100)
$(window).trigger 'resize'
expect(editor.activeEditSession.getSoftWrapColumn()).toBe 100
+58
Ver Arquivo
@@ -0,0 +1,58 @@
{Site} = require 'telepath'
fsUtils = require 'fs-utils'
Project = require 'project'
module.exports =
class Environment
constructor: ({@site, @state, siteId, projectPath}={}) ->
@site ?= new Site(siteId ? 1)
if @state?
@run => @project = deserialize(@state.get('project'))
else
@state = @site.createDocument({})
@project = new Project(projectPath ? fsUtils.resolveOnLoadPath('fixtures'))
@state.set(project: @project.getState())
clone: (params) ->
site = new Site(params.siteId)
new Environment(site: site, state: @state.clone(site))
destroy: ->
@project.destroy()
getState: -> @state
run: (fn) ->
uninstall = @install()
fn()
uninstall()
install: ->
oldSite = window.site
oldProject = window.project
window.site = @site
window.project = @project
->
window.site = oldSite
window.project = oldProject
connect: (otherEnv) ->
new EnvironmentConnection(this, otherEnv)
connectDocuments: (docA, docB, envB) ->
class EnvironmentConnection
constructor: (@envA, @envB) ->
@envA.getState().connect(@envB.getState())
connect: (docA, docB) ->
unless docA.site is @envA.site
throw new Error("Document and environment sites do not match (doc: site #{docA.site.id}, env: site #{@envA.site.id})")
unless docB.site is @envB.site
throw new Error("Document and environment sites do not match (doc: site #{docB.site.id}, env: site #{@envB.site.id})")
connection = docA.connect(docB)
connection.abFilter = (fn) => @envB.run(fn)
connection.baFilter = (fn) => @envA.run(fn)
connection
@@ -0,0 +1,4 @@
module.exports =
activate: -> throw new Error('Top that')
deactivate: ->
serialize: ->
+1
Ver Arquivo
@@ -0,0 +1 @@
Hello World!
+1
Ver Arquivo
@@ -0,0 +1 @@
Goodbye World!
+1
Ver Arquivo
@@ -0,0 +1 @@
Hello World!
+1
Ver Arquivo
@@ -0,0 +1 @@
Goodbye World!
@@ -1,6 +1,7 @@
fsUtils = require 'fs-utils'
fs = require 'fs'
path = require 'path'
temp = require 'temp'
describe "fsUtils", ->
describe ".read(path)", ->
@@ -82,6 +83,14 @@ describe "fsUtils", ->
expect(symlinkPaths).toEqual(paths)
it "ignores missing symlinks", ->
directory = temp.mkdirSync('symlink-in-here')
paths = []
onPath = (childPath) -> paths.push(childPath)
fs.symlinkSync(path.join(directory, 'source'), path.join(directory, 'destination'))
fsUtils.traverseTreeSync(directory, onPath)
expect(paths.length).toBe 0
describe ".md5ForPath(path)", ->
it "returns the MD5 hash of the file at the given path", ->
expect(fsUtils.md5ForPath(require.resolve('fixtures/sample.js'))).toBe 'dd38087d0d7e3e4802a6d3f9b9745f2b'
+17 -11
Ver Arquivo
@@ -11,27 +11,33 @@ window.nakedLoad = (file) ->
module.exports.runSpecSuite = (specSuite, logErrors=true) ->
{$$} = require 'space-pen'
nakedLoad 'jasmine'
nakedLoad 'jasmine-console-reporter'
require 'jasmine-focused'
AtomReporter = require 'atom-reporter'
$ = require 'jquery'
TimeReporter = require 'time-reporter'
timeReporter = new TimeReporter()
reporter = if atom.getLoadSettings().exitWhenDone
new jasmine.ConsoleReporter(document, logErrors)
if atom.getLoadSettings().exitWhenDone
{jasmineNode} = require 'jasmine-node/lib/jasmine-node/reporter'
reporter = new jasmineNode.TerminalReporter
print: (args...) ->
process.stderr.write(args...)
onComplete: (runner) ->
process.stdout.write('\n')
timeReporter.logLongestSuites 10, (line) -> process.stdout.write("#{line}\n")
process.stdout.write('\n')
timeReporter.logLongestSpecs 10, (line) -> process.stdout.write("#{line}\n")
atom.exit(runner.results().failedCount > 0 ? 1 : 0)
else
new AtomReporter()
AtomReporter = require 'atom-reporter'
reporter = new AtomReporter()
require specSuite
jasmineEnv = jasmine.getEnv()
jasmineEnv.addReporter(reporter)
jasmineEnv.addReporter(timeReporter)
jasmineEnv.addReporter(new TimeReporter())
jasmineEnv.specFilter = (spec) -> reporter.specFilter(spec)
$('body').append $$ ->
@div id: 'jasmine-content'
$('body').append $$ -> @div id: 'jasmine-content'
jasmineEnv.execute()
@@ -256,6 +256,24 @@ describe "Keymap", ->
it "returns false to prevent the browser from transferring focus", ->
expect(keymap.handleKeyEvent(keydownEvent('U+0009', target: fragment[0]))).toBe false
describe ".keystrokesByCommandForSelector(selector)", ->
it "returns a hash of all commands and their keybindings", ->
keymap.bindKeys 'body', 'a': 'letter'
keymap.bindKeys '.editor', 'b': 'letter'
keymap.bindKeys '.editor', '1': 'number'
keymap.bindKeys '.editor', 'meta-alt-1': 'number-with-modifiers'
expect(keymap.keystrokesByCommandForSelector()).toEqual
'letter': ['b', 'a']
'number': ['1']
'number-with-modifiers': ['alt-meta-1']
expect(keymap.keystrokesByCommandForSelector('.editor')).toEqual
'letter': ['b']
'number': ['1']
'number-with-modifiers': ['alt-meta-1']
describe ".bindKeys(selector, bindings)", ->
it "normalizes the key patterns in the hash to put the modifiers in alphabetical order", ->
fooHandler = jasmine.createSpy('fooHandler')
@@ -1,10 +1,11 @@
{createSite} = require 'telepath'
{Site} = require 'telepath'
{View} = require 'space-pen'
PaneContainer = require 'pane-container'
Pane = require 'pane'
Environment = require 'environment'
describe "PaneContainer replication", ->
[container1, container2, pane1a, pane1b, pane1c] = []
[env1, env2, envConnection, container1, container2, pane1a, pane1b, pane1c] = []
class TestView extends View
@deserialize: ({name}) -> new TestView(name)
@@ -17,18 +18,29 @@ describe "PaneContainer replication", ->
beforeEach ->
registerDeserializer(TestView)
container1 = new PaneContainer
pane1a = new Pane(new TestView('A'))
container1.setRoot(pane1a)
pane1b = pane1a.splitRight(new TestView('B'))
pane1c = pane1b.splitDown(new TestView('C'))
doc1 = container1.getState()
doc2 = doc1.clone(createSite(2))
doc1.connect(doc2)
container2 = deserialize(doc2)
env1 = new Environment(siteId: 1)
env2 = env1.clone(siteId: 2)
envConnection = env1.connect(env2)
doc2 = null
env1.run ->
container1 = new PaneContainer
pane1a = new Pane(new TestView('A'))
container1.setRoot(pane1a)
pane1b = pane1a.splitRight(new TestView('B'))
pane1c = pane1b.splitDown(new TestView('C'))
doc1 = container1.getState()
doc2 = doc1.clone(env2.site)
envConnection.connect(doc1, doc2)
env2.run ->
container2 = deserialize(doc2)
afterEach ->
env1.destroy()
env2.destroy()
unregisterDeserializer(TestView)
it "replicates the inital state of a pane container with splits", ->
@@ -80,3 +92,17 @@ describe "PaneContainer replication", ->
expect(container1.children()).not.toExist()
expect(container2.children()).not.toExist()
# FIXME: We need to get this passing again on master
xit "replicates splitting of panes containing edit sessions", ->
env1.run ->
pane1a.showItem(project.open('dir/a'))
pane1a.splitDown()
expect(project.getBuffers().length).toBe 1
expect(container1.find('.row > :eq(0) > :eq(0)').view().activeItem.getRelativePath()).toBe 'dir/a'
expect(container1.find('.row > :eq(0) > :eq(1)').view().activeItem.getRelativePath()).toBe 'dir/a'
env2.run ->
expect(container2.find('.row > :eq(0) > :eq(0)').view().activeItem.getRelativePath()).toBe 'dir/a'
expect(container2.find('.row > :eq(0) > :eq(1)').view().activeItem.getRelativePath()).toBe 'dir/a'
@@ -109,6 +109,15 @@ describe "PaneContainer", ->
expect(container.reopenItem()).toBeFalsy()
expect(pane1.activeItem).toEqual item3
describe "when the last-closed pane item is an edit session", ->
it "reopens the edit session (regression)", ->
editSession = project.open('sample.js')
pane3.showItem(editSession)
pane3.destroyItem(editSession)
expect(container.reopenItem()).toBeTruthy()
expect(pane3.activeItem.getPath()).toBe editSession.getPath()
expect(container.reopenItem()).toBeFalsy()
describe "when there is no active pane", ->
it "attaches a new pane with the reconstructed last pane item and focuses it", ->
container.attachToDom()
@@ -140,6 +149,12 @@ describe "PaneContainer", ->
expect(container.reopenItem()).toBeFalsy()
expect(pane1.activeItem).toEqual item3
pane1.destroyItem(item3)
container.setRoot(new Pane(item3))
expect(container.reopenItem()).toBeFalsy()
expect(container.getActivePane().getItems().length).toBe 1
expect(container.getActivePaneItem()).toEqual item3
describe ".saveAll()", ->
it "saves all open pane items", ->
pane1.showItem(new TestView('4'))
@@ -1,6 +1,6 @@
PaneContainer = require 'pane-container'
Pane = require 'pane'
{createSite} = require 'telepath'
{Site} = require 'telepath'
describe "Pane replication", ->
[editSession1a, editSession1b, container1, pane1, doc1] = []
@@ -14,7 +14,7 @@ describe "Pane replication", ->
container1.setRoot(pane1)
doc1 = container1.getState()
doc2 = doc1.clone(createSite(2))
doc2 = doc1.clone(new Site(2))
doc1.connect(doc2)
container2 = deserialize(doc2)
@@ -517,6 +517,18 @@ describe "Pane", ->
expect(becameActiveHandler.callCount).toBe 1
it "triggers 'pane:became-inactive' when it was previously active", ->
becameInactiveHandler = jasmine.createSpy("becameInactiveHandler")
container.on 'pane:became-inactive', becameInactiveHandler
expect(pane.isActive()).toBeFalsy()
pane.focusin()
expect(pane.isActive()).toBeTruthy()
pane.splitRight()
expect(pane.isActive()).toBeFalsy()
expect(becameInactiveHandler.callCount).toBe 1
describe "split methods", ->
[pane1, view3, view4] = []
beforeEach ->
@@ -719,27 +731,33 @@ describe "Pane", ->
newPane = deserialize(pane.serialize())
expect(newPane.activeItem).toEqual editSession2
xit "defaults to the first item on deserialization if the active item was not serializable", ->
expect(view2.serialize?()).toBeFalsy()
it "does not show items that cannot be deserialized", ->
spyOn(console, 'warn')
pane.showItem(view2)
paneState = pane.serialize()
paneState.get('items').set(pane.items.indexOf(view2), {deserializer: 'Bogus'}) # nuke serialized state of active item
console.log pane.serialize().toObject()
newPane = deserialize(pane.serialize())
expect(newPane.activeItem).toEqual editSession1
newPane = deserialize(paneState)
expect(newPane.activeItem).toEqual pane.items[0]
expect(newPane.items.length).toBe pane.items.length - 1
it "focuses the pane after attach only if had focus when serialized", ->
container.attachToDom()
reloadContainer = ->
projectState = project.serialize()
containerState = container.serialize()
container.remove()
project.destroy()
window.project = deserialize(projectState)
container = deserialize(containerState)
pane = container.getRoot()
container.attachToDom()
container.attachToDom()
pane.focus()
state = pane.serialize()
pane.remove()
newPane = deserialize(state)
container.setRoot(newPane)
expect(newPane).toMatchSelector(':has(:focus)')
reloadContainer()
expect(pane).toMatchSelector(':has(:focus)')
$(document.activeElement).blur()
state = newPane.serialize()
newPane.remove()
newerPane = deserialize(state)
expect(newerPane).not.toMatchSelector(':has(:focus)')
reloadContainer()
expect(pane).not.toMatchSelector(':has(:focus)')
+49
Ver Arquivo
@@ -0,0 +1,49 @@
{Site} = require 'telepath'
fsUtils = require 'fs-utils'
Project = require 'project'
Git = require 'git'
describe "Project replication", ->
[doc1, doc2, project1, project2] = []
beforeEach ->
# pretend that home-1/project and home-2/project map to the same git repository url
spyOn(Git, 'open').andReturn
getOriginUrl: -> 'git://server/project.git'
destroy: ->
config.set('core.projectHome', fsUtils.resolveOnLoadPath('fixtures/replication/home-1'))
project1 = new Project(fsUtils.resolveOnLoadPath('fixtures/replication/home-1/project'))
project1.bufferForPath('file-1.txt')
project1.bufferForPath('file-1.txt')
expect(project1.getBuffers().length).toBe 1
doc1 = project1.getState()
doc2 = doc1.clone(new Site(2))
connection = doc1.connect(doc2)
# pretend we're bootstrapping a joining window
config.set('core.projectHome', fsUtils.resolveOnLoadPath('fixtures/replication/home-2'))
project2 = deserialize(doc2)
afterEach ->
project1.destroy()
project2.destroy()
it "replicates the initial path and open buffers of the project", ->
expect(project2.getPath()).not.toBe project1.getPath()
expect(project2.getBuffers().length).toBe 1
expect(project2.getBuffers()[0].getRelativePath()).toBe project1.getBuffers()[0].getRelativePath()
expect(project2.getBuffers()[0].getPath()).not.toBe project1.getBuffers()[0].getPath()
it "replicates insertion and removal of open buffers", ->
project2.bufferForPath('file-2.txt')
expect(project1.getBuffers().length).toBe 2
expect(project2.getBuffers()[0].getRelativePath()).toBe project1.getBuffers()[0].getRelativePath()
expect(project2.getBuffers()[1].getRelativePath()).toBe project1.getBuffers()[1].getRelativePath()
expect(project2.getBuffers()[0].getRelativePath()).not.toBe project1.getBuffers()[0].getPath()
expect(project2.getBuffers()[1].getRelativePath()).not.toBe project1.getBuffers()[1].getPath()
project1.removeBuffer(project1.bufferForPath('file-2.txt'))
expect(project1.getBuffers().length).toBe 1
expect(project2.getBuffers()[0].getRelativePath()).toBe project1.getBuffers()[0].getRelativePath()
@@ -8,6 +8,19 @@ describe "Project", ->
beforeEach ->
project.setPath(project.resolve('dir'))
describe "serialization", ->
deserializedProject = null
afterEach ->
deserializedProject?.destroy()
it "destroys unretained buffers and does not include them in the serialized state", ->
project.bufferForPath('a')
expect(project.getBuffers().length).toBe 1
deserializedProject = deserialize(project.serialize())
expect(deserializedProject.getBuffers().length).toBe 0
expect(project.getBuffers().length).toBe 0
describe "when an edit session is destroyed", ->
it "removes edit session and calls destroy on buffer (if buffer is not referenced by other edit sessions)", ->
editSession = project.open("a")
@@ -98,7 +111,8 @@ describe "Project", ->
describe "when passed a path that matches a custom opener", ->
it "returns the resource returned by the custom opener", ->
expect(project.open("a.foo", hey: "there")).toEqual { foo: "a.foo", options: {hey: "there"} }
pathToOpen = project.resolve('a.foo')
expect(project.open(pathToOpen, hey: "there")).toEqual { foo: pathToOpen, options: {hey: "there"} }
expect(project.open("bar://baz")).toEqual { bar: "bar://baz" }
describe ".bufferForPath(path)", ->
@@ -22,6 +22,15 @@ describe "RootView", ->
describe "@deserialize()", ->
viewState = null
refreshRootViewAndProject = ->
rootViewState = rootView.serialize()
projectState = project.serialize()
rootView.remove()
project.destroy()
window.project = deserialize(projectState)
window.rootView = deserialize(rootViewState)
rootView.attachToDom()
describe "when the serialized RootView has an unsaved buffer", ->
it "constructs the view with the same panes", ->
rootView.attachToDom()
@@ -29,14 +38,12 @@ describe "RootView", ->
editor1 = rootView.getActiveView()
buffer = editor1.getBuffer()
editor1.splitRight()
viewState = rootView.serialize()
rootView.remove()
expect(rootView.getActiveView()).toBe rootView.getEditors()[1]
window.rootView = deserialize(viewState)
rootView.attachToDom()
refreshRootViewAndProject()
expect(rootView.getEditors().length).toBe 2
expect(rootView.getActiveView().getText()).toBe buffer.getText()
expect(rootView.getActiveView()).toBe rootView.getEditors()[1]
expect(rootView.title).toBe "untitled - #{project.getPath()}"
describe "when there are open editors", ->
@@ -53,10 +60,7 @@ describe "RootView", ->
pane4.activeItem.setCursorScreenPosition([0, 2])
pane2.focus()
viewState = rootView.serialize()
rootView.remove()
window.rootView = deserialize(viewState)
rootView.attachToDom()
refreshRootViewAndProject()
expect(rootView.getEditors().length).toBe 4
editor1 = rootView.panes.find('.row > .pane .editor:eq(0)').view()
@@ -89,12 +93,7 @@ describe "RootView", ->
it "constructs the view with no open editors", ->
rootView.getActivePane().remove()
expect(rootView.getEditors().length).toBe 0
viewState = rootView.serialize()
rootView.remove()
window.rootView = deserialize(viewState)
rootView.attachToDom()
refreshRootViewAndProject()
expect(rootView.getEditors().length).toBe 0
describe "focus", ->
@@ -366,11 +365,3 @@ describe "RootView", ->
rootView.open(require.resolve('fixtures/sample.txt'))
expect(count).toBe 1
expect(callbackBuffer).toBe rootView.getActiveView().getBuffer()
describe "when a 'new-editor' event is triggered", ->
it "opens a new untitled editor", ->
itemCount = rootView.getActivePane().getItems().length
rootView.trigger 'new-editor'
expect(rootView.getActivePaneItem().getPath()).toBeUndefined()
expect(rootView.getActivePaneItem().getBuffer().fileExists()).toBeFalsy()
expect(rootView.getActivePane().getItems().length).toBe itemCount + 1
@@ -172,6 +172,13 @@ describe "RowMap", ->
expect(map.bufferRowRangeForScreenRow(7)).toEqual [21, 22]
expect(map.bufferRowRangeForScreenRow(8)).toEqual [22, 27]
it "replaces regions that cover 0 buffer rows at the start or end of the buffer row range", ->
map.mapBufferRowRange(0, 0, 1)
map.mapBufferRowRange(0, 1, 1)
map.mapBufferRowRange(1, 1, 1)
map.mapBufferRowRange(0, 1, 3)
expect(map.screenRowRangeForBufferRow(0)).toEqual [0, 3]
describe "when the row range straddles existing regions", ->
it "splits the straddled regions and places the new region between them", ->
# filler region 0
@@ -1,12 +1,10 @@
Buffer = require 'text-buffer'
EditSession = require 'edit-session'
Range = require 'range'
describe "Selection", ->
[buffer, editSession, selection] = []
beforeEach ->
buffer = new Buffer(require.resolve('fixtures/sample.js'))
buffer = project.buildBuffer('sample.js')
editSession = new EditSession(buffer: buffer, tabLength: 2)
selection = editSession.getSelection()
@@ -16,18 +14,18 @@ describe "Selection", ->
describe ".deleteSelectedText()", ->
describe "when nothing is selected", ->
it "deletes nothing", ->
selection.setBufferRange new Range([0,3], [0,3])
selection.setBufferRange [[0,3], [0,3]]
selection.deleteSelectedText()
expect(buffer.lineForRow(0)).toBe "var quicksort = function () {"
describe "when one line is selected", ->
it "deletes selected text and clears the selection", ->
selection.setBufferRange new Range([0,4], [0,14])
selection.setBufferRange [[0,4], [0,14]]
selection.deleteSelectedText()
expect(buffer.lineForRow(0)).toBe "var = function () {"
endOfLine = buffer.lineForRow(0).length
selection.setBufferRange new Range([0,0], [0, endOfLine])
selection.setBufferRange [[0,0], [0, endOfLine]]
selection.deleteSelectedText()
expect(buffer.lineForRow(0)).toBe ""
@@ -35,7 +33,7 @@ describe "Selection", ->
describe "when multiple lines are selected", ->
it "deletes selected text and clears the selection", ->
selection.setBufferRange new Range([0,1], [2,39])
selection.setBufferRange [[0,1], [2,39]]
selection.deleteSelectedText()
expect(buffer.lineForRow(0)).toBe "v;"
expect(selection.isEmpty()).toBeTruthy()
@@ -60,7 +58,7 @@ describe "Selection", ->
describe "when only the selection's tail is moved (regression)", ->
it "emits the 'screen-range-changed' event", ->
selection.setBufferRange([[2, 0], [2, 10]], reverse: true)
selection.setBufferRange([[2, 0], [2, 10]], isReversed: true)
changeScreenRangeHandler = jasmine.createSpy('changeScreenRangeHandler')
selection.on 'screen-range-changed', changeScreenRangeHandler
+1 -9
Ver Arquivo
@@ -7,7 +7,7 @@ $ = jQuery = require 'jquery'
_ = require 'underscore'
Keymap = require 'keymap'
Config = require 'config'
Point = require 'point'
{Point} = require 'telepath'
Project = require 'project'
Directory = require 'directory'
File = require 'file'
@@ -16,7 +16,6 @@ TokenizedBuffer = require 'tokenized-buffer'
fsUtils = require 'fs-utils'
pathwatcher = require 'pathwatcher'
RootView = require 'root-view'
Git = require 'git'
clipboard = require 'clipboard'
requireStylesheet "jasmine"
fixturePackagesPath = fsUtils.resolveOnLoadPath('fixtures/packages')
@@ -36,10 +35,6 @@ jasmine.getEnv().defaultTimeoutInterval = 5000
beforeEach ->
jQuery.fx.off = true
window.project = new Project(fsUtils.resolveOnLoadPath('fixtures'))
window.git = Git.open(project.getPath())
window.project.on 'path-changed', ->
window.git?.destroy()
window.git = Git.open(window.project.getPath())
window.resetTimeouts()
atom.packageStates = {}
@@ -88,9 +83,6 @@ afterEach ->
if project?
project.destroy()
window.project = null
if git?
git.destroy()
window.git = null
$('#jasmine-content').empty() unless window.debugContent
delete atom.windowState
jasmine.unspy(atom, 'saveWindowState')
+38 -9
Ver Arquivo
@@ -1,18 +1,47 @@
require 'window'
measure 'spec suite require time', ->
fs = require 'fs'
fsUtils = require 'fs-utils'
path = require 'path'
_ = require 'underscore'
require 'spec-helper'
# Run core specs
for specPath in fsUtils.listTreeSync(fsUtils.resolveOnLoadPath("spec")) when /-spec\.coffee$/.test specPath
require specPath
requireSpecs = (directoryPath, specType) ->
for specPath in fsUtils.listTreeSync(path.join(directoryPath, 'spec')) when /-spec\.coffee$/.test specPath
require specPath
spec.coreSpec = true for spec in jasmine.getEnv().currentRunner().specs()
setSpecType = (specType) ->
for spec in jasmine.getEnv().currentRunner().specs() when not spec.specType?
spec.specType = specType
# Run extension specs
for packageDirPath in config.packageDirPaths
for packagePath in fsUtils.listSync(packageDirPath)
for specPath in fsUtils.listTreeSync(path.join(packagePath, "spec")) when /-spec\.coffee$/.test specPath
require specPath
runAllSpecs = ->
requireSpecs(window.resourcePath)
setSpecType('core')
fixturesPackagesPath = fsUtils.resolveOnLoadPath('fixtures/packages')
packagePaths = atom.getAvailablePackageNames().map (packageName) -> atom.resolvePackagePath(packageName)
packagePaths = _.groupBy packagePaths, (packagePath) ->
if packagePath.indexOf("#{fixturesPackagesPath}#{path.sep}") is 0
'fixtures'
else if packagePath.indexOf("#{window.resourcePath}#{path.sep}") is 0
'bundled'
else
'user'
# Run bundled package specs
requireSpecs(packagePath) for packagePath in packagePaths.bundled ? []
setSpecType('bundled')
# Run user package specs
requireSpecs(packagePath) for packagePath in packagePaths.user ? []
setSpecType('user')
runSpecs = (specPath) ->
requireSpecs(specPath)
setSpecType("user")
if specPath = atom.getLoadSettings().specPath
runSpecs(specPath)
else
runAllSpecs()
+41
Ver Arquivo
@@ -0,0 +1,41 @@
{Site} = require 'telepath'
describe "TextBuffer replication", ->
[buffer1, buffer2] = []
beforeEach ->
buffer1 = project.buildBuffer('sample.js')
buffer1.insert([0, 0], 'changed\n')
doc1 = buffer1.getState()
doc2 = doc1.clone(new Site(2))
doc1.connect(doc2)
buffer2 = deserialize(doc2, {project})
afterEach ->
buffer1.destroy()
buffer2.destroy()
it "replicates the initial path and text", ->
expect(buffer2.getPath()).toBe buffer1.getPath()
expect(buffer2.getText()).toBe buffer1.getText()
it "replicates changes to the text and emits 'change' events on all replicas", ->
buffer1.on 'changed', handler1 = jasmine.createSpy("buffer1 change handler")
buffer2.on 'changed', handler2 = jasmine.createSpy("buffer2 change handler")
buffer1.change([[1, 4], [1, 6]], 'h')
expect(buffer1.lineForRow(1)).toBe 'var hicksort = function () {'
expect(buffer2.lineForRow(1)).toBe 'var hicksort = function () {'
expect(buffer1.isModified()).toBeTruthy()
expect(buffer2.isModified()).toBeTruthy()
expectedEvent =
oldRange: [[1, 4], [1, 6]]
oldText: "qu"
newRange: [[1, 4], [1, 5]]
newText: "h"
expect(handler1).toHaveBeenCalledWith(expectedEvent)
expect(handler2).toHaveBeenCalledWith(expectedEvent)
expect(handler1.callCount).toBe 1
expect(handler2.callCount).toBe 1
@@ -3,6 +3,7 @@ Buffer = require 'text-buffer'
fsUtils = require 'fs-utils'
path = require 'path'
_ = require 'underscore'
{Site} = require 'telepath'
describe 'TextBuffer', ->
[filePath, fileContents, buffer] = []
@@ -27,10 +28,11 @@ describe 'TextBuffer', ->
buffer = project.bufferForPath(filePath)
expect(buffer.getText()).toBe fsUtils.read(filePath)
it "is not modified and has no undo history", ->
it "does not allow the initial state of the buffer to be undone", ->
filePath = require.resolve 'fixtures/sample.txt'
buffer = project.bufferForPath(filePath)
expect(buffer.isModified()).toBeFalsy()
expect(buffer.undoManager.undoHistory.length).toBe 0
buffer.undo()
expect(buffer.getText()).toBe fsUtils.read(filePath)
describe "when no file exists for the path", ->
it "is modified and is initially empty", ->
@@ -419,7 +421,7 @@ describe 'TextBuffer', ->
expect(event.newText).toBe "foo\nbar"
it "allows a 'changed' event handler to safely undo the change", ->
buffer.on 'changed', -> buffer.undo()
buffer.one 'changed', -> buffer.undo()
buffer.change([0, 0], "hello")
expect(buffer.lineForRow(0)).toBe "var quicksort = function () {"
@@ -541,6 +543,35 @@ describe 'TextBuffer', ->
waitsFor ->
changeHandler.callCount > 0
describe ".getRelativePath()", ->
[filePath, newPath, bufferToChange, eventHandler] = []
beforeEach ->
filePath = path.join(fsUtils.resolveOnLoadPath("fixtures"), "atom-manipulate-me")
newPath = "#{filePath}-i-moved"
fsUtils.writeSync(filePath, "")
bufferToChange = project.bufferForPath(filePath)
eventHandler = jasmine.createSpy('eventHandler')
bufferToChange.on 'path-changed', eventHandler
afterEach ->
bufferToChange.destroy()
fsUtils.remove(filePath) if fsUtils.exists(filePath)
fsUtils.remove(newPath) if fsUtils.exists(newPath)
it "updates when the text buffer's file is moved", ->
expect(bufferToChange.getRelativePath()).toBe('atom-manipulate-me')
jasmine.unspy(window, "setTimeout")
eventHandler.reset()
fsUtils.move(filePath, newPath)
waitsFor "buffer path change", ->
eventHandler.callCount > 0
runs ->
expect(bufferToChange.getRelativePath()).toBe('atom-manipulate-me-i-moved')
describe ".getTextInRange(range)", ->
describe "when range is empty", ->
it "returns an empty string", ->
@@ -782,421 +813,6 @@ describe 'TextBuffer', ->
expect(buffer.positionForCharacterIndex(13)).toEqual [2, 0]
expect(buffer.positionForCharacterIndex(20)).toEqual [3, 0]
describe "markers", ->
markerCreatedHandler = null
beforeEach ->
buffer.on('marker-created', markerCreatedHandler = jasmine.createSpy("markerCreatedHandler"))
describe "marker creation", ->
it "allows markers to be created with ranges and positions", ->
marker1 = buffer.markRange([[4, 20], [4, 23]])
expect(marker1.getRange()).toEqual [[4, 20], [4, 23]]
expect(marker1.getHeadPosition()).toEqual [4, 23]
expect(marker1.getTailPosition()).toEqual [4, 20]
marker2 = buffer.markPosition([4, 20])
expect(marker2.getRange()).toEqual [[4, 20], [4, 20]]
expect(marker2.getHeadPosition()).toEqual [4, 20]
expect(marker2.getTailPosition()).toEqual [4, 20]
it "allows markers to be created in a reversed orientation", ->
marker = buffer.markRange([[4, 20], [4, 23]], reverse: true)
expect(marker.isReversed()).toBeTruthy()
expect(marker.getRange()).toEqual [[4, 20], [4, 23]]
expect(marker.getHeadPosition()).toEqual [4, 20]
expect(marker.getTailPosition()).toEqual [4, 23]
it "emits the 'marker-created' event when markers are created", ->
marker = buffer.markRange([[4, 20], [4, 23]])
expect(markerCreatedHandler).toHaveBeenCalledWith(marker)
describe "marker manipulation", ->
marker = null
beforeEach ->
marker = buffer.markRange([[4, 20], [4, 23]])
it "allows a marker's head and tail positions to be changed", ->
marker.setHeadPosition([5, 3])
expect(marker.getRange()).toEqual [[4, 20], [5, 3]]
marker.setTailPosition([6, 3])
expect(marker.getRange()).toEqual [[5, 3], [6, 3]]
expect(marker.isReversed()).toBeTruthy()
it "clips head and tail positions to ensure they are in bounds", ->
marker.setHeadPosition([-100, -5])
expect(marker.getRange()).toEqual([[0, 0], [4, 20]])
marker.setTailPosition([Infinity, Infinity])
expect(marker.getRange()).toEqual([[0, 0], [12, 2]])
it "allows a marker's tail to be placed and cleared", ->
marker.clearTail()
expect(marker.getRange()).toEqual [[4, 23], [4, 23]]
marker.placeTail()
marker.setHeadPosition([2, 0])
expect(marker.getRange()).toEqual [[2, 0], [4, 23]]
expect(marker.isReversed()).toBeTruthy()
it "returns whether the position changed", ->
expect(marker.setHeadPosition([5, 3])).toBeTruthy()
expect(marker.setHeadPosition([5, 3])).toBeFalsy()
expect(marker.setTailPosition([6, 3])).toBeTruthy()
expect(marker.setTailPosition([6, 3])).toBeFalsy()
describe "change events", ->
[changedHandler, marker] = []
beforeEach ->
marker = buffer.markRange([[4, 20], [4, 23]])
marker.on 'changed', changedHandler = jasmine.createSpy("changedHandler")
it "triggers 'changed' events when the marker's head position changes", ->
marker.setHeadPosition([6, 2])
expect(changedHandler).toHaveBeenCalled()
expect(changedHandler.argsForCall[0][0]).toEqual {
oldHeadPosition: [4, 23]
newHeadPosition: [6, 2]
oldTailPosition: [4, 20]
newTailPosition: [4, 20]
bufferChanged: false
valid: true
}
changedHandler.reset()
buffer.insert([6, 0], '...')
expect(changedHandler.argsForCall[0][0]).toEqual {
oldTailPosition: [4, 20]
newTailPosition: [4, 20]
oldHeadPosition: [6, 2]
newHeadPosition: [6, 5]
bufferChanged: true
valid: true
}
it "calls the given callback when the marker's tail position changes", ->
marker.setTailPosition([6, 2])
expect(changedHandler).toHaveBeenCalled()
expect(changedHandler.argsForCall[0][0]).toEqual {
oldHeadPosition: [4, 23]
newHeadPosition: [4, 23]
oldTailPosition: [4, 20]
newTailPosition: [6, 2]
bufferChanged: false
valid: true
}
changedHandler.reset()
buffer.insert([6, 0], '...')
expect(changedHandler.argsForCall[0][0]).toEqual {
oldHeadPosition: [4, 23]
newHeadPosition: [4, 23]
oldTailPosition: [6, 2]
newTailPosition: [6, 5]
bufferChanged: true
valid: true
}
it "triggers 'changed' events when the selection's tail is cleared", ->
marker.clearTail()
expect(changedHandler).toHaveBeenCalled()
expect(changedHandler.argsForCall[0][0]).toEqual {
oldHeadPosition: [4, 23]
newHeadPosition: [4, 23]
oldTailPosition: [4, 20]
newTailPosition: [4, 23]
bufferChanged: false
valid: true
}
it "only triggers 'changed' events once when both the marker's head and tail positions change due to the same operation", ->
buffer.insert([4, 0], '...')
expect(changedHandler.callCount).toBe 1
expect(changedHandler.argsForCall[0][0]).toEqual {
oldTailPosition: [4, 20]
newTailPosition: [4, 23]
oldHeadPosition: [4, 23]
newHeadPosition: [4, 26]
bufferChanged: true
valid: true
}
changedHandler.reset()
marker.setRange([[0, 0], [1, 1]])
expect(changedHandler.callCount).toBe 1
expect(changedHandler.argsForCall[0][0]).toEqual {
oldTailPosition: [4, 23]
newTailPosition: [0, 0]
oldHeadPosition: [4, 26]
newHeadPosition: [1, 1]
bufferChanged: false
valid: true
}
it "triggers 'changed' events with the valid flag set to false when the marker is invalidated", ->
buffer.deleteRow(4)
expect(changedHandler.callCount).toBe 1
expect(changedHandler.argsForCall[0][0]).toEqual {
oldTailPosition: [4, 20]
newTailPosition: [4, 20]
oldHeadPosition: [4, 23]
newHeadPosition: [4, 23]
bufferChanged: true
valid: false
}
changedHandler.reset()
buffer.undo()
expect(changedHandler.callCount).toBe 1
expect(changedHandler.argsForCall[0][0]).toEqual {
oldTailPosition: [4, 20]
newTailPosition: [4, 20]
oldHeadPosition: [4, 23]
newHeadPosition: [4, 23]
bufferChanged: true
valid: true
}
describe ".findMarkers(attributes)", ->
[marker1, marker2, marker3, marker4] = []
beforeEach ->
marker1 = buffer.markRange([[0, 0], [3, 0]], class: 'a')
marker2 = buffer.markRange([[0, 0], [5, 0]], class: 'a')
marker3 = buffer.markRange([[6, 0], [7, 0]], class: 'a')
marker4 = buffer.markRange([[9, 0], [10, 0]], class: 'b')
it "returns the markers matching the given attributes, sorted by the buffer location and size of their ranges", ->
expect(buffer.findMarkers(class: 'a')).toEqual [marker2, marker1, marker3]
it "allows the startRow and endRow to be specified", ->
expect(buffer.findMarkers(class: 'a', startRow: 0)).toEqual [marker2, marker1]
expect(buffer.findMarkers(class: 'a', startRow: 0, endRow: 3)).toEqual [marker1]
expect(buffer.findMarkers(endRow: 10)).toEqual [marker4]
describe "marker destruction", ->
marker = null
beforeEach ->
marker = buffer.markRange([[4, 20], [4, 23]])
it "allows a marker to be destroyed", ->
marker.destroy()
expect(buffer.getMarker(marker.id)).toBeUndefined()
it "does not restore invalidated markers that have been destroyed", ->
buffer.delete([[4, 15], [4, 25]])
expect(buffer.getMarker(marker.id)).toBeUndefined()
marker.destroy()
buffer.undo()
expect(buffer.getMarker(marker.id)).toBeUndefined()
# even "invalidationStrategy: never" markers get destroyed properly
marker2 = buffer.markRange([[4, 20], [4, 23]], invalidationStrategy: 'never')
buffer.delete([[4, 15], [4, 25]])
marker2.destroy()
buffer.undo()
expect(buffer.getMarker(marker2.id)).toBeUndefined()
it "emits 'destroyed' on the marker when it is destroyed", ->
marker.on 'destroyed', destroyedHandler = jasmine.createSpy("destroyedHandler")
marker.destroy()
expect(destroyedHandler).toHaveBeenCalled()
describe "marker updates due to buffer changes", ->
[marker1, marker2, marker3] = []
beforeEach ->
marker1 = buffer.markRange([[4, 20], [4, 23]])
marker2 = buffer.markRange([[4, 20], [4, 23]], invalidationStrategy: 'never')
marker3 = buffer.markRange([[4, 20], [4, 23]], invalidationStrategy: 'between')
describe "when the buffer changes due to a new operation", ->
describe "when the change precedes the marker range", ->
it "moves the marker", ->
buffer.insert([4, 5], '...')
expect(marker1.getRange()).toEqual [[4, 23], [4, 26]]
buffer.delete([[4, 5], [4, 8]])
expect(marker1.getRange()).toEqual [[4, 20], [4, 23]]
buffer.insert([0, 0], '\nhi\n')
expect(marker1.getRange()).toEqual [[6, 20], [6, 23]]
# undo works
buffer.undo()
expect(marker1.getRange()).toEqual [[4, 20], [4, 23]]
buffer.undo()
expect(marker1.getRange()).toEqual [[4, 23], [4, 26]]
it "restores the marker range exactly on undo", ->
marker = buffer.markRange([[3, 0], [3, 62]])
buffer.delete([[2, 0], [3, 0]])
expect(marker.getRange()).toEqual [[2, 0], [2, 62]]
buffer.undo()
expect(marker.getRange()).toEqual [[3, 0], [3, 62]]
describe "when the change follows the marker range", ->
it "does not move the marker", ->
buffer.insert([6, 5], '...')
expect(marker1.getRange()).toEqual [[4, 20], [4, 23]]
buffer.delete([[6, 5], [6, 8]])
expect(marker1.getRange()).toEqual [[4, 20], [4, 23]]
buffer.insert([10, 0], '\nhi\n')
expect(marker1.getRange()).toEqual [[4, 20], [4, 23]]
describe "when the change is an insertion at the start of the marker range", ->
it "does not move the start point, but does move the end point", ->
buffer.insert([4, 20], '...')
expect(marker1.getRange()).toEqual [[4, 20], [4, 26]]
describe "when the invalidation strategy is 'between'", ->
it "invalidates the marker", ->
buffer.insert([4, 20], '...')
expect(marker3.isValid()).toBeFalsy()
describe "when the change is an insertion at the end of the marker range", ->
it "moves the end point", ->
buffer.insert([4, 23], '...')
expect(marker1.getRange()).toEqual [[4, 20], [4, 26]]
describe "when the invalidation strategy is 'between'", ->
it "invalidates the marker", ->
buffer.insert([4, 23], '...')
expect(marker3.isValid()).toBeFalsy()
describe "when the change surrounds the marker range", ->
describe "when the marker's invalidation strategy is 'contains' (the default)", ->
it "invalidates the marker", ->
buffer.delete([[4, 15], [4, 25]])
expect(marker1.isValid()).toBeFalsy()
buffer.undo()
expect(marker1.isValid()).toBeTruthy()
expect(marker1.getRange()).toEqual [[4, 20], [4, 23]]
describe "when the marker's invalidation strategy is 'between'", ->
it "invalidates the marker", ->
buffer.delete([[4, 15], [4, 25]])
expect(marker3.isValid()).toBeFalsy()
buffer.undo()
expect(marker3.isValid()).toBeTruthy()
expect(marker3.getRange()).toEqual [[4, 20], [4, 23]]
describe "when the marker's invalidation strategy is 'never'", ->
it "does not invalidate the marker, but sets it to an empty range at the end of the change", ->
buffer.change([[4, 15], [4, 25]], "...")
expect(marker2.isValid()).toBeTruthy()
expect(marker2.getRange()).toEqual [[4, 18], [4, 18]]
buffer.undo()
expect(marker2.isValid()).toBeTruthy()
expect(marker2.getRange()).toEqual [[4, 20], [4, 23]]
describe "when the change straddles the start of the marker range", ->
describe "when the marker's invalidation strategy is 'contains' (the default)", ->
it "invalidates the marker", ->
buffer.delete([[4, 15], [4, 22]])
expect(marker1.isValid()).toBeFalsy()
buffer.undo()
expect(marker1.isValid()).toBeTruthy()
expect(marker1.getRange()).toEqual [[4, 20], [4, 23]]
describe "when the marker's invalidation strategy is 'between'", ->
it "invalidates the marker", ->
buffer.delete([[4, 15], [4, 22]])
expect(marker3.isValid()).toBeFalsy()
buffer.undo()
expect(marker3.isValid()).toBeTruthy()
expect(marker3.getRange()).toEqual [[4, 20], [4, 23]]
describe "when the marker's invalidation strategy is 'never'", ->
it "moves the start of the marker range to the end of the change", ->
buffer.delete([[4, 15], [4, 22]])
expect(marker2.isValid()).toBeTruthy()
expect(marker2.getRange()).toEqual [[4, 15], [4, 16]]
buffer.undo()
expect(marker2.isValid()).toBeTruthy()
expect(marker2.getRange()).toEqual [[4, 20], [4, 23]]
describe "when the change straddles the end of the marker range", ->
describe "when the marker's invalidation strategy is 'contains' (the default)", ->
it "invalidates the marker", ->
buffer.delete([[4, 22], [4, 25]])
expect(marker1.isValid()).toBeFalsy()
buffer.undo()
expect(marker1.isValid()).toBeTruthy()
expect(marker1.getRange()).toEqual [[4, 20], [4, 23]]
describe "when the marker's invalidation strategy is 'between'", ->
it "invalidates the marker", ->
buffer.delete([[4, 22], [4, 25]])
expect(marker3.isValid()).toBeFalsy()
buffer.undo()
expect(marker3.isValid()).toBeTruthy()
expect(marker3.getRange()).toEqual [[4, 20], [4, 23]]
describe "when the marker's invalidation strategy is 'never'", ->
it "moves the end of the marker range to the start of the change", ->
buffer.delete([[4, 22], [4, 25]])
expect(marker2.isValid()).toBeTruthy()
expect(marker2.getRange()).toEqual [[4, 20], [4, 22]]
buffer.undo()
expect(marker2.isValid()).toBeTruthy()
expect(marker2.getRange()).toEqual [[4, 20], [4, 23]]
describe "when the change is between the start and the end of the marker range", ->
describe "when the marker's invalidation strategy is 'contains' (the default)", ->
it "does not invalidate the marker", ->
buffer.insert([4, 21], 'x')
expect(marker1.isValid()).toBeTruthy()
expect(marker1.getRange()).toEqual [[4, 20], [4, 24]]
buffer.undo()
expect(marker1.isValid()).toBeTruthy()
expect(marker1.getRange()).toEqual [[4, 20], [4, 23]]
describe "when the marker's invalidation strategy is 'between'", ->
it "invalidates the marker", ->
buffer.insert([4, 21], 'x')
expect(marker3.isValid()).toBeFalsy()
buffer.undo()
expect(marker3.isValid()).toBeTruthy()
expect(marker3.getRange()).toEqual [[4, 20], [4, 23]]
describe "when the marker's invalidation strategy is 'never'", ->
it "moves the end of the marker range to the start of the change", ->
buffer.insert([4, 21], 'x')
expect(marker2.isValid()).toBeTruthy()
expect(marker2.getRange()).toEqual [[4, 20], [4, 24]]
buffer.undo()
expect(marker2.isValid()).toBeTruthy()
expect(marker2.getRange()).toEqual [[4, 20], [4, 23]]
describe "when the buffer changes due to the undo or redo of a previous operation", ->
it "restores invalidated markers when undoing/redoing in the other direction", ->
buffer.change([[4, 21], [4, 24]], "foo")
expect(marker1.isValid()).toBeFalsy()
marker3 = buffer.markRange([[4, 20], [4, 23]])
buffer.undo()
expect(marker1.isValid()).toBeTruthy()
expect(marker1.getRange()).toEqual [[4, 20], [4, 23]]
expect(marker3.isValid()).toBeFalsy()
marker4 = buffer.markRange([[4, 20], [4, 23]])
buffer.redo()
expect(marker3.isValid()).toBeTruthy()
expect(marker3.getRange()).toEqual [[4, 20], [4, 23]]
expect(marker4.isValid()).toBeFalsy()
buffer.undo()
expect(marker4.isValid()).toBeTruthy()
expect(marker4.getRange()).toEqual [[4, 20], [4, 23]]
describe ".markersForPosition(position)", ->
it "returns all markers that intersect the given position", ->
m1 = buffer.markRange([[3, 4], [3, 10]])
m2 = buffer.markRange([[3, 4], [3, 5]])
m3 = buffer.markPosition([3, 5])
expect(_.difference(buffer.markersForPosition([3, 5]), [m1, m2, m3]).length).toBe 0
expect(_.difference(buffer.markersForPosition([3, 4]), [m1, m2]).length).toBe 0
expect(_.difference(buffer.markersForPosition([3, 10]), [m1]).length).toBe 0
describe ".usesSoftTabs()", ->
it "returns true if the first indented line begins with tabs", ->
buffer.setText("function() {\n foo();\n}")
@@ -1254,20 +870,6 @@ describe 'TextBuffer', ->
expect(buffer.getText()).toBe "ab\nc"
describe "line ending support", ->
describe ".lineEndingForRow(line)", ->
it "return the line ending for each buffer line", ->
buffer.setText("a\r\nb\nc")
expect(buffer.lineEndingForRow(0)).toBe '\r\n'
expect(buffer.lineEndingForRow(1)).toBe '\n'
expect(buffer.lineEndingForRow(2)).toBeUndefined()
describe ".lineForRow(line)", ->
it "returns the line text without the line ending for both lf and crlf lines", ->
buffer.setText("a\r\nb\nc")
expect(buffer.lineForRow(0)).toBe 'a'
expect(buffer.lineForRow(1)).toBe 'b'
expect(buffer.lineForRow(2)).toBe 'c'
describe ".getText()", ->
it "returns the text with the corrent line endings for each row", ->
buffer.setText("a\r\nb\nc")
@@ -1285,7 +887,7 @@ describe 'TextBuffer', ->
describe "when the current line has a line ending", ->
it "uses the same line ending as the line where the text is inserted", ->
buffer.setText("a\r\n")
buffer.insert([0,1], "hello\n1\n\n2")
buffer.insert([0, 1], "hello\n1\n\n2")
expect(buffer.getText()).toBe "ahello\r\n1\r\n\r\n2\r\n"
describe "when the current line has no line ending (because it's the last line of the buffer)", ->
@@ -1301,60 +903,72 @@ describe 'TextBuffer', ->
buffer.append("hello\n1\r\n2\n")
expect(buffer.getText()).toBe "\ninitialtexthello\n1\n2\n"
describe ".clipPosition(position)", ->
describe "when the position is before the start of the buffer", ->
it "returns the first position in the buffer", ->
expect(buffer.clipPosition([-1,0])).toEqual [0,0]
expect(buffer.clipPosition([0,-1])).toEqual [0,0]
expect(buffer.clipPosition([-1,-1])).toEqual [0,0]
describe "when the position is after the end of the buffer", ->
it "returns the last position in the buffer", ->
buffer.setText('some text')
expect(buffer.clipPosition([1, 0])).toEqual [0,9]
expect(buffer.clipPosition([0,10])).toEqual [0,9]
expect(buffer.clipPosition([10,Infinity])).toEqual [0,9]
describe "serialization", ->
serializedState = null
buffer2 = null
reloadBuffer = ->
serializedState = buffer.serialize()
buffer.release()
buffer = Buffer.deserialize(serializedState)
afterEach ->
buffer2?.release()
describe "when the serialized buffer had no unsaved changes", ->
it "loads the current contents of the file at the serialized path", ->
path = buffer.getPath()
text = buffer.getText()
reloadBuffer()
expect(serializedState.text).toBeUndefined()
expect(buffer.getPath()).toBe(path)
expect(buffer.getText()).toBe(text)
expect(buffer.isModified()).toBeFalsy()
state = buffer.serialize()
state.get('text').insert([0, 0], 'simulate divergence of on-disk contents from serialized contents')
buffer2 = deserialize(state, {project})
expect(buffer2.isModified()).toBeFalsy()
expect(buffer2.getPath()).toBe(buffer.getPath())
expect(buffer2.getText()).toBe(buffer.getText())
describe "when the serialized buffer had unsaved changes", ->
it "restores the previous unsaved state of the buffer", ->
path = buffer.getPath()
previousText = buffer.getText()
buffer.setText("abc")
reloadBuffer()
expect(serializedState.text).toBe "abc"
expect(buffer.getPath()).toBe(path)
expect(buffer.getText()).toBe("abc")
buffer.setText(previousText)
expect(buffer.isModified()).toBeFalsy()
state = buffer.serialize()
expect(state.getObject('text')).toBe 'abc'
buffer2 = deserialize(state, {project})
expect(buffer2.getPath()).toBe(buffer.getPath())
expect(buffer2.getText()).toBe(buffer.getText())
expect(buffer2.isModified()).toBeTruthy()
buffer2.setText(previousText)
expect(buffer2.isModified()).toBeFalsy()
describe "when the serialized buffer was unsaved and had no path", ->
it "restores the previous unsaved state of the buffer", ->
buffer.setPath(undefined)
buffer.setText("abc")
reloadBuffer()
expect(serializedState.path).toBeUndefined()
expect(buffer.getPath()).toBeUndefined()
expect(buffer.getText()).toBe("abc")
it "never deserializes two separate instances of the same buffer", ->
serializedState = buffer.serialize()
buffer.release()
buffer = Buffer.deserialize(serializedState)
expect(Buffer.deserialize(serializedState)).toBe buffer
state = buffer.serialize()
expect(state.get('path')).toBeUndefined()
expect(state.getObject('text')).toBe 'abc'
buffer2 = deserialize(state)
expect(buffer2.getPath()).toBeUndefined()
expect(buffer2.getText()).toBe("abc")
describe "when the buffer has remote markers", ->
[buffer2, buffer3] = []
afterEach ->
buffer2.destroy()
buffer3.destroy()
it "does not include them in the serialized state", ->
doc1 = buffer.getState()
doc2 = doc1.clone(new Site(2))
doc1.connect(doc2)
buffer2 = deserialize(doc2, {project})
buffer.markPosition [1, 0]
buffer2.markPosition [2, 0]
expect(buffer.getMarkerCount()).toBe 2
expect(buffer.getMarkers()[0].isRemote()).toBe false
expect(buffer.getMarkers()[1].isRemote()).toBe true
buffer3 = deserialize(buffer.serialize(), {project})
expect(buffer3.getMarkerCount()).toBe 1
expect(buffer3.getMarkers()[0].isRemote()).toBe false
expect(buffer3.getMarkers()[0].getRange()).toEqual [[1, 0], [1, 0]]
@@ -14,6 +14,7 @@ describe "TextMateGrammar", ->
atom.activatePackage('ruby-tmbundle', sync: true)
atom.activatePackage('html-tmbundle', sync: true)
atom.activatePackage('php-tmbundle', sync: true)
atom.activatePackage('python-tmbundle', sync: true)
grammar = syntax.selectGrammar("hello.coffee")
describe "@loadSync(path)", ->
@@ -661,3 +662,26 @@ describe "TextMateGrammar", ->
expect(tokens[0].value).toBe "'"
expect(tokens[1].value).toBe "\uD835\uDF97"
expect(tokens[2].value).toBe "'"
describe "python", ->
it "parses import blocks correctly", ->
grammar = syntax.selectGrammar("file.py")
lines = grammar.tokenizeLines "import a\nimport b"
line1 = lines[0]
expect(line1.length).toBe 3
expect(line1[0].value).toEqual "import"
expect(line1[0].scopes).toEqual ["source.python", "keyword.control.import.python"]
expect(line1[1].value).toEqual " "
expect(line1[1].scopes).toEqual ["source.python"]
expect(line1[2].value).toEqual "a"
expect(line1[2].scopes).toEqual ["source.python"]
line2 = lines[1]
expect(line2.length).toBe 3
expect(line2[0].value).toEqual "import"
expect(line2[0].scopes).toEqual ["source.python", "keyword.control.import.python"]
expect(line2[1].value).toEqual " "
expect(line2[1].scopes).toEqual ["source.python"]
expect(line2[2].value).toEqual "b"
expect(line2[2].scopes).toEqual ["source.python"]
@@ -4,13 +4,23 @@ Theme = require 'theme'
ThemeManager = require 'theme-manager'
describe "ThemeManager", ->
themeManager = null
beforeEach ->
themeManager = new ThemeManager()
afterEach ->
themeManager.unload()
describe "when the core.themes config value changes", ->
it "add/removes stylesheets to reflect the new config value", ->
themeManager = new ThemeManager()
themeManager.on 'reloaded', reloadHandler = jasmine.createSpy()
spyOn(themeManager, 'getUserStylesheetPath').andCallFake -> null
themeManager.load()
config.set('core.themes', [])
expect($('style.userTheme').length).toBe 0
expect(reloadHandler).toHaveBeenCalled()
config.set('core.themes', ['atom-dark-syntax'])
expect($('style.userTheme').length).toBe 1
@@ -24,9 +34,14 @@ describe "ThemeManager", ->
config.set('core.themes', [])
expect($('style.userTheme').length).toBe 0
# atom-dark-ui has an directory path, the syntax ones dont.
config.set('core.themes', ['atom-light-syntax', 'atom-dark-ui', 'atom-dark-syntax'])
importPaths = themeManager.getImportPaths()
expect(importPaths.length).toBe 1
expect(importPaths[0]).toContain 'atom-dark-ui'
describe "when a theme fails to load", ->
it "logs a warning", ->
themeManager = new ThemeManager()
spyOn(console, 'warn')
themeManager.loadTheme('a-theme-that-will-not-be-found')
expect(console.warn).toHaveBeenCalled()
@@ -18,6 +18,7 @@ describe "Theme", ->
themePath = project.resolve('themes/theme-stylesheet.css')
theme = new Theme(themePath)
expect($(".editor").css("padding-top")).toBe "1234px"
expect(theme.directoryPath).not.toBeDefined()
it "parses, loads and applies less", ->
expect($(".editor").css("padding-bottom")).not.toBe "1234px"
@@ -33,6 +34,7 @@ describe "Theme", ->
themePath = project.resolve('themes/theme-with-package-file')
theme = new Theme(themePath)
expect(theme.directoryPath).toBe themePath
expect($(".editor").css("padding-top")).toBe("101px")
expect($(".editor").css("padding-right")).toBe("102px")
expect($(".editor").css("padding-bottom")).toBe("103px")
@@ -45,6 +47,7 @@ describe "Theme", ->
themePath = project.resolve('themes/theme-without-package-file')
theme = new Theme(themePath)
expect(theme.directoryPath).toBe themePath
expect($(".editor").css("padding-top")).toBe "10px"
expect($(".editor").css("padding-right")).toBe "20px"
expect($(".editor").css("padding-bottom")).toBe "30px"
+29 -18
Ver Arquivo
@@ -1,27 +1,33 @@
_ = require 'underscore'
module.exports =
class TimeReporter extends jasmine.Reporter
class TimeReporter extends jasmine.Reporter
constructor: ->
window.timedSpecs = []
window.timedSuites = {}
window.logLongestSpec = -> window.logLongestSpecs(1)
window.logLongestSpec = => @logLongestSpecs(1)
window.logLongestSpecs = (number) => @logLongestSpecs(number)
window.logLongestSuite = => @logLongestSuites(1)
window.logLongestSuites = (number) => @logLongestSuites(number)
window.logLongestSpecs = (number=10) =>
console.log "#{number} longest running specs:"
for spec in _.sortBy(window.timedSpecs, (spec) -> -spec.time)[0...number]
console.log "#{spec.time}ms"
console.log spec.description
logLongestSuites: (number=10, log) ->
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]
time = Math.round(suite[1] / 100) / 10
log " #{suite[0]} (#{time}s)"
undefined
window.logLongestSuite = -> window.logLongestSuites(1)
window.logLongestSuites = (number=10) =>
console.log "#{number} longest running suites:"
suites = _.map(window.timedSuites, (key, value) -> [value, key])
for suite in _.sortBy(suites, (suite) => -suite[1])[0...number]
console.log suite[0], suite[1]
logLongestSpecs: (number=10, log) ->
log ?= (line) -> console.log(line)
log "Longest running specs:"
for spec in _.sortBy(window.timedSpecs, (spec) -> -spec.time)[0...number]
time = Math.round(spec.time / 100) / 10
log "#{spec.description} (#{time}s)"
undefined
reportSpecStarting: (spec) ->
stack = [spec.description]
@@ -31,22 +37,27 @@ class TimeReporter extends jasmine.Reporter
@suite = suite.description
suite = suite.parentSuite
@time = new Date().getTime()
reducer = (memo, description, index) ->
"#{memo}#{_.multiplyString(' ', index)}#{description}\n"
@description = _.reduce(stack, reducer, "")
if index is 0
"#{description}"
else
"#{memo}\n#{_.multiplyString(' ', index)}#{description}"
@description = _.reduce(stack, reducer, '')
@time = new Date().getTime()
reportSpecResults: (spec) ->
return unless @time? and @description?
duration = new Date().getTime() - @time
window.timedSpecs.push
description: @description
time: duration
name: spec.getFullName()
if timedSuites[@suite]
window.timedSuites[@suite] += duration
else
window.timedSuites[@suite] = duration
@time = null
@description = null
@@ -1,6 +1,5 @@
TokenizedBuffer = require 'tokenized-buffer'
Buffer = require 'text-buffer'
Range = require 'range'
{Range} = require 'telepath'
_ = require 'underscore'
describe "TokenizedBuffer", ->
@@ -20,10 +19,18 @@ describe "TokenizedBuffer", ->
advanceClock() while tokenizedBuffer.firstInvalidRow()?
changeHandler?.reset()
describe "@deserialize(state)", ->
it "constructs a tokenized buffer with the same buffer and tabLength setting", ->
buffer = project.bufferForPath('sample.js')
tokenizedBuffer1 = new TokenizedBuffer(buffer: buffer, tabLength: 4)
tokenizedBuffer2 = deserialize(tokenizedBuffer1.serialize())
expect(tokenizedBuffer2.buffer).toBe tokenizedBuffer1.buffer
expect(tokenizedBuffer2.getTabLength()).toBe tokenizedBuffer1.getTabLength()
describe "when the buffer contains soft-tabs", ->
beforeEach ->
buffer = project.bufferForPath('sample.js')
tokenizedBuffer = new TokenizedBuffer(buffer)
tokenizedBuffer = new TokenizedBuffer({buffer})
startTokenizing(tokenizedBuffer)
tokenizedBuffer.on "changed", changeHandler = jasmine.createSpy('changeHandler')
@@ -303,7 +310,7 @@ describe "TokenizedBuffer", ->
beforeEach ->
atom.activatePackage('coffee-script-tmbundle', sync: true)
buffer = project.bufferForPath('sample-with-tabs.coffee')
tokenizedBuffer = new TokenizedBuffer(buffer)
tokenizedBuffer = new TokenizedBuffer({buffer})
startTokenizing(tokenizedBuffer)
afterEach ->
@@ -315,7 +322,7 @@ describe "TokenizedBuffer", ->
fullyTokenize(tokenizedBuffer)
it "renders each tab as its own atomic token with a value of size tabLength", ->
tabAsSpaces = _.multiplyString(' ', tokenizedBuffer.tabLength)
tabAsSpaces = _.multiplyString(' ', tokenizedBuffer.getTabLength())
screenLine0 = tokenizedBuffer.lineForScreenRow(0)
expect(screenLine0.text).toBe "# Econ 101#{tabAsSpaces}"
{ tokens } = screenLine0
@@ -332,11 +339,11 @@ describe "TokenizedBuffer", ->
describe "when the buffer contains surrogate pairs", ->
beforeEach ->
atom.activatePackage('javascript-tmbundle', sync: true)
buffer = new Buffer 'sample-with-pairs.js', """
buffer = project.buildBuffer 'sample-with-pairs.js', """
'abc\uD835\uDF97def'
//\uD835\uDF97xyz
"""
tokenizedBuffer = new TokenizedBuffer(buffer)
tokenizedBuffer = new TokenizedBuffer({buffer})
fullyTokenize(tokenizedBuffer)
afterEach ->
@@ -372,7 +379,7 @@ describe "TokenizedBuffer", ->
atom.activatePackage('ruby-on-rails-tmbundle', sync: true)
buffer = project.bufferForPath(null, "<div class='name'><%= User.find(2).full_name %></div>")
tokenizedBuffer = new TokenizedBuffer(buffer)
tokenizedBuffer = new TokenizedBuffer({buffer})
tokenizedBuffer.setGrammar(syntax.selectGrammar('test.erb'))
fullyTokenize(tokenizedBuffer)
@@ -391,7 +398,7 @@ describe "TokenizedBuffer", ->
it "returns the correct token (regression)", ->
buffer = project.bufferForPath('sample.js')
tokenizedBuffer = new TokenizedBuffer(buffer)
tokenizedBuffer = new TokenizedBuffer({buffer})
fullyTokenize(tokenizedBuffer)
expect(tokenizedBuffer.tokenForPosition([1,0]).scopes).toEqual ["source.js"]
expect(tokenizedBuffer.tokenForPosition([1,1]).scopes).toEqual ["source.js"]
@@ -400,7 +407,7 @@ describe "TokenizedBuffer", ->
describe ".bufferRangeForScopeAtPosition(selector, position)", ->
beforeEach ->
buffer = project.bufferForPath('sample.js')
tokenizedBuffer = new TokenizedBuffer(buffer)
tokenizedBuffer = new TokenizedBuffer({buffer})
fullyTokenize(tokenizedBuffer)
describe "when the selector does not match the token at the position", ->
@@ -10,6 +10,7 @@ describe "Window", ->
beforeEach ->
atom.getLoadSettings().initialPath = project.getPath()
project.destroy()
windowEventHandler = new WindowEventHandler()
window.deserializeEditorWindow()
projectPath = project.getPath()
@@ -39,9 +40,9 @@ describe "Window", ->
describe "window:close event", ->
it "closes the window", ->
spyOn(window, 'close')
spyOn(atom, 'close')
$(window).trigger 'window:close'
expect(window.close).toHaveBeenCalled()
expect(atom.close).toHaveBeenCalled()
it "emits the beforeunload event", ->
$(window).off 'beforeunload'
@@ -169,6 +170,7 @@ describe "Window", ->
unregisterDeserializer(Foo)
it "calls deserialize on the deserializer for the given state object, or returns undefined if one can't be found", ->
spyOn(console, 'warn')
object = deserialize({ deserializer: 'Foo', name: 'Bar' })
expect(object.name).toBe 'Bar'
expect(deserialize({ deserializer: 'Bogus' })).toBeUndefined()
@@ -207,7 +209,8 @@ describe "Window", ->
spyOn(atom, "open")
event = buildDragEvent("drop", [ {path: "/fake1"}, {path: "/fake2"} ])
window.onDrop(event)
expect(atom.open.callCount).toBe 2
expect(atom.open.callCount).toBe 1
expect(atom.open.argsForCall[0][0]).toEqual pathsToOpen: ['/fake1', '/fake2']
describe "when a non-file is dragged to window", ->
it "does nothing", ->
-120
Ver Arquivo
@@ -1,120 +0,0 @@
Range = require 'range'
_ = require 'underscore'
### Internal ###
module.exports =
class BufferChangeOperation
buffer: null
oldRange: null
oldText: null
newRange: null
newText: null
markersToRestoreOnUndo: null
markersToRestoreOnRedo: null
constructor: ({@buffer, @oldRange, @newText, @options}) ->
@options ?= {}
do: ->
@buffer.pauseEvents()
@pauseMarkerObservation()
@markersToRestoreOnUndo = @invalidateMarkers(@oldRange)
if @oldRange?
@oldText = @buffer.getTextInRange(@oldRange)
@newRange = @calculateNewRange(@oldRange, @newText)
newRange = @changeBuffer
oldRange: @oldRange
newRange: @newRange
oldText: @oldText
newText: @newText
@restoreMarkers(@markersToRestoreOnRedo) if @markersToRestoreOnRedo
@buffer.resumeEvents()
@resumeMarkerObservation()
newRange
undo: ->
@buffer.pauseEvents()
@pauseMarkerObservation()
@markersToRestoreOnRedo = @invalidateMarkers(@newRange)
if @oldRange?
@changeBuffer
oldRange: @newRange
newRange: @oldRange
oldText: @newText
newText: @oldText
@restoreMarkers(@markersToRestoreOnUndo)
@buffer.resumeEvents()
@resumeMarkerObservation()
splitLines: (text) ->
lines = text.split('\n')
lineEndings = []
for line, index in lines
if _.endsWith(line, '\r')
lines[index] = line[...-1]
lineEndings[index] = '\r\n'
else
lineEndings[index] = '\n'
{lines, lineEndings}
changeBuffer: ({ oldRange, newRange, newText, oldText }) ->
{ prefix, suffix } = @buffer.prefixAndSuffixForRange(oldRange)
{lines, lineEndings} = @splitLines(newText)
lastLineIndex = lines.length - 1
if lines.length == 1
lines = [prefix + newText + suffix]
else
lines[0] = prefix + lines[0]
lines[lastLineIndex] += suffix
startRow = oldRange.start.row
endRow = oldRange.end.row
normalizeLineEndings = @options.normalizeLineEndings ? true
if normalizeLineEndings and suggestedLineEnding = @buffer.suggestedLineEndingForRow(startRow)
lineEndings[index] = suggestedLineEnding for index in [0..lastLineIndex]
_.spliceWithArray(@buffer.lines, startRow, endRow - startRow + 1, lines)
_.spliceWithArray(@buffer.lineEndings, startRow, endRow - startRow + 1, lineEndings)
@buffer.cachedMemoryContents = null
@buffer.conflict = false if @buffer.conflict and !@buffer.isModified()
event = { oldRange, newRange, oldText, newText }
@updateMarkers(event)
@buffer.trigger 'changed', event
@buffer.scheduleModifiedEvents()
newRange
calculateNewRange: (oldRange, newText) ->
newRange = new Range(oldRange.start.copy(), oldRange.start.copy())
{lines} = @splitLines(newText)
if lines.length == 1
newRange.end.column += newText.length
else
lastLineIndex = lines.length - 1
newRange.end.row += lastLineIndex
newRange.end.column = lines[lastLineIndex].length
newRange
invalidateMarkers: (oldRange) ->
@buffer.getMarkers().map (marker) -> marker.tryToInvalidate(oldRange)
pauseMarkerObservation: ->
marker.pauseEvents() for marker in @buffer.getMarkers(includeInvalid: true)
resumeMarkerObservation: ->
marker.resumeEvents() for marker in @buffer.getMarkers(includeInvalid: true)
@buffer.trigger 'markers-updated' if @oldRange?
updateMarkers: (bufferChange) ->
marker.handleBufferChange(bufferChange) for marker in @buffer.getMarkers()
restoreMarkers: (markersToRestore) ->
for [id, previousRange] in markersToRestore
if validMarker = @buffer.validMarkers[id]
validMarker.setRange(previousRange)
else if invalidMarker = @buffer.invalidMarkers[id]
invalidMarker.revalidate()

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