Comparar commits

...

178 Commits

Autor SHA1 Mensagem Data
Kevin Sawicki 4155c53bd6 Upgrade to markdown-preview@0.93 2014-07-11 13:03:44 -07:00
Ben Ogle d3538502c5 Update git-diff to fix atom/git-diff#31 2014-07-11 12:35:52 -07:00
Kevin Sawicki 90a17de8bd Upgrade to markdown-preview@0.92 2014-07-11 11:56:44 -07:00
Kevin Sawicki a82ea86a05 Upgrade to markdown-preview@0.91 2014-07-11 11:05:03 -07:00
Ben Ogle 22c4992788 Merge pull request #2760 from atom/package-api-stability-notice
Add stability message for Atom.io API
2014-07-11 10:58:57 -07:00
Ben Ogle 2a5d034248 Merge pull request #2920 from atom/bo-gutter-toggle-api
Move gutter member into a showLineNumbers observe block
2014-07-11 10:54:24 -07:00
Kevin Sawicki ed3c37c101 Upgrade to tree-view@0.109.0 2014-07-11 10:42:27 -07:00
Kevin Sawicki 558e5e52c5 Prepare 0.115 2014-07-11 09:57:20 -07:00
Kevin Sawicki 92d16a9d0a Upgrade to apm@0.77 2014-07-11 09:23:31 -07:00
Ivan Žužak f224a6d5f0 Upgrade to fuzzy-finder@0.57.0 2014-07-11 18:14:56 +02:00
probablycorey 16f95a1420 Upgrade to metrics@v0.33.0 2014-07-11 09:02:53 -07:00
Kevin Sawicki 0231d02877 Upgrade to language-javascript@0.35 2014-07-11 08:47:10 -07:00
Kevin Sawicki 6d2b70b3d9 Check that args are present before mapping over
Closes #2925
2014-07-11 08:40:53 -07:00
Ben Ogle 49b825aeb3 Merge pull request #2927 from batjko/master
Change shift-delete to trigger core:cut in Win32 and Linux
2014-07-11 08:01:29 -07:00
Patrick Metzdorf 357299a700 Change shift-delete to trigger core:cut
Win32 and Linux keymaps
2014-07-11 10:14:56 +01:00
Ben Ogle 88df674dd6 Move gutter member into a showLineNumbers observe block 2014-07-10 18:04:53 -07:00
Kevin Sawicki 31afa0abd5 Merge pull request #2915 from atom/ks-32-bit-node-on-windows
Ship 32-bit node with apm on Windows
2014-07-10 17:40:50 -07:00
Kevin Sawicki b11accec6d 📝 Doc --arch=ia32 flag 2014-07-10 17:28:21 -07:00
Kevin Sawicki defa869d5c Upgrade to apm@0.76 2014-07-10 17:28:21 -07:00
Kevin Sawicki 8d4be6ab57 Install apm in 32-bit mode on Windows CI 2014-07-10 17:28:21 -07:00
Ben Ogle 9976166902 Render the line numbers after gutter mount
Fixes #2916
2014-07-10 17:25:58 -07:00
Kevin Sawicki 8ea277ef77 Upgrade to language-javascript@0.34 2014-07-10 17:22:13 -07:00
Kevin Sawicki d85b8bfaf3 Merge pull request #2889 from atom/ks-windows-dimensions-on-windows
Validate window dimensions
2014-07-10 14:30:01 -07:00
Daniel Hengeveld d9e15d937e Merge pull request #2895 from atom/dh-atom-io-package-rename-doc
Change some heading levels and add docs for package renames
2014-07-10 14:26:21 -07:00
Kevin Sawicki 908ff5d3cd 💄 Add space before -> 2014-07-10 14:21:02 -07:00
Kevin Sawicki 35b4ba3066 💄 2014-07-10 14:21:02 -07:00
Kevin Sawicki f90e47daef Handle invalid serialized window dimensions 2014-07-10 14:21:02 -07:00
Kevin Sawicki 5440dd68a7 Use instance method 2014-07-10 14:21:01 -07:00
Kevin Sawicki 11205d9eaa Don't store invalid window dimensions on Windows 2014-07-10 14:21:01 -07:00
Kevin Sawicki 34e37fce7c Upgrade to apm@0.75 2014-07-10 12:02:18 -07:00
Kevin Sawicki 3402c8dcd1 Dedupe request in apm folder
This prevents long path issues on Windows
2014-07-10 11:47:02 -07:00
Kevin Sawicki 3921a63f67 Just use variable in hash 2014-07-10 11:44:55 -07:00
Kevin Sawicki 5ecaf5dfc4 Upgrade to apm@0.74 2014-07-10 11:30:41 -07:00
Ben Ogle 475f92351f == -> is 2014-07-10 10:40:49 -07:00
Kevin Sawicki 0a5b378425 Upgrade to apm 0.73 2014-07-10 10:01:00 -07:00
Kevin Sawicki 157774f552 Map ctrl-f4 to core:close command on Windows
Closes #2903
2014-07-10 09:14:15 -07:00
Kevin Sawicki 320c12134a Upgrade to apm 0.72 2014-07-10 09:02:18 -07:00
Kevin Sawicki 280b451835 Merge pull request #2904 from maschs/ms-fixTypo
Fix typo
2014-07-10 08:25:20 -07:00
Maximilian Schüßler 4ee03fe590 Fix typo 2014-07-10 16:30:45 +02:00
Ben Ogle db1652f1ed Add return statement docs 2014-07-09 18:25:37 -07:00
Ben Ogle 8013ff7775 Update decoration API docs 2014-07-09 18:16:20 -07:00
Daniel Hengeveld c24475c2c8 Add error type to package version doc 2014-07-09 17:45:10 -07:00
Daniel Hengeveld 580c639265 Change some heading levels and add rename doc 2014-07-09 17:41:19 -07:00
Ben Ogle 4c33549371 Merge pull request #2888 from atom/bo-speedup-decoration-render
Index line-wise decorations by ids
2014-07-09 14:11:55 -07:00
Ben Ogle 7be5553ba1 Index line decorations by ids
And don’t use _.deepContains
2014-07-09 12:51:52 -07:00
Kevin Sawicki 43936a1faf Upgrade to find-and-replace@0.126 2014-07-09 12:24:34 -07:00
Kevin Sawicki e3c44bf551 📝 Add Windows installation instructions 2014-07-09 11:14:21 -07:00
Kevin Sawicki 6b0636d331 Upgrade to whitespace@0.24 2014-07-09 11:06:35 -07:00
Ben Ogle cb0ee735be Default cursor on scrollbars.
Fixes #2876
2014-07-09 08:46:48 -07:00
Kevin Sawicki 036dc06bac Upgrade to language-coffee-script@0.25 2014-07-09 08:23:14 -07:00
Nathan Sobo 7155ec4b73 Fix autoscroll specs for addSelectionForBufferRange 2014-07-09 08:06:14 -06:00
Nathan Sobo 86ea4d94bb Only autoscroll in model when adding selection in React editors
Fixes atom/find-and-replace#245
2014-07-09 07:46:44 -06:00
Nathan Sobo 6a2021ac98 Emit editor:will-be-removed event when unmounting the React editor 2014-07-08 21:29:53 -06:00
Nathan Sobo 6fe05064eb Use default implementation of ::destroy from theorist Model class
Move actions that need to happen on destruction to ::destroyed hook.
2014-07-08 21:29:32 -06:00
Nathan Sobo dd5c9ff6d4 Remove stray logging 2014-07-08 21:06:34 -06:00
Nathan Sobo 29179d0bbc Merge pull request #2867 from atom/ns-react-empty-line-invisibles
Render empty line invisibles in React editor
2014-07-08 20:54:41 -06:00
Kevin Sawicki f6400a4097 Upgrade to settings-view@0.133 2014-07-08 16:30:43 -07:00
Nathan Sobo e170b9f56b Render line-ending invisibles on empty lines
Fixes #2857

Including correct interleaving with indent guides.
2014-07-08 16:53:06 -06:00
probablycorey 2ea8418c66 Prepare 0.114.0 2014-07-08 15:38:08 -07:00
probablycorey c20a4a3084 Upgrade to release-notes@v0.35.0 2014-07-08 15:15:47 -07:00
Kevin Sawicki 0be64f9902 Upgrade to release-notes@0.34 2014-07-08 14:32:43 -07:00
Kevin Sawicki 5300fefef4 Prepare 0.113 2014-07-08 14:03:24 -07:00
Nathan Sobo 2602e6ec0a Merge pull request #2865 from atom/ns-react-fix-width-remeasurement
Streamline character width remeasurement to hopefully avoid exceptions
2014-07-08 14:27:26 -06:00
Nathan Sobo 1a22fc3c68 Streamline character width remeasurement to hopefully avoid exceptions
Previously, I was just remeasuring characters whenever the stylesheets
changed. I think there were situations in which the model changed, then
I remeasured characters prior to updating the view to match the model,
causing DOM exceptions. This switches the approach to only ever measure
characters after an update, ensuring the view always matches the model.
2014-07-08 14:17:39 -06:00
Kevin Sawicki 6d02861f11 Upgrade to release-notes@0.33 2014-07-08 13:13:49 -07:00
Corey Johnson 57ed190ea3 Merge pull request #2859 from atom/cj-windows-updater
Add autoUpdater shim for Windows
2014-07-08 12:52:45 -07:00
probablycorey 436d7de817 Send empty event arg 2014-07-08 11:46:04 -07:00
probablycorey a9feed2e4a Maintain autoUpdater listeners even if the version is in dev mode.
This is so we can test the auto-updater
2014-07-08 11:41:41 -07:00
Kevin Sawicki 8b04e94d09 Upgrade to apm 0.71 2014-07-08 11:38:53 -07:00
Ben Ogle 5c5576c39d Use right margins for toolbar btn-groups rather than left.
Fixes #2830
2014-07-08 11:18:48 -07:00
Ben Ogle 2b957beeda 💄 Fix ugly test 2014-07-08 11:18:47 -07:00
probablycorey 832aeffd4f Add basic updater spec 2014-07-08 11:12:28 -07:00
Kevin Sawicki 5d08ecdcb2 Remove logging in specs 2014-07-08 10:57:22 -07:00
Nathan Sobo 997529774c Clean up after stylesheet applications in editor-component-spec 2014-07-08 11:55:50 -06:00
Nathan Sobo 48d20ff1ec Only remeasure char widths on stylesheet changes if editor is visible
Fixes #2856
2014-07-08 11:46:23 -06:00
Kevin Sawicki 0793f291d1 Prepare 0.112 2014-07-08 10:23:06 -07:00
Kevin Sawicki 8d479328ec Upgrade to language-ruby@0.32 2014-07-08 09:29:04 -07:00
Kevin Sawicki 569326e76a Upgrade to language-sql@0.9 2014-07-08 09:17:44 -07:00
Kevin Sawicki 8372b84e9f Prepare 0.111 2014-07-07 18:23:21 -07:00
Ben Ogle eda55156e5 Merge pull request #2819 from atom/bo-decoration-api
Update the decoration API
2014-07-07 18:06:35 -07:00
Kevin Sawicki c40a526302 Only require core specs to pass on Windows
Still ironing out some flaky package specs that occasionally fail
2014-07-07 18:02:54 -07:00
Ben Ogle 540b038ced Add is destroyed flag to decoration 2014-07-07 17:48:40 -07:00
Ben Ogle ce1ebec253 Fix specs 2014-07-07 17:48:24 -07:00
probablycorey 44e121c997 Add autoUpdater shim for Windows 2014-07-07 17:07:42 -07:00
Nathan Sobo 3579404bed Merge pull request #2858 from atom/ns-react-fix-wrap-guide
Make React editor indent guide work like it did in the old editor
2014-07-07 18:07:36 -06:00
Kevin Sawicki 1e19860409 Upgrade to markdown-preview@0.90 2014-07-07 17:03:02 -07:00
Ben Ogle eab4b578a3 Upgrade packages to use new decoration APIs 2014-07-07 17:01:49 -07:00
Nathan Sobo 2878196e0a Make React editor indent guide work like it did in the old editor
Fixes #2367

* The indent level of empty lines is the *max* of the nearest non empty
  line, rather than favoring the level of the line below.

* An extra wrap guide is no longer rendered for empty lines

I didn't port the specs over because we already had good coverage at the
model level. It just needed to be updated for the preferred behavior.
2014-07-07 17:59:26 -06:00
Kevin Sawicki 1c037411e9 Ignore domhandler tests 2014-07-07 16:09:40 -07:00
Kevin Sawicki 68144681b2 💄 2014-07-07 16:05:01 -07:00
Kevin Sawicki 484a516bd6 Relative path might be missing 2014-07-07 16:03:28 -07:00
Kevin Sawicki fa6e84415b Ignore gaze from jasmine-node
This is only used when jasmine-node is being launched from the CLI
with --autotest/--watch which the bundled spec runner does not use
or expose.

This reduces all bundled paths to be under 200 characters relative
to the root install location.
2014-07-07 15:57:38 -07:00
Kevin Sawicki 7117634ba8 Ignore more test directories 2014-07-07 15:57:38 -07:00
Kevin Sawicki a108c283cf Add grunt task to log long paths in built app 2014-07-07 15:57:38 -07:00
Kevin Sawicki 3dc61f4a7a Ignore more test directories 2014-07-07 15:57:37 -07:00
Nathan Sobo 9685e3f1db Merge pull request #2855 from atom/ns-active-pane-deserialization
Move serialization of active pane from Pane to PaneContainer
2014-07-07 16:49:29 -06:00
Nathan Sobo b2c70f9e69 Move serialization of active pane from Pane to PaneContainer
Fixes #2694
Fixel #2853

Previously, we were storing an `active` boolean for each pane. We've
had some strange bugs where every pane is serializing `active: false`,
which causes exceptions when loading up the stored data.

This new approach serializes the activePaneId on the PaneContainer
itself. Since the PaneContainer is the source of truth regarding the
active pane, it makes more sense to handle it here.

This unfortunately changes the serialization version for the
PaneContainer, so people won't have their state persisted after
upgrading. But it seems better than leaving cruft to handle the old
serialization situation.
2014-07-07 16:36:10 -06:00
Ben Ogle d7a3ffa9de Handle Decoration::update 2014-07-07 15:13:04 -07:00
Nathan Sobo 18ed91a402 Merge pull request #2852 from atom/ns-react-remeasure-characters-on-stylesheet-change
Re-measure character widths when stylesheets change
2014-07-07 15:47:29 -06:00
Ben Ogle e991b3d10c Move from addDecoration -> decorateMarker 2014-07-07 14:43:56 -07:00
Nathan Sobo f1b7f9ca30 Merge pull request #2851 from atom/ns-react-autoscroll-on-undo
Autoscroll to cursor on undo
2014-07-07 15:42:10 -06:00
Nathan Sobo e1e510e473 Re-measure character widths when stylesheets change
Fixes #2845
2014-07-07 15:39:00 -06:00
Nathan Sobo d042d15a50 Autoscroll to cursor on undo
Fixes #2815

This commit changes our autoscroll strategy for cursors significantly.

Originally, we were autoscrolling whenever the cursor's marker changed
positions. This worked well, except we didn't end up autoscrolling when
the user *attempted* to move the cursor to an invalid position, such as
moving down at the end of the buffer, due to the fact that the marker
wouldn't change.

Then, we moved to always requesting an autoscroll whenever a position
change was requested via Cursor::changePosition. This missed out on
moving the cursor when inserting text, so we then also added an explicit
autoscroll call when inserting text.

This had the problem of not autoscrolling due to undo. So finally, this
solution combines explicit autoscroll in ::changePosition to capture
intent, as well as implicit autoscrolling whenever the cursor's marker
position changes due to a textual change in the buffer. This captures
undo/redo correctly.
2014-07-07 15:21:48 -06:00
Ben Ogle fe9fec733d Stub out Decoration::destroy and Decoration::update 2014-07-07 14:19:20 -07:00
Kevin Sawicki 06095e57d7 Prepare 0.110 2014-07-07 14:07:41 -07:00
Nathan Sobo b83f908e28 Merge pull request #2850 from atom/ns-react-account-for-padding-in-softwrap
Account for padding-left on scroll view when soft-wrapping lines in the React editor
2014-07-07 14:36:20 -06:00
Nathan Sobo fad2a63a14 Account for padding-left on the scroll view when soft-wrapping lines
Fixes #2844
2014-07-07 14:02:24 -06:00
Nathan Sobo 2de42303d4 💄 2014-07-07 13:55:32 -06:00
Nathan Sobo a7aed07d70 Merge pull request #2849 from atom/ns-react-fix-softwrap-scroll-left
Scroll React editor all the way left when soft wrap is enabled
2014-07-07 13:31:15 -06:00
Nathan Sobo 673b62f547 Scroll React editor all the way left when soft wrap is enabled
Fixes #2842
2014-07-07 12:26:33 -06:00
Ben Ogle 19835f2f66 Upgrade tabs to support mousewheel navigation 2014-07-07 11:04:24 -07:00
Kevin Sawicki 7474de8f7e Upgrade to markdown-preview@0.89 2014-07-07 10:50:07 -07:00
Kevin Sawicki 84c30ef6c5 Set initial concurrency to 1 on all platforms 2014-07-07 10:26:12 -07:00
Kevin Sawicki 0aa5fa9eeb Increase timeout on Windows CI 2014-07-07 10:14:38 -07:00
Kevin Sawicki b5f8b159fc Upgrade to settings-view@0.132 2014-07-07 10:05:16 -07:00
Kevin Sawicki 79357be899 Upgrade to markdown-preview@0.88 2014-07-07 09:29:21 -07:00
Kevin Sawicki 12d6a90ddc Upgrade to wrap-guide@0.21 2014-07-07 09:13:11 -07:00
Kevin Sawicki 4eb3be6f17 Upgrade to markdown-preview@0.87 2014-07-07 09:12:29 -07:00
Kevin Sawicki af622c6b74 Upgrade to wrap-guide@0.20 2014-07-07 07:37:51 -07:00
Kevin Sawicki df8e0a8464 📝 Add is-focused class to cursor example
This is required to take effect for the default Atom light syntax
theme.

Closes #2834
2014-07-06 10:08:24 -07:00
Kevin Sawicki a1c1879ba6 Merge pull request #2813 from atom/ks-codesign-on-windows-ci
Codesign on Windows CI
2014-07-05 11:48:39 -07:00
Kevin Sawicki d1e52d4105 Restore spec task 2014-07-05 11:29:10 -07:00
Kevin Sawicki 0f01840e3e Restore publish checks 2014-07-05 11:28:56 -07:00
Kevin Sawicki e1945fce14 Comment out Janky check 2014-07-05 11:15:56 -07:00
Kevin Sawicki e6ecf10616 Publish builds from this branch to test signing 2014-07-05 11:12:59 -07:00
Kevin Sawicki b85ebbad2a Separate /F argument to taskkill 2014-07-05 11:06:07 -07:00
Kevin Sawicki 38ba96a54f Break up commands into two spawns 2014-07-05 10:49:25 -07:00
Kevin Sawicki 334e2ef7ab Temporarily disable specs 2014-07-05 10:46:22 -07:00
Kevin Sawicki 58efeb8a20 Force kill on Windows 2014-07-05 10:45:48 -07:00
Kevin Sawicki 3ae6540c70 Kill all atom.exe before signing 2014-07-05 10:45:35 -07:00
Kevin Sawicki 497ac5e5ce Add kill command for Windows 2014-07-05 10:41:45 -07:00
Kevin Sawicki 8735780473 Reenable specs 2014-07-05 10:29:50 -07:00
Kevin Sawicki 888b5ab098 Always pass specs to test signing 2014-07-05 10:19:14 -07:00
Kevin Sawicki c897f42d51 Use JANKY_SIGNTOOL env var to sign 2014-07-05 10:19:14 -07:00
Kevin Sawicki 3c5312e834 signtool is now on the PATH 2014-07-05 10:19:14 -07:00
Kevin Sawicki c59cbb3b25 Use full path to signtool.bat 2014-07-05 10:19:13 -07:00
Kevin Sawicki b3da11edfb 💄 Use switch 2014-07-05 10:19:13 -07:00
Kevin Sawicki f56b487935 Call signtool on Windows 2014-07-05 10:19:13 -07:00
Kevin Sawicki 840abd6780 Upgrade to settings-view@0.131 2014-07-05 10:17:49 -07:00
Kevin Sawicki 2e554ac819 Use cross platform path in Project::replace spec 2014-07-05 10:01:19 -07:00
Kevin Sawicki 35c7bc0eef Upgrade to language-coffee-script@0.24 2014-07-05 08:35:49 -07:00
Ben Ogle d99a9b0f3f Merge pull request #2826 from atom/ns-flash-specs
Explicitly test removal of flash class prior to next animation frame
2014-07-04 09:53:55 -07:00
Nathan Sobo 7ac8b80172 Explicitly test removal of flash class prior to next animation frame 2014-07-04 09:56:51 -06:00
Ben Ogle 68f2bd56f0 Upgrade find-and-replace to flash the current result 2014-07-03 17:51:43 -07:00
Ben Ogle e709b986cd Upgrade themes to fix atom/tabs#64 2014-07-03 17:51:21 -07:00
Ben Ogle 74bdd5f0e8 Merge pull request #2794 from atom/bo-flash
Add ability to 'flash' selections
2014-07-03 17:48:08 -07:00
Ben Ogle 48b6c24882 Add Editor::selectionFlashDuration rather than magic number 2014-07-03 17:36:45 -07:00
Ben Ogle e5f800ef35 💄 2014-07-03 17:32:38 -07:00
Ben Ogle 492022fdd8 Fix spec 2014-07-03 17:32:38 -07:00
Ben Ogle cf7b87842e Upgrade all the themes
Removes flash / highlighted from ui themes
Adds flash color to syntax themes
2014-07-03 17:32:38 -07:00
Ben Ogle 1838ff2502 Use ‘flash’ class rather than ‘highlighted’.
Pull the flash into the base theme rather than the ui themes
2014-07-03 17:32:38 -07:00
Ben Ogle 505bfc28db fix spec 2014-07-03 17:32:37 -07:00
Ben Ogle abbe8d2eec Flash works for selections 2014-07-03 17:32:37 -07:00
Ben Ogle bf33d96899 Decorations can be flashed 2014-07-03 17:32:37 -07:00
Ben Ogle a56b5eef2f Remove the decoration update stuff 2014-07-03 17:32:37 -07:00
Ben Ogle 80eb31679f Add a Decoration object. Rework to use this object 2014-07-03 17:32:37 -07:00
Ben Ogle 54039e9d3b Don’t use state. Modify the dom directly 2014-07-03 17:32:37 -07:00
Ben Ogle 92c28fc44f 💄 2014-07-03 17:32:37 -07:00
Ben Ogle bc67efb72b 💄 Waaay less awkward 2014-07-03 17:32:37 -07:00
Ben Ogle 0ee4d864be Move flashing into the highlight component 2014-07-03 17:32:37 -07:00
Ben Ogle 1d724339d6 Don’t use attributes 2014-07-03 17:32:37 -07:00
Ben Ogle ce90b72807 Handle the decoration + highlighted in the selection 2014-07-03 17:32:37 -07:00
Ben Ogle 4f356121d7 Handle decoration updates in the editor-component 2014-07-03 17:32:37 -07:00
Ben Ogle 7b19152a58 Add updateDecorationForMarker() 2014-07-03 17:32:37 -07:00
Ben Ogle 15da69287e Upgrade tabs, fix flicker issue 2014-07-03 17:23:03 -07:00
Kevin Sawicki 8d8db5142f Upgrade to language-javascript@0.33 2014-07-03 15:44:28 -07:00
Kevin Sawicki 6d7881bcfe Upgrade to language-less@0.12 2014-07-03 15:29:52 -07:00
Nathan Sobo c2b7955ec6 Adjust DisplayBuffer::longestScreenRow when lines are inserted/removed
Fixes #2810

The line corresponding to the longest screen row moves when lines are
inserted or removed above it, so we need to adjust it accordingly or we
won't always realize when a change affects the longest line.
2014-07-03 16:15:49 -06:00
Ben Ogle cc073ae462 Merge pull request #2816 from atom/bo-remove-fnr-marker-less
Remove fnr marker less from themes, and into fnr
2014-07-03 14:59:56 -07:00
Ben Ogle 3348c0e75a Upgrade syntax themes to remove find-result marker css
It is now in find-and-replace based on syntax-variables. Better!
2014-07-03 14:43:58 -07:00
Ben Ogle 376a850507 Update find-and-replace to set the marker css 2014-07-03 14:27:46 -07:00
Ben Ogle 168c6cdbca Revert "Move the find-and-replace marker css into the base theme "
This reverts commit 942041f214.
2014-07-03 14:22:58 -07:00
Nathan Sobo 9ece33dbfe Handle double and triple click with command key held down
Fixes #2812
2014-07-03 15:18:53 -06:00
Ben Ogle 942041f214 Move the find-and-replace marker css into the base theme 2014-07-03 14:12:23 -07:00
Nathan Sobo 260be2e096 Autoscroll *after* inserting text, not before
Fixes #2787
2014-07-03 14:47:43 -06:00
Kevin Sawicki 6c8b4de986 Upgrade to settings-view@0.130 2014-07-03 13:38:32 -07:00
Kevin Sawicki 9b267728d0 Upgrade to language-ruby@0.31 2014-07-03 13:07:52 -07:00
Daniel Hengeveld 126d0d1b3c Add stability message for Atom.io API
This indicates that the Atom.io API is not frozen - this is describing the state
of things, not announcing a new policy.
2014-06-27 12:33:50 -07:00
42 arquivos alterados com 873 adições e 288 exclusões
+12
Ver Arquivo
@@ -6,10 +6,21 @@ Visit [atom.io](https://atom.io) to learn more.
## Installing
### Mac OS X
Download the latest [Atom release](https://github.com/atom/atom/releases/latest).
Atom will automatically update when a new release is available.
### Windows
Install the [Atom chocolatey package](https://chocolatey.org/packages/Atom).
1. Install [chocolatey](https://chocolatey.org).
2. Close and reopen your command prompt or PowerShell window.
3. Run `cinst Atom`
4. In the future run `cup Atom` to upgrade to the latest release.
## Building
* [Linux](docs/build-instructions/linux.md)
@@ -18,4 +29,5 @@ Atom will automatically update when a new release is available.
* [Windows](docs/build-instructions/windows.md)
## Developing
Check out the [guides](https://atom.io/docs/latest) and the [API reference](https://atom.io/docs/api).
+1 -1
Ver Arquivo
@@ -6,6 +6,6 @@
"url": "https://github.com/atom/atom.git"
},
"dependencies": {
"atom-package-manager": "0.70.0"
"atom-package-manager": "0.77.0"
}
}
+4 -1
Ver Arquivo
@@ -47,14 +47,17 @@ module.exports = (grunt) ->
contentsDir = shellAppDir
appDir = path.join(shellAppDir, 'resources', 'app')
installDir ?= path.join(process.env.ProgramFiles, appName)
killCommand = 'taskkill /F /IM atom.exe'
else if process.platform is 'darwin'
contentsDir = path.join(shellAppDir, 'Contents')
appDir = path.join(contentsDir, 'Resources', 'app')
installDir ?= path.join('/Applications', appName)
killCommand = 'pkill -9 Atom'
else
contentsDir = shellAppDir
appDir = path.join(shellAppDir, 'resources', 'app')
installDir ?= process.env.INSTALL_PREFIX ? '/usr/local'
killCommand ='pkill -9 Atom'
coffeeConfig =
glob_to_multiple:
@@ -213,7 +216,7 @@ module.exports = (grunt) ->
shell:
'kill-atom':
command: 'pkill -9 Atom'
command: killCommand
options:
stdout: false
stderr: false
+10
Ver Arquivo
@@ -51,7 +51,17 @@ module.exports = (grunt) ->
path.join('pegjs', 'examples')
path.join('plist', 'tests')
path.join('xmldom', 'test')
path.join('combined-stream', 'test')
path.join('delayed-stream', 'test')
path.join('domhandler', 'test')
path.join('fstream-ignore', 'test')
path.join('harmony-collections', 'test')
path.join('lru-cache', 'test')
path.join('minimatch', 'test')
path.join('normalize-package-data', 'test')
path.join('npm', 'test')
path.join('jasmine-reporters', 'ext')
path.join('jasmine-node', 'node_modules', 'gaze')
path.join('build', 'Release', 'obj.target')
path.join('build', 'Release', 'obj')
path.join('build', 'Release', '.deps')
+15 -6
Ver Arquivo
@@ -1,12 +1,12 @@
path = require 'path'
module.exports = (grunt) ->
{spawn} = require('./task-helpers')(grunt)
grunt.registerTask 'codesign', 'Codesign the app', ->
return unless process.platform is 'darwin'
done = @async()
if process.env.XCODE_KEYCHAIN
if process.platform is 'darwin' and process.env.XCODE_KEYCHAIN
unlockKeychain (error) ->
if error?
done(error)
@@ -22,6 +22,15 @@ module.exports = (grunt) ->
spawn {cmd, args}, (error) -> callback(error)
signApp = (callback) ->
cmd = 'codesign'
args = ['-f', '-v', '-s', 'Developer ID Application: GitHub', grunt.config.get('atom.shellAppDir')]
spawn {cmd, args}, (error) -> callback(error)
switch process.platform
when 'darwin'
cmd = 'codesign'
args = ['-f', '-v', '-s', 'Developer ID Application: GitHub', grunt.config.get('atom.shellAppDir')]
spawn {cmd, args}, (error) -> callback(error)
when 'win32'
spawn {cmd: 'taskkill', args: ['/F', '/IM', 'atom.exe']}, ->
cmd = process.env.JANKY_SIGNTOOL ? 'signtool'
args = [path.join(grunt.config.get('atom.shellAppDir'), 'atom.exe')]
spawn {cmd, args}, (error) -> callback(error)
else
callback()
+18
Ver Arquivo
@@ -0,0 +1,18 @@
path = require 'path'
module.exports = (grunt) ->
grunt.registerTask 'output-long-paths', 'Log long paths in the built application', ->
shellAppDir = grunt.config.get('atom.shellAppDir')
longPaths = []
grunt.file.recurse shellAppDir, (absolutePath, rootPath, relativePath, fileName) ->
if relativePath
fullPath = path.join(relativePath, fileName)
else
fullPath = fileName
longPaths.push(fullPath) if fullPath.length >= 200
longPaths.sort (longPath1, longPath2) -> longPath2.length - longPath1.length
longPaths.forEach (longPath) ->
grunt.log.error "#{longPath.length} character path: #{longPath}"
+7 -4
Ver Arquivo
@@ -53,9 +53,7 @@ module.exports = (grunt) ->
continue unless isAtomPackage(packagePath)
packageSpecQueue.push(packagePath)
# TODO: Restore concurrency on Windows
packageSpecQueue.concurrency = 1 unless process.platform is 'win32'
packageSpecQueue.concurrency = 1
packageSpecQueue.drain = -> callback(null, failedPackages)
runCoreSpecs = (callback) ->
@@ -105,4 +103,9 @@ module.exports = (grunt) ->
failures.push "atom core" if coreSpecFailed
grunt.log.error("[Error]".red + " #{failures.join(', ')} spec(s) failed") if failures.length > 0
done(!coreSpecFailed and failedPackages.length == 0)
if process.platform is 'win32' and process.env.JANKY_SHA1
# Package specs are still flaky on Windows CI
done(!coreSpecFailed)
else
done(!coreSpecFailed and failedPackages.length == 0)
+37 -8
Ver Arquivo
@@ -1,4 +1,4 @@
## Atom.io package and update API
# Atom.io package and update API
This guide describes the web API used by [apm](https://github.com/atom/apm) and
Atom. The vast majority of use cases are met by the `apm` command-line tool,
@@ -8,6 +8,8 @@ and making sure you have pushed your git tag. In fact, Atom itself shells out to
uses `apm`, see the [PackageManager class](https://github.com/atom/settings-view/blob/master/lib/package-manager.coffee)
in the `settings-view` package.
*This API should be considered pre-release and is subject to change (though significant breaking changes are unlikely).*
### Authorization
For calls to the API that require authentication, provide a valid token from your
@@ -17,9 +19,11 @@ For calls to the API that require authentication, provide a valid token from you
All requests that take parameters require `application/json`.
## Resources
# API Resources
### Packages
## Packages
### Listing packages
#### GET /api/packages
@@ -40,6 +44,8 @@ Returns a list of all packages in the following format:
]
```
### Showing package details
#### GET /api/packages/:package_name
Returns package details and versions for a single package
@@ -68,6 +74,8 @@ Returns:
}
```
### Creating a package
#### POST /api/packages
Create a new package; requires authentication.
@@ -92,6 +100,7 @@ Returns:
- The package.json at owner/repo isn't valid
- **409** - A package by that name already exists
### Deleting a package
#### DELETE /api/packages/:package_name
@@ -103,6 +112,13 @@ Returns:
- **400** - Repository is inaccessible
- **401** - Unauthorized
### Renaming a package
Packages are renamed by publishing a new version with the name changed in `package.json`
See [Creating a new package version](#creating-a-new-package-version) for details.
Requests made to the previous name will forward to the new name.
### Package Versions
#### GET /api/packages/:package_name/versions/:version_name
@@ -144,7 +160,9 @@ Returns `package.json` with `dist` key added for e.g. tarball download:
#### POST /api/packages/:package_name/versions
Creates a new package version from a git tag; requires authentication.
Creates a new package version from a git tag; requires authentication. If `rename`
is not `true`, the `name` field in `package.json` *must* match the current package
name.
#### Parameters
@@ -152,14 +170,15 @@ Creates a new package version from a git tag; requires authentication.
that the version name will not be taken from the tag, but from the `version`
key in the `package.json` file at that ref. The authenticating user *must* have
access to the package repository.
- **rename** - Boolean indicating whether this version contains a new name for the package.
#### Returns
- **201** - Successfully created. Returns created version.
- **400** - Git tag not found / Repository inaccessible
- **400** - Git tag not found / Repository inaccessible / package.json invalid
- **409** - Version exists
### Delete a version
### Deleting a version
#### DELETE /api/packages/:package_name/versions/:version_name
@@ -172,7 +191,9 @@ you'll need to increment the version when republishing.
Returns 204 No Content
### Stars
## Stars
### Listing user stars
#### GET /api/users/:login/stars
@@ -186,18 +207,24 @@ List the authenticated user's starred packages; requires authentication.
Return value is similar to **GET /api/packages**
### Starring a package
#### POST /api/packages/:name/star
Star a package; requires authentication.
Returns a package.
### Unstarring a package
#### DELETE /api/packages/:name/star
Unstar a package; requires authentication.
Returns 204 No Content.
### Listing a package's stargazers
#### GET /api/packages/:name/stargazers
List the users that have starred a package.
@@ -211,7 +238,9 @@ Returns a list of user objects:
]
```
### Atom updates
## Atom updates
### Listing Atom updates
#### GET /api/updates
+1 -1
Ver Arquivo
@@ -169,7 +169,7 @@ For example, to change the color of the cursor, you could add the following
rule to your _~/.atom/styles.less_ file:
```less
.editor .cursor {
.editor.is-focused .cursor {
border-color: pink;
}
```
+1 -1
Ver Arquivo
@@ -38,7 +38,7 @@
'shift-pageup': 'core:select-page-up'
'shift-pagedown': 'core:select-page-down'
'delete': 'core:delete'
'shift-delete': 'core:delete'
'shift-delete': 'core:cut'
'pageup': 'core:page-up'
'pagedown': 'core:page-down'
'backspace': 'core:backspace'
+2 -1
Ver Arquivo
@@ -26,6 +26,7 @@
'ctrl-s': 'core:save'
'ctrl-S': 'core:save-as'
'ctrl-w': 'core:close'
'ctrl-f4': 'core:close'
'ctrl-z': 'core:undo'
'ctrl-y': 'core:redo'
'ctrl-x': 'core:cut'
@@ -40,7 +41,7 @@
'shift-pageup': 'core:select-page-up'
'shift-pagedown': 'core:select-page-down'
'delete': 'core:delete'
'shift-delete': 'core:delete'
'shift-delete': 'core:cut'
'pageup': 'core:page-up'
'pagedown': 'core:page-down'
'backspace': 'core:backspace'
+25 -25
Ver Arquivo
@@ -1,7 +1,7 @@
{
"name": "atom",
"productName": "Atom",
"version": "0.109.0",
"version": "0.115.0",
"description": "A hackable text editor for the 21st Century.",
"main": "./src/browser/main.js",
"repository": {
@@ -62,54 +62,54 @@
"vm-compatibility-layer": "0.1.0"
},
"packageDependencies": {
"atom-dark-syntax": "0.17.0",
"atom-dark-ui": "0.30.0",
"atom-light-syntax": "0.18.0",
"atom-light-ui": "0.26.0",
"base16-tomorrow-dark-theme": "0.17.0",
"solarized-dark-syntax": "0.18.0",
"solarized-light-syntax": "0.9.0",
"atom-dark-syntax": "0.19.0",
"atom-dark-ui": "0.32.0",
"atom-light-syntax": "0.20.0",
"atom-light-ui": "0.28.0",
"base16-tomorrow-dark-theme": "0.19.0",
"solarized-dark-syntax": "0.20.0",
"solarized-light-syntax": "0.11.0",
"archive-view": "0.33.0",
"autocomplete": "0.28.0",
"autoflow": "0.17.0",
"autosave": "0.14.0",
"background-tips": "0.15.0",
"bookmarks": "0.26.0",
"bookmarks": "0.27.0",
"bracket-matcher": "0.48.0",
"command-palette": "0.24.0",
"deprecation-cop": "0.7.0",
"dev-live-reload": "0.31.0",
"exception-reporting": "0.18.0",
"feedback": "0.33.0",
"find-and-replace": "0.122.0",
"fuzzy-finder": "0.56.0",
"git-diff": "0.34.0",
"find-and-replace": "0.126.0",
"fuzzy-finder": "0.57.0",
"git-diff": "0.36.0",
"go-to-line": "0.23.0",
"grammar-selector": "0.27.0",
"image-view": "0.36.0",
"keybinding-resolver": "0.18.0",
"link": "0.24.0",
"markdown-preview": "0.86.0",
"metrics": "0.32.0",
"markdown-preview": "0.93.0",
"metrics": "0.33.0",
"open-on-github": "0.29.0",
"package-generator": "0.31.0",
"release-notes": "0.32.0",
"settings-view": "0.129.0",
"release-notes": "0.35.0",
"settings-view": "0.133.0",
"snippets": "0.47.0",
"spell-check": "0.38.0",
"status-bar": "0.41.0",
"styleguide": "0.29.0",
"symbols-view": "0.59.0",
"tabs": "0.42.0",
"tabs": "0.44.0",
"timecop": "0.21.0",
"tree-view": "0.108.0",
"tree-view": "0.109.0",
"update-package-dependencies": "0.6.0",
"welcome": "0.17.0",
"whitespace": "0.23.0",
"wrap-guide": "0.19.0",
"whitespace": "0.24.0",
"wrap-guide": "0.21.0",
"language-c": "0.21.0",
"language-coffee-script": "0.23.0",
"language-coffee-script": "0.25.0",
"language-css": "0.17.0",
"language-gfm": "0.42.0",
"language-git": "0.9.0",
@@ -117,21 +117,21 @@
"language-html": "0.22.0",
"language-hyperlink": "0.10.0",
"language-java": "0.11.0",
"language-javascript": "0.32.0",
"language-javascript": "0.35.0",
"language-json": "0.8.0",
"language-less": "0.11.0",
"language-less": "0.12.0",
"language-make": "0.10.0",
"language-objective-c": "0.11.0",
"language-perl": "0.9.0",
"language-php": "0.15.0",
"language-property-list": "0.7.0",
"language-python": "0.18.0",
"language-ruby": "0.30.0",
"language-ruby": "0.32.0",
"language-ruby-on-rails": "0.15.0",
"language-sass": "0.13.0",
"language-shellscript": "0.8.0",
"language-source": "0.7.0",
"language-sql": "0.8.0",
"language-sql": "0.9.0",
"language-text": "0.6.0",
"language-todo": "0.10.0",
"language-toml": "0.12.0",
+26 -5
Ver Arquivo
@@ -44,23 +44,44 @@ function bootstrap() {
var apmInstallCommand = npmPath + npmFlags + 'install';
var apmInstallOptions = {cwd: apmInstallPath};
var moduleInstallCommand = apmPath + ' install' + apmFlags;
var dedupeCommand = apmPath + ' dedupe' + apmFlags;
var dedupeApmCommand = apmPath + ' dedupe' + apmFlags;
var dedupeNpmCommand = npmPath + npmFlags + 'dedupe';
if (process.argv.indexOf('--no-quiet') === -1) {
buildInstallCommand += ' --quiet';
apmInstallCommand += ' --quiet';
moduleInstallCommand += ' --quiet';
dedupeCommand += ' --quiet';
dedupeApmCommand += ' --quiet';
dedupeNpmCommand += ' --quiet';
buildInstallOptions.ignoreStdout = true;
apmInstallOptions.ignoreStdout = true;
}
// apm ships with 32-bit node so make sure its native modules are compiled
// for a 32-bit target architecture
if (process.env.JANKY_SHA1 && process.platform === 'win32')
apmInstallCommand += ' --arch=ia32';
var commands = [
{command: buildInstallCommand, message: 'Installing build modules...', options: buildInstallOptions},
{command: apmInstallCommand, message: 'Installing apm...', options: apmInstallOptions},
{
command: buildInstallCommand,
message: 'Installing build modules...',
options: buildInstallOptions
},
{
command: apmInstallCommand,
message: 'Installing apm...',
options: apmInstallOptions
},
apmPath + ' clean' + apmFlags,
moduleInstallCommand,
dedupeCommand + ' ' + packagesToDedupe.join(' '),
dedupeApmCommand + ' ' + packagesToDedupe.join(' '),
{
command: dedupeNpmCommand + ' request',
options: {
cwd: path.resolve(__dirname, '..', 'apm', 'node_modules', 'atom-package-manager')
}
},
];
process.chdir(path.dirname(__dirname));
+15
Ver Arquivo
@@ -535,3 +535,18 @@ describe "the `atom` global", ->
expect(atom.isReleasedVersion()).toBe true
version = '36b5518'
expect(atom.isReleasedVersion()).toBe false
describe "window:update-available", ->
it "is triggered when the auto-updater sends the update-downloaded event", ->
updateAvailableHandler = jasmine.createSpy("update-available-handler")
atom.workspaceView.on 'window:update-available', updateAvailableHandler
autoUpdater = require('remote').require('auto-updater')
autoUpdater.emit 'update-downloaded', null, "notes", "version"
waitsFor ->
updateAvailableHandler.callCount > 0
runs ->
[event, version, notes] = updateAvailableHandler.mostRecentCall.args
expect(notes).toBe 'notes'
expect(version).toBe 'version'
+50 -6
Ver Arquivo
@@ -215,6 +215,19 @@ describe "DisplayBuffer", ->
displayBuffer.setEditorWidthInChars(-1)
expect(displayBuffer.editorWidthInChars).not.toBe -1
it "sets ::scrollLeft to 0 and keeps it there when soft wrapping is enabled", ->
displayBuffer.setDefaultCharWidth(10)
displayBuffer.setWidth(50)
displayBuffer.manageScrollPosition = true
displayBuffer.setSoftWrap(false)
displayBuffer.setScrollLeft(Infinity)
expect(displayBuffer.getScrollLeft()).toBeGreaterThan 0
displayBuffer.setSoftWrap(true)
expect(displayBuffer.getScrollLeft()).toBe 0
displayBuffer.setScrollLeft(10)
expect(displayBuffer.getScrollLeft()).toBe 0
describe "primitive folding", ->
beforeEach ->
displayBuffer.destroy()
@@ -329,8 +342,6 @@ describe "DisplayBuffer", ->
fold2 = displayBuffer.createFold(4, 9)
fold1 = displayBuffer.createFold(0, 4)
displayBuffer.logLines(0, 20)
expect(displayBuffer.lineForRow(0).text).toMatch /^0/
expect(displayBuffer.lineForRow(1).text).toMatch /^10/
@@ -643,6 +654,19 @@ describe "DisplayBuffer", ->
buffer.delete([[6, 0], [6, 65]])
expect(displayBuffer.getMaxLineLength()).toBe 62
it "correctly updates the location of the longest screen line when changes occur", ->
expect(displayBuffer.getLongestScreenRow()).toBe 6
buffer.delete([[0, 0], [2, 0]])
expect(displayBuffer.getLongestScreenRow()).toBe 4
buffer.delete([[4, 0], [5, 0]])
expect(displayBuffer.getLongestScreenRow()).toBe 1
expect(displayBuffer.getMaxLineLength()).toBe 62
buffer.delete([[2, 0], [4, 0]])
expect(displayBuffer.getLongestScreenRow()).toBe 1
expect(displayBuffer.getMaxLineLength()).toBe 62
describe "::destroy()", ->
it "unsubscribes all display buffer markers from their underlying buffer marker (regression)", ->
marker = displayBuffer.markBufferPosition([12, 2])
@@ -1014,15 +1038,35 @@ describe "DisplayBuffer", ->
expect(start.left).toBe (4 * 10) + (6 * 11)
describe "decorations", ->
it "can add decorations associated with markers and remove them", ->
decoration = {type: 'gutter', class: 'one'}
[marker, decoration, decorationParams] = []
beforeEach ->
marker = displayBuffer.markBufferRange([[2, 13], [3, 15]])
decorationParams = {type: 'gutter', class: 'one'}
decoration = displayBuffer.decorateMarker(marker, decorationParams)
displayBuffer.addDecorationForMarker(marker, decoration)
it "can add decorations associated with markers and remove them", ->
expect(decoration).toBeDefined()
expect(decoration.getParams()).toBe decorationParams
expect(displayBuffer.decorationForId(decoration.id)).toBe decoration
expect(displayBuffer.decorationsForScreenRowRange(2, 3)[marker.id][0]).toBe decoration
displayBuffer.removeDecorationForMarker(marker, decoration)
decoration.destroy()
expect(displayBuffer.decorationsForScreenRowRange(2, 3)[marker.id]).not.toBeDefined()
expect(displayBuffer.decorationForId(decoration.id)).not.toBeDefined()
it "will not fail if the decoration is removed twice", ->
decoration.destroy()
decoration.destroy()
expect(displayBuffer.decorationForId(decoration.id)).not.toBeDefined()
describe "when a decoration is updated via Decoration::update()", ->
it "emits an 'updated' event containing the new and old params", ->
decoration.on 'updated', updatedSpy = jasmine.createSpy()
decoration.update type: 'gutter', class: 'two'
{oldParams, newParams} = updatedSpy.mostRecentCall.args[0]
expect(oldParams).toEqual decorationParams
expect(newParams).toEqual type: 'gutter', class: 'two', id: decoration.id
describe "::setScrollTop", ->
beforeEach ->
+211 -44
Ver Arquivo
@@ -232,6 +232,28 @@ describe "EditorComponent", ->
runSetImmediateCallbacks()
expect(component.lineNodeForScreenRow(0).textContent).toBe "a line that ends with a carriage return#{invisibles.cr}#{invisibles.eol}"
it "renders invisible line-ending characters on empty lines", ->
expect(component.lineNodeForScreenRow(10).textContent).toBe invisibles.eol
it "interleaves invisible line-ending characters with indent guides on empty lines", ->
component.setShowIndentGuide(true)
editor.setTextInBufferRange([[10, 0], [11, 0]], "\r\n", false)
runSetImmediateCallbacks()
expect(component.lineNodeForScreenRow(10).innerHTML).toBe '<span class="indent-guide"><span class="invisible-character">C</span><span class="invisible-character">E</span></span>'
editor.setTabLength(3)
runSetImmediateCallbacks()
expect(component.lineNodeForScreenRow(10).innerHTML).toBe '<span class="indent-guide"><span class="invisible-character">C</span><span class="invisible-character">E</span> </span>'
editor.setTabLength(1)
runSetImmediateCallbacks()
expect(component.lineNodeForScreenRow(10).innerHTML).toBe '<span class="indent-guide"><span class="invisible-character">C</span></span><span class="indent-guide"><span class="invisible-character">E</span></span>'
editor.setTextInBufferRange([[9, 0], [9, Infinity]], ' ')
editor.setTextInBufferRange([[11, 0], [11, Infinity]], ' ')
runSetImmediateCallbacks()
expect(component.lineNodeForScreenRow(10).innerHTML).toBe '<span class="indent-guide"><span class="invisible-character">C</span></span><span class="invisible-character">E</span>'
describe "when soft wrapping is enabled", ->
beforeEach ->
editor.setText "a line that wraps "
@@ -269,13 +291,11 @@ describe "EditorComponent", ->
line2LeafNodes = getLeafNodes(component.lineNodeForScreenRow(2))
expect(line2LeafNodes.length).toBe 3
expect(line2LeafNodes.length).toBe 2
expect(line2LeafNodes[0].textContent).toBe ' '
expect(line2LeafNodes[0].classList.contains('indent-guide')).toBe true
expect(line2LeafNodes[1].textContent).toBe ' '
expect(line2LeafNodes[1].classList.contains('indent-guide')).toBe true
expect(line2LeafNodes[2].textContent).toBe ' '
expect(line2LeafNodes[2].classList.contains('indent-guide')).toBe true
it "renders indent guides correctly on lines containing only whitespace", ->
editor.getBuffer().insert([1, Infinity], '\n ')
@@ -303,7 +323,7 @@ describe "EditorComponent", ->
it "updates the indent guides on empty lines preceding an indentation change", ->
editor.getBuffer().insert([12, 0], '\n')
runSetImmediateCallbacks()
editor.getBuffer().insert([13, 0], ' ')
editor.getBuffer().insert([13, 0], ' ')
runSetImmediateCallbacks()
line12LeafNodes = getLeafNodes(component.lineNodeForScreenRow(12))
@@ -315,7 +335,7 @@ describe "EditorComponent", ->
it "updates the indent guides on empty lines following an indentation change", ->
editor.getBuffer().insert([12, 2], '\n')
runSetImmediateCallbacks()
editor.getBuffer().insert([12, 0], ' ')
editor.getBuffer().insert([12, 0], ' ')
runSetImmediateCallbacks()
line13LeafNodes = getLeafNodes(component.lineNodeForScreenRow(13))
@@ -451,6 +471,7 @@ describe "EditorComponent", ->
expect(component.refs.gutter).not.toBeDefined()
atom.config.set("editor.showLineNumbers", true)
expect(component.refs.gutter).toBeDefined()
expect(component.lineNumberNodeForScreenRow(3)).toBeDefined()
describe "fold decorations", ->
describe "rendering fold decorations", ->
@@ -587,6 +608,33 @@ describe "EditorComponent", ->
expect(cursorRect.left).toBe rangeRect.left
expect(cursorRect.width).toBe rangeRect.width
it "positions cursors correctly after character widths are changed via a stylesheet change", ->
atom.config.set('editor.fontFamily', 'sans-serif')
editor.setCursorScreenPosition([0, 16])
runSetImmediateCallbacks()
atom.themes.applyStylesheet 'test', """
.function.js {
font-weight: bold;
}
"""
runSetImmediateCallbacks() # re-measure characters once for a synchronous set of stylesheet changes
runSetImmediateCallbacks() # update based on new measurements
cursor = node.querySelector('.cursor')
cursorRect = cursor.getBoundingClientRect()
cursorLocationTextNode = component.lineNodeForScreenRow(0).querySelector('.storage.type.function.js').firstChild
range = document.createRange()
range.setStart(cursorLocationTextNode, 0)
range.setEnd(cursorLocationTextNode, 1)
rangeRect = range.getBoundingClientRect()
expect(cursorRect.left).toBe rangeRect.left
expect(cursorRect.width).toBe rangeRect.width
atom.themes.removeStylesheet('test')
it "sets the cursor to the default character width at the end of a line", ->
editor.setCursorScreenPosition([0, Infinity])
runSetImmediateCallbacks()
@@ -743,13 +791,26 @@ describe "EditorComponent", ->
expect(selectionNode.offsetTop).toBe editor.getLineHeightInPixels()
expect(selectionNode.offsetLeft).toBe editor.pixelPositionForScreenPosition([1, 6]).left
it "will flash the selection when flash:true is passed to editor::setSelectedBufferRange", ->
editor.setSelectedBufferRange([[1, 6], [1, 10]], flash: true)
runSetImmediateCallbacks()
selectionNode = node.querySelector('.selection')
expect(selectionNode.classList.contains('flash')).toBe true
advanceClock editor.selectionFlashDuration
expect(selectionNode.classList.contains('flash')).toBe false
editor.setSelectedBufferRange([[1, 5], [1, 7]], flash: true)
runSetImmediateCallbacks()
expect(selectionNode.classList.contains('flash')).toBe true
describe "line decoration rendering", ->
[marker, decoration] = []
[marker, decoration, decorationParams] = []
beforeEach ->
marker = editor.displayBuffer.markBufferRange([[2, 13], [3, 15]], invalidate: 'inside')
decoration = {type: ['gutter', 'line'], class: 'a'}
editor.addDecorationForMarker(marker, decoration)
decorationParams = {type: ['gutter', 'line'], class: 'a'}
decoration = editor.decorateMarker(marker, decorationParams)
runSetImmediateCallbacks()
it "applies line decoration classes to lines and line numbers", ->
@@ -763,7 +824,7 @@ describe "EditorComponent", ->
# Add decorations that are out of range
marker2 = editor.displayBuffer.markBufferRange([[9, 0], [9, 0]])
editor.addDecorationForMarker(marker2, type: ['gutter', 'line'], class: 'b')
editor.decorateMarker(marker2, type: ['gutter', 'line'], class: 'b')
runSetImmediateCallbacks()
# Scroll decorations into view
@@ -786,7 +847,7 @@ describe "EditorComponent", ->
marker.destroy()
marker = editor.markBufferRange([[0, 0], [0, 2]])
editor.addDecorationForMarker(marker, type: ['gutter', 'line'], class: 'b')
editor.decorateMarker(marker, type: ['gutter', 'line'], class: 'b')
runSetImmediateCallbacks()
expect(lineNumberHasClass(0, 'b')).toBe true
expect(lineNumberHasClass(1, 'b')).toBe false
@@ -820,7 +881,7 @@ describe "EditorComponent", ->
it "remove decoration classes and unsubscribes from markers decorations are removed", ->
expect(marker.getSubscriptionCount('changed'))
editor.removeDecorationForMarker(marker, decoration)
decoration.destroy()
runSetImmediateCallbacks()
expect(lineNumberHasClass(1, 'a')).toBe false
expect(lineNumberHasClass(2, 'a')).toBe false
@@ -855,7 +916,7 @@ describe "EditorComponent", ->
describe "when the decoration's 'onlyHead' property is true", ->
it "only applies the decoration's class to lines containing the marker's head", ->
editor.addDecorationForMarker(marker, type: ['gutter', 'line'], class: 'only-head', onlyHead: true)
editor.decorateMarker(marker, type: ['gutter', 'line'], class: 'only-head', onlyHead: true)
runSetImmediateCallbacks()
expect(lineAndLineNumberHaveClass(1, 'only-head')).toBe false
expect(lineAndLineNumberHaveClass(2, 'only-head')).toBe false
@@ -864,7 +925,7 @@ describe "EditorComponent", ->
describe "when the decoration's 'onlyEmpty' property is true", ->
it "only applies the decoration when its marker is empty", ->
editor.addDecorationForMarker(marker, type: ['gutter', 'line'], class: 'only-empty', onlyEmpty: true)
editor.decorateMarker(marker, type: ['gutter', 'line'], class: 'only-empty', onlyEmpty: true)
runSetImmediateCallbacks()
expect(lineAndLineNumberHaveClass(2, 'only-empty')).toBe false
expect(lineAndLineNumberHaveClass(3, 'only-empty')).toBe false
@@ -876,7 +937,7 @@ describe "EditorComponent", ->
describe "when the decoration's 'onlyNonEmpty' property is true", ->
it "only applies the decoration when its marker is non-empty", ->
editor.addDecorationForMarker(marker, type: ['gutter', 'line'], class: 'only-non-empty', onlyNonEmpty: true)
editor.decorateMarker(marker, type: ['gutter', 'line'], class: 'only-non-empty', onlyNonEmpty: true)
runSetImmediateCallbacks()
expect(lineAndLineNumberHaveClass(2, 'only-non-empty')).toBe true
expect(lineAndLineNumberHaveClass(3, 'only-non-empty')).toBe true
@@ -887,12 +948,12 @@ describe "EditorComponent", ->
expect(lineAndLineNumberHaveClass(3, 'only-non-empty')).toBe false
describe "highlight decoration rendering", ->
[marker, decoration, scrollViewClientLeft] = []
[marker, decoration, decorationParams, scrollViewClientLeft] = []
beforeEach ->
scrollViewClientLeft = node.querySelector('.scroll-view').getBoundingClientRect().left
marker = editor.displayBuffer.markBufferRange([[2, 13], [3, 15]], invalidate: 'inside')
decoration = {type: 'highlight', class: 'test-highlight'}
editor.addDecorationForMarker(marker, decoration)
decorationParams = {type: 'highlight', class: 'test-highlight'}
decoration = editor.decorateMarker(marker, decorationParams)
runSetImmediateCallbacks()
it "does not render highlights for off-screen lines until they come on-screen", ->
@@ -901,7 +962,7 @@ describe "EditorComponent", ->
runSetImmediateCallbacks()
marker = editor.displayBuffer.markBufferRange([[9, 2], [9, 4]], invalidate: 'inside')
editor.addDecorationForMarker(marker, type: 'highlight', class: 'some-highlight')
editor.decorateMarker(marker, type: 'highlight', class: 'some-highlight')
runSetImmediateCallbacks()
# Should not be rendering range containing the marker
@@ -929,7 +990,7 @@ describe "EditorComponent", ->
expect(regions.length).toBe 2
it "removes highlights when a decoration is removed", ->
editor.removeDecorationForMarker(marker, decoration)
decoration.destroy()
runSetImmediateCallbacks()
regions = node.querySelectorAll('.test-highlight .region')
expect(regions.length).toBe 0
@@ -960,6 +1021,39 @@ describe "EditorComponent", ->
regions = node.querySelectorAll('.test-highlight .region')
expect(regions.length).toBe 2
describe "when flashing a decoration via Decoration::flash()", ->
highlightNode = null
beforeEach ->
highlightNode = node.querySelector('.test-highlight')
it "adds and removes the flash class specified in ::flash", ->
expect(highlightNode.classList.contains('flash-class')).toBe false
decoration.flash('flash-class', 10)
expect(highlightNode.classList.contains('flash-class')).toBe true
advanceClock(10)
expect(highlightNode.classList.contains('flash-class')).toBe false
describe "when ::flash is called again before the first has finished", ->
it "removes the class from the decoration highlight before adding it for the second ::flash call", ->
delayAnimationFrames = true
decoration.flash('flash-class', 10)
nextAnimationFrame()
expect(highlightNode.classList.contains('flash-class')).toBe true
advanceClock(2)
decoration.flash('flash-class', 10)
# Removed for 1 frame to force CSS transition to restart
expect(highlightNode.classList.contains('flash-class')).toBe false
nextAnimationFrame()
expect(highlightNode.classList.contains('flash-class')).toBe true
advanceClock(10)
expect(highlightNode.classList.contains('flash-class')).toBe false
describe "when a decoration's marker moves", ->
it "moves rendered highlights when the buffer is changed", ->
regionStyle = node.querySelector('.test-highlight .region').style
@@ -983,6 +1077,16 @@ describe "EditorComponent", ->
regionStyle = node.querySelector('.test-highlight .region').style
expect(parseInt(regionStyle.top)).toBe 5 * lineHeightInPixels
describe "when a decoration is updated via Decoration::update", ->
it "renders the decoration's new params", ->
expect(node.querySelector('.test-highlight')).toBeTruthy()
decoration.update(type: 'highlight', class: 'new-test-highlight')
runSetImmediateCallbacks()
expect(node.querySelector('.test-highlight')).toBeFalsy()
expect(node.querySelector('.new-test-highlight')).toBeTruthy()
describe "hidden input field", ->
it "renders the hidden input field at the position of the last cursor if the cursor is on screen and the editor is focused", ->
editor.setVerticalScrollMargin(0)
@@ -1029,7 +1133,7 @@ describe "EditorComponent", ->
expect(inputNode.offsetTop).toBe 0
expect(inputNode.offsetLeft).toBe 0
describe "mouse interactions on the scrollView", ->
describe "mouse interactions on the lines", ->
linesNode = null
beforeEach ->
@@ -1065,34 +1169,61 @@ describe "EditorComponent", ->
expect(editor.getSelectedScreenRanges()).toEqual [[[3, 4], [3, 4]], [[5, 6], [5, 6]]]
describe "when a non-folded line is double-clicked", ->
it "selects the word containing the nearest screen position", ->
linesNode.dispatchEvent(buildMouseEvent('mousedown', clientCoordinatesForScreenPosition([5, 10]), detail: 2))
linesNode.dispatchEvent(buildMouseEvent('mouseup'))
expect(editor.getSelectedScreenRange()).toEqual [[5, 6], [5, 13]]
describe "when no modifier keys are held down", ->
it "selects the word containing the nearest screen position", ->
linesNode.dispatchEvent(buildMouseEvent('mousedown', clientCoordinatesForScreenPosition([5, 10]), detail: 1))
linesNode.dispatchEvent(buildMouseEvent('mouseup'))
linesNode.dispatchEvent(buildMouseEvent('mousedown', clientCoordinatesForScreenPosition([5, 10]), detail: 2))
linesNode.dispatchEvent(buildMouseEvent('mouseup'))
expect(editor.getSelectedScreenRange()).toEqual [[5, 6], [5, 13]]
linesNode.dispatchEvent(buildMouseEvent('mousedown', clientCoordinatesForScreenPosition([6, 6]), detail: 1))
linesNode.dispatchEvent(buildMouseEvent('mouseup'))
expect(editor.getSelectedScreenRange()).toEqual [[6, 6], [6, 6]]
linesNode.dispatchEvent(buildMouseEvent('mousedown', clientCoordinatesForScreenPosition([6, 6]), detail: 1))
linesNode.dispatchEvent(buildMouseEvent('mouseup'))
expect(editor.getSelectedScreenRange()).toEqual [[6, 6], [6, 6]]
linesNode.dispatchEvent(buildMouseEvent('mousedown', clientCoordinatesForScreenPosition([8, 8]), detail: 1, shiftKey: true))
linesNode.dispatchEvent(buildMouseEvent('mouseup'))
expect(editor.getSelectedScreenRange()).toEqual [[6, 6], [8, 8]]
linesNode.dispatchEvent(buildMouseEvent('mousedown', clientCoordinatesForScreenPosition([8, 8]), detail: 1, shiftKey: true))
linesNode.dispatchEvent(buildMouseEvent('mouseup'))
expect(editor.getSelectedScreenRange()).toEqual [[6, 6], [8, 8]]
describe "when the command key is held down", ->
it "selects the word containing the newly-added cursor", ->
linesNode.dispatchEvent(buildMouseEvent('mousedown', clientCoordinatesForScreenPosition([5, 10]), detail: 1, metaKey: true))
linesNode.dispatchEvent(buildMouseEvent('mouseup'))
linesNode.dispatchEvent(buildMouseEvent('mousedown', clientCoordinatesForScreenPosition([5, 10]), detail: 2, metaKey: true))
linesNode.dispatchEvent(buildMouseEvent('mouseup'))
expect(editor.getSelectedScreenRanges()).toEqual [[[0, 0], [0, 0]], [[5, 6], [5, 13]]]
describe "when a non-folded line is triple-clicked", ->
it "selects the line containing the nearest screen position", ->
linesNode.dispatchEvent(buildMouseEvent('mousedown', clientCoordinatesForScreenPosition([5, 10]), detail: 3))
linesNode.dispatchEvent(buildMouseEvent('mouseup'))
expect(editor.getSelectedScreenRange()).toEqual [[5, 0], [6, 0]]
describe "when no modifier keys are held down", ->
it "selects the line containing the nearest screen position", ->
linesNode.dispatchEvent(buildMouseEvent('mousedown', clientCoordinatesForScreenPosition([5, 10]), detail: 1))
linesNode.dispatchEvent(buildMouseEvent('mouseup'))
linesNode.dispatchEvent(buildMouseEvent('mousedown', clientCoordinatesForScreenPosition([5, 10]), detail: 2))
linesNode.dispatchEvent(buildMouseEvent('mouseup'))
linesNode.dispatchEvent(buildMouseEvent('mousedown', clientCoordinatesForScreenPosition([5, 10]), detail: 3))
linesNode.dispatchEvent(buildMouseEvent('mouseup'))
expect(editor.getSelectedScreenRange()).toEqual [[5, 0], [6, 0]]
linesNode.dispatchEvent(buildMouseEvent('mousedown', clientCoordinatesForScreenPosition([6, 6]), detail: 1, shiftKey: true))
linesNode.dispatchEvent(buildMouseEvent('mouseup'))
expect(editor.getSelectedScreenRange()).toEqual [[5, 0], [7, 0]]
linesNode.dispatchEvent(buildMouseEvent('mousedown', clientCoordinatesForScreenPosition([6, 6]), detail: 1, shiftKey: true))
linesNode.dispatchEvent(buildMouseEvent('mouseup'))
expect(editor.getSelectedScreenRange()).toEqual [[5, 0], [7, 0]]
linesNode.dispatchEvent(buildMouseEvent('mousedown', clientCoordinatesForScreenPosition([7, 5]), detail: 1))
linesNode.dispatchEvent(buildMouseEvent('mouseup'))
linesNode.dispatchEvent(buildMouseEvent('mousedown', clientCoordinatesForScreenPosition([8, 8]), detail: 1, shiftKey: true))
linesNode.dispatchEvent(buildMouseEvent('mouseup'))
expect(editor.getSelectedScreenRange()).toEqual [[7, 5], [8, 8]]
linesNode.dispatchEvent(buildMouseEvent('mousedown', clientCoordinatesForScreenPosition([7, 5]), detail: 1))
linesNode.dispatchEvent(buildMouseEvent('mouseup'))
linesNode.dispatchEvent(buildMouseEvent('mousedown', clientCoordinatesForScreenPosition([8, 8]), detail: 1, shiftKey: true))
linesNode.dispatchEvent(buildMouseEvent('mouseup'))
expect(editor.getSelectedScreenRange()).toEqual [[7, 5], [8, 8]]
describe "when the command key is held down", ->
it "selects the line containing the newly-added cursor", ->
linesNode.dispatchEvent(buildMouseEvent('mousedown', clientCoordinatesForScreenPosition([5, 10]), detail: 1, metaKey: true))
linesNode.dispatchEvent(buildMouseEvent('mouseup'))
linesNode.dispatchEvent(buildMouseEvent('mousedown', clientCoordinatesForScreenPosition([5, 10]), detail: 2, metaKey: true))
linesNode.dispatchEvent(buildMouseEvent('mouseup'))
linesNode.dispatchEvent(buildMouseEvent('mousedown', clientCoordinatesForScreenPosition([5, 10]), detail: 3, metaKey: true))
linesNode.dispatchEvent(buildMouseEvent('mouseup'))
expect(editor.getSelectedScreenRanges()).toEqual [[[0, 0], [0, 0]], [[5, 0], [6, 0]]]
describe "when the mouse is clicked and dragged", ->
it "selects to the nearest screen position until the mouse button is released", ->
@@ -1731,6 +1862,29 @@ describe "EditorComponent", ->
line0Right = node.querySelector('.line > span:last-child').getBoundingClientRect().right
expect(cursorLeft).toBe line0Right
describe "when stylesheets change while the editor is hidden", ->
afterEach ->
atom.themes.removeStylesheet('test')
it "does not re-measure character widths until the editor is shown again", ->
atom.config.set('editor.fontFamily', 'sans-serif')
wrapperView.hide()
atom.themes.applyStylesheet 'test', """
.function.js {
font-weight: bold;
}
"""
runSetImmediateCallbacks()
wrapperView.show()
editor.setCursorBufferPosition([0, Infinity])
runSetImmediateCallbacks()
cursorLeft = node.querySelector('.cursor').getBoundingClientRect().left
line0Right = node.querySelector('.line > span:last-child').getBoundingClientRect().right
expect(cursorLeft).toBe line0Right
describe "when lines are changed while the editor is hidden", ->
it "does not measure new characters until the editor is shown again", ->
editor.setText('')
@@ -1741,9 +1895,11 @@ describe "EditorComponent", ->
wrapperView.show()
expect(node.querySelector('.cursor').style['-webkit-transform']).toBe "translate3d(#{9 * charWidth}px, 0px, 0px)"
describe "when the editor component is resized", ->
it "updates the component based on a new size", ->
describe "soft wrapping", ->
beforeEach ->
editor.setSoftWrap(true)
it "updates the wrap location when the editor is resized", ->
newHeight = 4 * editor.getLineHeightInPixels() + "px"
expect(newHeight).toBeLessThan node.style.height
node.style.height = newHeight
@@ -1758,6 +1914,16 @@ describe "EditorComponent", ->
runSetImmediateCallbacks()
expect(node.querySelector('.line').textContent).toBe "var quicksort "
it "accounts for the scroll view's padding when determining the wrap location", ->
scrollViewNode = node.querySelector('.scroll-view')
scrollViewNode.style.paddingLeft = 20 + 'px'
node.style.width = 30 * charWidth + 'px'
advanceClock(component.scrollViewMeasurementInterval)
runSetImmediateCallbacks()
expect(component.lineNodeForScreenRow(0).textContent).toBe "var quicksort = "
describe "default decorations", ->
it "applies .cursor-line decorations for line numbers overlapping selections", ->
editor.setCursorScreenPosition([4, 4])
@@ -1820,6 +1986,7 @@ describe "EditorComponent", ->
buildMouseEvent = (type, properties...) ->
properties = extend({bubbles: true, cancelable: true}, properties...)
properties.detail ?= 1
event = new MouseEvent(type, properties)
Object.defineProperty(event, 'which', get: -> properties.which) if properties.which?
if properties.target?
+15
Ver Arquivo
@@ -785,6 +785,19 @@ describe "Editor", ->
editor.moveCursorLeft()
expect(editor.getScrollLeft()).toBe 58 * 10
it "scrolls down when inserting lines makes the document longer than the editor's height", ->
editor.setCursorScreenPosition([13, Infinity])
editor.insertNewline()
expect(editor.getScrollBottom()).toBe 14 * 10
editor.insertNewline()
expect(editor.getScrollBottom()).toBe 15 * 10
it "autoscrolls to the cursor when it moves due to undo", ->
editor.insertText('abc')
editor.setScrollTop(Infinity)
editor.undo()
expect(editor.getScrollTop()).toBe 0
describe "selection", ->
selection = null
@@ -1227,6 +1240,8 @@ describe "Editor", ->
expect(editor.getSelectedBufferRanges()).toEqual [[[0, 0], [0, 0]], [[3, 4], [5, 6]]]
it "autoscrolls to the added selection if needed", ->
editor.manageScrollPosition = true
editor.setLineHeightInPixels(10)
editor.setDefaultCharWidth(10)
editor.setHeight(50)
+5 -2
Ver Arquivo
@@ -208,13 +208,16 @@ describe "Project", ->
describe "when a file doesn't exist", ->
it "calls back with an error", ->
errors = []
missingPath = path.resolve('/not-a-file.js')
expect(fs.existsSync(missingPath)).toBeFalsy()
waitsForPromise ->
atom.project.replace /items/gi, 'items', ['/not-a-file.js'], (result, error) ->
atom.project.replace /items/gi, 'items', [missingPath], (result, error) ->
errors.push(error)
runs ->
expect(errors).toHaveLength 1
expect(errors[0].path).toBe '/not-a-file.js'
expect(errors[0].path).toBe missingPath
describe "when called with unopened files", ->
it "replaces properly", ->
+1 -1
Ver Arquivo
@@ -37,7 +37,7 @@ jasmine.getEnv().addEqualityTester(_.isEqual) # Use underscore's definition of e
if process.platform is 'win32' and process.env.JANKY_SHA1
# Use longer timeout on Windows CI
jasmine.getEnv().defaultTimeoutInterval = 30000
jasmine.getEnv().defaultTimeoutInterval = 60000
else
jasmine.getEnv().defaultTimeoutInterval = 5000
+6 -6
Ver Arquivo
@@ -684,8 +684,8 @@ describe "TokenizedBuffer", ->
expect(tokenizedBuffer.lineForScreenRow(5).indentLevel).toBe 3
expect(tokenizedBuffer.lineForScreenRow(6).indentLevel).toBe 3
expect(tokenizedBuffer.lineForScreenRow(9).indentLevel).toBe 2
expect(tokenizedBuffer.lineForScreenRow(10).indentLevel).toBe 2
expect(tokenizedBuffer.lineForScreenRow(9).indentLevel).toBe 3
expect(tokenizedBuffer.lineForScreenRow(10).indentLevel).toBe 3
expect(tokenizedBuffer.lineForScreenRow(11).indentLevel).toBe 2
tokenizedBuffer.on "changed", changeHandler = jasmine.createSpy('changeHandler')
@@ -693,12 +693,12 @@ describe "TokenizedBuffer", ->
buffer.setTextInRange([[7, 0], [8, 65]], ' one\n two\n three\n four')
delete changeHandler.argsForCall[0][0].bufferChange
expect(changeHandler).toHaveBeenCalledWith(start: 5, end: 8, delta: 2)
expect(changeHandler).toHaveBeenCalledWith(start: 5, end: 10, delta: 2)
expect(tokenizedBuffer.lineForScreenRow(5).indentLevel).toBe 4
expect(tokenizedBuffer.lineForScreenRow(6).indentLevel).toBe 4
expect(tokenizedBuffer.lineForScreenRow(11).indentLevel).toBe 2
expect(tokenizedBuffer.lineForScreenRow(12).indentLevel).toBe 2
expect(tokenizedBuffer.lineForScreenRow(11).indentLevel).toBe 4
expect(tokenizedBuffer.lineForScreenRow(12).indentLevel).toBe 4
expect(tokenizedBuffer.lineForScreenRow(13).indentLevel).toBe 2
it "updates the indentLevel of empty lines surrounding a change that removes lines", ->
@@ -711,7 +711,7 @@ describe "TokenizedBuffer", ->
buffer.setTextInRange([[7, 0], [8, 65]], ' ok')
delete changeHandler.argsForCall[0][0].bufferChange
expect(changeHandler).toHaveBeenCalledWith(start: 5, end: 8, delta: -1)
expect(changeHandler).toHaveBeenCalledWith(start: 5, end: 10, delta: -1)
expect(tokenizedBuffer.lineForScreenRow(5).indentLevel).toBe 2
expect(tokenizedBuffer.lineForScreenRow(6).indentLevel).toBe 2
+19 -7
Ver Arquivo
@@ -225,9 +225,15 @@ class Atom extends Model
else
@center()
# Returns true if the dimensions are useable, false if they should be ignored.
# Work around for https://github.com/atom/atom-shell/issues/473
isValidDimensions: ({x, y, width, height}={}) ->
width > 0 and height > 0 and x + width > 0 and y + height > 0
storeDefaultWindowDimensions: ->
dimensions = JSON.stringify(atom.getWindowDimensions())
localStorage.setItem("defaultWindowDimensions", dimensions)
dimensions = @getWindowDimensions()
if @isValidDimensions(dimensions)
localStorage.setItem("defaultWindowDimensions", JSON.stringify(dimensions))
getDefaultWindowDimensions: ->
{windowDimensions} = @getLoadSettings()
@@ -240,15 +246,21 @@ class Atom extends Model
console.warn "Error parsing default window dimensions", error
localStorage.removeItem("defaultWindowDimensions")
{width, height} = screen.getPrimaryDisplay().workAreaSize
dimensions ? {x: 0, y: 0, width: Math.min(1024, width), height: height}
if @isValidDimensions(dimensions)
dimensions
else
{width, height} = screen.getPrimaryDisplay().workAreaSize
{x: 0, y: 0, width: Math.min(1024, width), height}
restoreWindowDimensions: ->
windowDimensions = @state.windowDimensions ? @getDefaultWindowDimensions()
@setWindowDimensions(windowDimensions)
dimensions = @state.windowDimensions
unless @isValidDimensions(dimensions)
dimensions = @getDefaultWindowDimensions()
@setWindowDimensions(dimensions)
storeWindowDimensions: ->
@state.windowDimensions = @getWindowDimensions()
dimensions = @getWindowDimensions()
@state.windowDimensions = dimensions if @isValidDimensions(dimensions)
# Public: Get the load settings for the current window.
#
+1
Ver Arquivo
@@ -138,6 +138,7 @@ class AtomWindow
when 'window:reload' then @reload()
when 'window:toggle-dev-tools' then @toggleDevTools()
when 'window:close' then @close()
when 'window:update-available' then @sendCommandToBrowserWindow(command, args...) # For spec testing
else if @isWebViewFocused()
@sendCommandToBrowserWindow(command, args...)
else
+24 -4
Ver Arquivo
@@ -1,3 +1,4 @@
https = require 'https'
autoUpdater = require 'auto-updater'
dialog = require 'dialog'
_ = require 'underscore-plus'
@@ -16,11 +17,12 @@ class AutoUpdateManager
constructor: (@version) ->
@state = IDLE_STATE
@feedUrl = "https://atom.io/api/updates?version=#{@version}"
# Only released versions should check for updates.
return if /\w{7}/.test(@version)
if process.platform is 'win32'
autoUpdater.checkForUpdates = => @checkForUpdatesShim()
autoUpdater.setFeedUrl "https://atom.io/api/updates?version=#{@version}"
autoUpdater.setFeedUrl @feedUrl
autoUpdater.on 'checking-for-update', =>
@setState(CHECKING_STATE)
@@ -39,7 +41,25 @@ class AutoUpdateManager
@setState(UPDATE_AVAILABLE_STATE)
@emitUpdateAvailableEvent(@getWindows()...)
@check(hidePopups: true)
# Only released versions should check for updates.
unless /\w{7}/.test(@version)
@check(hidePopups: true)
# Windows doesn't have an auto-updater, so use this method to shim the events.
checkForUpdatesShim: ->
autoUpdater.emit 'checking-for-update'
request = https.get @feedUrl, (response) ->
if response.statusCode == 200
body = ""
response.on 'data', (chunk) -> body += chunk
response.on 'end', ->
{notes, name} = JSON.parse(body)
autoUpdater.emit 'update-downloaded', null, notes, name
else
autoUpdater.emit 'update-not-available'
request.on 'error', (error) ->
autoUpdater.emit 'error', null, error.message
emitUpdateAvailableEvent: (windows...) ->
return unless @releaseVersion? and @releaseNotes
+4 -1
Ver Arquivo
@@ -45,7 +45,10 @@ class BufferedProcess
# Related to joyent/node#2318
if process.platform is "win32"
# Quote all arguments and escapes inner quotes
cmdArgs = args.map (arg) -> "\"#{arg.replace(/"/g, '\\"')}\""
if args?
cmdArgs = args.map (arg) -> "\"#{arg.replace(/"/g, '\\"')}\""
else
cmdArgs = []
cmdArgs.unshift("\"#{command}\"")
cmdArgs = ['/s', '/c', "\"#{cmdArgs.join(' ')}\""]
cmdOptions = _.clone(options)
+1
Ver Arquivo
@@ -28,6 +28,7 @@ class Cursor extends Model
# Supports old editor view
@needsAutoscroll ?= @isLastCursor() and !textChanged
@autoscroll() if @editor.manageScrollPosition and @isLastCursor() and textChanged
@goalColumn = null
+107
Ver Arquivo
@@ -0,0 +1,107 @@
_ = require 'underscore-plus'
{Subscriber, Emitter} = require 'emissary'
idCounter = 0
nextId = -> idCounter++
# Public: Represents a decoration that follows a {Marker}. A decoration is
# basically a visual representation of a marker. It allows you to add CSS
# classes to line numbers in the gutter, lines, and add selection-line regions
# around marked ranges of text.
#
# {Decoration} objects are not meant to be created directly, but created with
# {Editor::decorateMarker}. eg.
#
# ```coffee
# range = editor.getSelectedBufferRange() # any range you like
# marker = editor.markBufferRange(range)
# decoration = editor.decorateMarker(marker, {type: 'line', class: 'my-line-class'})
# ```
#
# Best practice for destorying the decoration is by destroying the {Marker}.
#
# ```
# marker.destroy()
# ```
#
# You should only use {Decoration::destroy} when you still need or do not own
# the marker.
#
# ### IDs
# Each {Decoration} has a unique ID available via `decoration.id`.
#
# ### Events
# A couple of events are emitted:
#
# * `destroyed`: When the {Decoration} is destroyed
# * `updated`: When the {Decoration} is updated via {Decoration::update}.
# Event object has properties `oldParams` and `newParams`
#
module.exports =
class Decoration
Emitter.includeInto(this)
@isType: (decorationParams, type) ->
if _.isArray(decorationParams.type)
type in decorationParams.type
else
type is decorationParams.type
constructor: (@marker, @displayBuffer, @params) ->
@id = nextId()
@params.id = @id
@flashQueue = null
@isDestroyed = false
# Public: Destroy this marker.
#
# If you own the marker, you should use {Marker:destroy} which will destroy
# this decoration.
destroy: ->
return if @isDestroyed
@isDestroyed = true
@displayBuffer.removeDecoration(this)
@emit 'destoryed'
# Public: Update the marker with new params. Allows you to change the decoration's class.
#
# ```
# decoration.update({type: 'gutter', class: 'my-new-class'})
# ```
update: (newParams) ->
return if @isDestroyed
oldParams = @params
@params = newParams
@params.id = @id
@displayBuffer.decorationUpdated(this)
@emit 'updated', {oldParams, newParams}
# Public: Returns the marker associated with this {Decoration}
getMarker: -> @marker
# Public: Returns the {Decoration}'s params.
getParams: -> @params
# Public: Check if this decoration is of type `type`
#
# type - A {String} type like `'gutter'`
#
# Returns a {Boolean}
isType: (type) ->
Decoration.isType(@params, type)
matchesPattern: (decorationPattern) ->
return false unless decorationPattern?
for key, value of decorationPattern
return false if @params[key] != value
true
flash: (klass, duration=500) ->
flashObject = {class: klass, duration}
@flashQueue ?= []
@flashQueue.push(flashObject)
@emit 'flash'
consumeNextFlash: ->
return @flashQueue.shift() if @flashQueue?.length > 0
null
+43 -39
Ver Arquivo
@@ -8,6 +8,7 @@ TokenizedBuffer = require './tokenized-buffer'
RowMap = require './row-map'
Fold = require './fold'
Token = require './token'
Decoration = require './decoration'
DisplayBufferMarker = require './display-buffer-marker'
class BufferToScreenConversionError extends Error
@@ -45,6 +46,7 @@ class DisplayBuffer extends Model
@charWidthsByScope = {}
@markers = {}
@foldsByMarkerId = {}
@decorationsById = {}
@decorationsByMarkerId = {}
@decorationMarkerChangedSubscriptions = {}
@decorationMarkerDestroyedSubscriptions = {}
@@ -202,6 +204,9 @@ class DisplayBuffer extends Model
else
@scrollLeft = Math.round(scrollLeft)
getMaxScrollLeft: ->
@getScrollWidth() - @getClientWidth()
getScrollRight: -> @scrollLeft + @width
setScrollRight: (scrollRight) ->
@setScrollLeft(scrollRight - @width)
@@ -593,6 +598,12 @@ class DisplayBuffer extends Model
getMaxLineLength: ->
@maxLineLength
# Gets the row number of the longest screen line.
#
# Return a {}
getLongestScreenRow: ->
@longestScreenRow
# Given a buffer position, this converts it into a screen position.
#
# bufferPosition - An object that represents a buffer position. It can be either
@@ -746,31 +757,17 @@ class DisplayBuffer extends Model
rangeForAllLines: ->
new Range([0, 0], @clipScreenPosition([Infinity, Infinity]))
decorationForId: (id) ->
@decorationsById[id]
decorationsForScreenRowRange: (startScreenRow, endScreenRow) ->
decorationsByMarkerId = {}
for marker in @findMarkers(intersectsScreenRowRange: [startScreenRow, endScreenRow])
if decorations = @decorationsByMarkerId[marker.id]
decorationsByMarkerId[marker.id] = decorations
decorationsByMarkerId
decorationMatchesType: (decoration, type) ->
if _.isArray(decoration.type)
type in decoration.type
else
type is decoration.type
decorationMatchesPattern: (decoration, decorationPattern) ->
return false unless decoration? and decorationPattern?
for key, value of decorationPattern
return false if decoration[key] != value
true
addDecorationForMarker: (marker, decoration) ->
unless marker?
console.warn 'A null marker cannot be decorated'
return
decorateMarker: (marker, decorationParams) ->
marker = @getMarker(marker.id)
@decorationMarkerDestroyedSubscriptions[marker.id] ?= @subscribe marker, 'destroyed', =>
@@ -785,24 +782,23 @@ class DisplayBuffer extends Model
for decoration in decorations
@emit 'decoration-changed', marker, decoration, event
decoration = new Decoration(marker, this, decorationParams)
@decorationsByMarkerId[marker.id] ?= []
@decorationsByMarkerId[marker.id].push(decoration)
@decorationsById[decoration.id] = decoration
@emit 'decoration-added', marker, decoration
decoration
removeDecorationForMarker: (marker, decorationPattern) ->
unless marker?
console.warn 'A decoration cannot be removed from a null marker'
return
removeDecoration: (decoration) ->
{marker} = decoration
return unless decorations = @decorationsByMarkerId[marker.id]
index = decorations.indexOf(decoration)
for i in [decorations.length - 1..0]
decoration = decorations[i]
if @decorationMatchesPattern(decoration, decorationPattern)
decorations.splice(i, 1)
@emit 'decoration-removed', marker, decoration
@removedAllMarkerDecorations(marker) if decorations.length is 0
if index > -1
decorations.splice(index, 1)
delete @decorationsById[decoration.id]
@emit 'decoration-removed', marker, decoration
@removedAllMarkerDecorations(marker) if decorations.length is 0
removeAllDecorationsForMarker: (marker) ->
decorations = @decorationsByMarkerId[marker.id].slice()
@@ -818,6 +814,9 @@ class DisplayBuffer extends Model
delete @decorationMarkerChangedSubscriptions[marker.id]
delete @decorationMarkerDestroyedSubscriptions[marker.id]
decorationUpdated: (decoration) ->
@emit 'decoration-updated', decoration
# Retrieves a {DisplayBufferMarker} based on its id.
#
# id - A {Number} representing a marker id
@@ -971,7 +970,7 @@ class DisplayBuffer extends Model
for marker in @getMarkers()
marker.notifyObservers(textChanged: false)
destroy: ->
destroyed: ->
marker.unsubscribe() for marker in @getMarkers()
@tokenizedBuffer.destroy()
@unsubscribe()
@@ -991,18 +990,19 @@ class DisplayBuffer extends Model
endBufferRow = @rowMap.bufferRowRangeForBufferRow(endBufferRow - 1)[1]
startScreenRow = @rowMap.screenRowRangeForBufferRow(startBufferRow)[0]
endScreenRow = @rowMap.screenRowRangeForBufferRow(endBufferRow - 1)[1]
{screenLines, regions} = @buildScreenLines(startBufferRow, endBufferRow + bufferDelta)
screenDelta = screenLines.length - (endScreenRow - startScreenRow)
@screenLines[startScreenRow...endScreenRow] = screenLines
@rowMap.spliceRegions(startBufferRow, endBufferRow - startBufferRow, regions)
@findMaxLineLength(startScreenRow, endScreenRow, screenLines)
@findMaxLineLength(startScreenRow, endScreenRow, screenLines, screenDelta)
return if options.suppressChangeEvent
changeEvent =
start: startScreenRow
end: endScreenRow - 1
screenDelta: screenLines.length - (endScreenRow - startScreenRow)
screenDelta: screenDelta
bufferDelta: bufferDelta
if options.delayChangeEvent
@@ -1057,7 +1057,7 @@ class DisplayBuffer extends Model
{screenLines, regions}
findMaxLineLength: (startScreenRow, endScreenRow, newScreenLines) ->
findMaxLineLength: (startScreenRow, endScreenRow, newScreenLines, screenDelta) ->
oldMaxLineLength = @maxLineLength
if startScreenRow <= @longestScreenRow < endScreenRow
@@ -1066,19 +1066,23 @@ class DisplayBuffer extends Model
maxLengthCandidatesStartRow = 0
maxLengthCandidates = @screenLines
else
@longestScreenRow += screenDelta if endScreenRow < @longestScreenRow
maxLengthCandidatesStartRow = startScreenRow
maxLengthCandidates = newScreenLines
for screenLine, screenRow in maxLengthCandidates
for screenLine, i in maxLengthCandidates
screenRow = maxLengthCandidatesStartRow + i
length = screenLine.text.length
if length > @maxLineLength
@longestScreenRow = maxLengthCandidatesStartRow + screenRow
@longestScreenRow = screenRow
@maxLineLength = length
@computeScrollWidth() if oldMaxLineLength isnt @maxLineLength
computeScrollWidth: ->
@scrollWidth = @pixelPositionForScreenPosition([@longestScreenRow, @maxLineLength]).left + 1
@scrollWidth = @pixelPositionForScreenPosition([@longestScreenRow, @maxLineLength]).left
@scrollWidth += 1 unless @getSoftWrap()
@setScrollLeft(Math.min(@getScrollLeft(), @getMaxScrollLeft()))
handleBufferMarkersUpdated: =>
if event = @pendingChangeEvent
@@ -1090,7 +1094,7 @@ class DisplayBuffer extends Model
@emit 'marker-created', @getMarker(marker.id)
createFoldForMarker: (marker) ->
@addDecorationForMarker(marker, type: 'gutter', class: 'folded')
@decorateMarker(marker, type: 'gutter', class: 'folded')
new Fold(this, marker)
foldForMarker: (marker) ->
+33 -22
Ver Arquivo
@@ -42,7 +42,7 @@ EditorComponent = React.createClass
scrollSensitivity: 0.4
scrollViewMeasurementRequested: false
measureLineHeightAndDefaultCharWidthWhenShown: false
remeasureCharacterWidthsWhenShown: false
remeasureCharacterWidthsIfVisibleAfterNextUpdate: false
inputEnabled: true
scrollViewMeasurementInterval: 100
scopedCharacterWidthsChangeCount: null
@@ -182,6 +182,7 @@ EditorComponent = React.createClass
@measureScrollbars()
componentWillUnmount: ->
@props.parentView.trigger 'editor:will-be-removed', [@props.parentView]
@unsubscribe()
clearInterval(@scrollViewMeasurementIntervalId)
@scrollViewMeasurementIntervalId = null
@@ -280,21 +281,22 @@ EditorComponent = React.createClass
headScreenRow = null
if marker.isValid()
for decoration in decorations
if editor.decorationMatchesType(decoration, 'gutter') or editor.decorationMatchesType(decoration, 'line')
if decoration.isType('gutter') or decoration.isType('line')
decorationParams = decoration.getParams()
screenRange ?= marker.getScreenRange()
headScreenRow ?= marker.getHeadScreenPosition().row
startRow = screenRange.start.row
endRow = screenRange.end.row
endRow-- if not screenRange.isEmpty() and screenRange.end.column == 0
for screenRow in [startRow..endRow]
continue if decoration.onlyHead and screenRow isnt headScreenRow
continue if decorationParams.onlyHead and screenRow isnt headScreenRow
if screenRange.isEmpty()
continue if decoration.onlyNonEmpty
continue if decorationParams.onlyNonEmpty
else
continue if decoration.onlyEmpty
continue if decorationParams.onlyEmpty
decorationsByScreenRow[screenRow] ?= []
decorationsByScreenRow[screenRow].push decoration
decorationsByScreenRow[screenRow] ?= {}
decorationsByScreenRow[screenRow][decoration.id] = decorationParams
decorationsByScreenRow
@@ -306,13 +308,14 @@ EditorComponent = React.createClass
screenRange = marker.getScreenRange()
if marker.isValid() and not screenRange.isEmpty()
for decoration in decorations
if editor.decorationMatchesType(decoration, 'highlight')
if decoration.isType('highlight')
decorationParams = decoration.getParams()
filteredDecorations[markerId] ?=
id: markerId
startPixelPosition: editor.pixelPositionForScreenPosition(screenRange.start)
endPixelPosition: editor.pixelPositionForScreenPosition(screenRange.end)
decorations: []
filteredDecorations[markerId].decorations.push decoration
filteredDecorations[markerId].decorations.push decorationParams
# At least in Chromium 31, removing the last highlight causes a rendering
# artifact where chunks of the lines disappear, so we always leave this
@@ -330,6 +333,7 @@ EditorComponent = React.createClass
@subscribe editor, 'decoration-added', @onDecorationChanged
@subscribe editor, 'decoration-removed', @onDecorationChanged
@subscribe editor, 'decoration-changed', @onDecorationChanged
@subscribe editor, 'decoration-updated', @onDecorationChanged
@subscribe editor, 'character-widths-changed', @onCharacterWidthsChanged
@subscribe editor.$scrollTop.changes, @onScrollTopChanged
@subscribe editor.$scrollLeft.changes, @requestUpdate
@@ -458,7 +462,7 @@ EditorComponent = React.createClass
'editor:unfold-all': => editor.unfoldAll()
'editor:fold-current-row': => editor.foldCurrentRow()
'editor:unfold-current-row': => editor.unfoldCurrentRow()
'editor:fold-selection': => neditor.foldSelectedLines()
'editor:fold-selection': => editor.foldSelectedLines()
'editor:fold-at-indent-level-1': => editor.foldAllAtIndentLevel(0)
'editor:fold-at-indent-level-2': => editor.foldAllAtIndentLevel(1)
'editor:fold-at-indent-level-3': => editor.foldAllAtIndentLevel(2)
@@ -595,15 +599,18 @@ EditorComponent = React.createClass
editor.unfoldBufferRow(bufferRow)
return
if shiftKey
editor.selectToScreenPosition(screenPosition)
else if metaKey or (ctrlKey and process.platform isnt 'darwin')
editor.addCursorAtScreenPosition(screenPosition)
else
editor.setCursorScreenPosition(screenPosition)
switch detail
when 2 then editor.selectWord()
when 3 then editor.selectLine()
switch detail
when 1
if shiftKey
editor.selectToScreenPosition(screenPosition)
else if metaKey or (ctrlKey and process.platform isnt 'darwin')
editor.addCursorAtScreenPosition(screenPosition)
else
editor.setCursorScreenPosition(screenPosition)
when 2
editor.getLastSelection().selectWord()
when 3
editor.getLastSelection().selectLine()
@handleDragUntilMouseUp event, (screenPosition) ->
editor.selectToScreenPosition(screenPosition)
@@ -648,6 +655,8 @@ EditorComponent = React.createClass
onStylesheetsChanged: (stylesheet) ->
@refreshScrollbars() if @containsScrollbarSelector(stylesheet)
@remeasureCharacterWidthsIfVisibleAfterNextUpdate = true
@requestUpdate() if @state.visible
onScreenLinesChanged: (change) ->
{editor} = @props
@@ -762,6 +771,8 @@ EditorComponent = React.createClass
if position is 'absolute' or width
clientWidth = scrollViewNode.clientWidth
paddingLeft = parseInt(getComputedStyle(scrollViewNode).paddingLeft)
clientWidth -= paddingLeft
editor.setWidth(clientWidth) if clientWidth > 0
measureLineHeightAndCharWidthsIfNeeded: (prevState) ->
@@ -782,12 +793,12 @@ EditorComponent = React.createClass
if @state.visible
@remeasureCharacterWidths()
else
@remeasureCharacterWidthsWhenShown = true
else if @remeasureCharacterWidthsWhenShown and @state.visible and not prevState.visible
@remeasureCharacterWidthsIfVisibleAfterNextUpdate = true
else if @remeasureCharacterWidthsIfVisibleAfterNextUpdate and @state.visible
@remeasureCharacterWidthsIfVisibleAfterNextUpdate = false
@remeasureCharacterWidths()
remeasureCharacterWidths: ->
@remeasureCharacterWidthsWhenShown = false
@refs.lines.remeasureCharacterWidths()
onGutterWidthChanged: (@gutterWidth) ->
+52 -62
Ver Arquivo
@@ -131,6 +131,10 @@ TextMateScopeSelector = require('first-mate').ScopeSelector
# - {::markScreenRange}
# - {::getMarker}
# - {::findMarkers}
#
# ### Decorations
# - {::decorateMarker}
# - {::decorationsForScreenRowRange}
module.exports =
class Editor extends Model
Serializable.includeInto(this)
@@ -146,6 +150,7 @@ class Editor extends Model
selections: null
suppressSelectionMerging: false
updateBatchDepth: 0
selectionFlashDuration: 500
@delegatesMethods 'suggestedIndentForBufferRow', 'autoIndentBufferRow', 'autoIndentBufferRows',
'autoDecreaseIndentForBufferRow', 'toggleLineCommentForBufferRow', 'toggleLineCommentsForBufferRows',
@@ -218,6 +223,7 @@ class Editor extends Model
@subscribe @displayBuffer, "decoration-added", (args...) => @emit 'decoration-added', args...
@subscribe @displayBuffer, "decoration-removed", (args...) => @emit 'decoration-removed', args...
@subscribe @displayBuffer, "decoration-changed", (args...) => @emit 'decoration-changed', args...
@subscribe @displayBuffer, "decoration-updated", (args...) => @emit 'decoration-updated', args...
@subscribe @displayBuffer, "character-widths-changed", (changeCount) => @emit 'character-widths-changed', changeCount
getViewClass: ->
@@ -1078,8 +1084,10 @@ class Editor extends Model
# startScreenRow - the {Number} beginning screen row
# endScreenRow - the {Number} end screen row (inclusive)
#
# Returns an {Object} of decorations in the form `{1: [{type: 'gutter', class: 'someclass'}], 2: ...}`
# where the keys are markerIds, and the values are an array of decoration objects attached to the marker.
# Returns an {Object} of decorations in the form
# `{1: [{id: 10, type: 'gutter', class: 'someclass'}], 2: ...}`
# where the keys are {Marker} IDs, and the values are an array of decoration
# params objects attached to the marker.
# Returns an empty object when no decorations are found
decorationsForScreenRowRange: (startScreenRow, endScreenRow) ->
@displayBuffer.decorationsForScreenRowRange(startScreenRow, endScreenRow)
@@ -1088,62 +1096,45 @@ class Editor extends Model
# is invalidated, or is destroyed, the decoration will be updated to reflect
# the marker's state.
#
# There are three types of supported decorations:
# * `line`: Adds your CSS `class` to the line nodes within the range
# marked by the marker
# * `gutter`: Adds your CSS `class` to the line number nodes within the
# range marked by the marker
# * `highlight`: Adds a new highlight div to the editor surrounding the
# range marked by the marker. When the user selects text, the selection is
# visualized with a highlight decoration internally. The structure of this
# highlight will be:
# ```html
# <div class="highlight <your-class>">
# <!-- Will be one region for each row in the range. Spans 2 lines? There will be 2 regions. -->
# <div class="region"></div>
# </div>
# ```
#
# marker - A {Marker} you want this decoration to follow.
# decoration - An {Object} representing the decoration eg. `{type: 'gutter', class: 'linter-error'}`
# The decoration can contain the following keys:
# * type: There are a few supported decoration types:
# * `gutter`: Applies the decoration to the line numbers spanned by the
# marker.
# * `line`: Applies the decoration to the lines spanned by the marker.
# * `highlight`: Applies the decoration to a "highlight" behind the
# marked range. When the user selects text, the selection is
# visualized with a highlight decoration internally.
# * class: This CSS class will be applied to the decorated line number,
# line, or highlight.
# * onlyHead: If `true`, the decoration will only be applied to the head
# of the marker. Only applicable to the `line` and `gutter` types.
# * onlyEmpty: If `true`, the decoration will only be applied if the
# associated marker is empty. Only applicable to the `line` and
# `gutter` types.
# * onlyNonEmpty: If `true`, the decoration will only be applied if the
# associated marker is non-empty. Only applicable to the `line` and
# gutter types.
addDecorationForMarker: (marker, decoration) ->
@displayBuffer.addDecorationForMarker(marker, decoration)
# decorationParams - An {Object} representing the decoration eg. `{type: 'gutter', class: 'linter-error'}`
# :type - There are a few supported decoration types:
# * `gutter`: Applies the decoration to the line numbers spanned by the marker.
# * `line`: Applies the decoration to the lines spanned by the marker.
# * `highlight`: Applies the decoration to a "highlight" behind the marked range.
# :class - This CSS class will be applied to the decorated line number,
# line, or highlight.
# :onlyHead - If `true`, the decoration will only be applied to the head
# of the marker. Only applicable to the `line` and `gutter` types.
# :onlyEmpty - If `true`, the decoration will only be applied if the
# associated marker is empty. Only applicable to the `line` and
# `gutter` types.
# :onlyNonEmpty - If `true`, the decoration will only be applied if the
# associated marker is non-empty. Only applicable to the `line` and
# gutter types.
#
# Returns a {Decoration} object
decorateMarker: (marker, decorationParams) ->
@displayBuffer.decorateMarker(marker, decorationParams)
# Public: Removes all decorations associated with a {Marker} that match a
# `decorationPattern` and stop tracking the {Marker}.
#
# ```coffee
# marker = editor.markBufferRange([[4, 13], [5, 17]])
# editor.removeDecorationForMarker(marker, {type: 'gutter', class: 'linter-error'})
# ```
#
# All decorations matching a pattern will be removed. For example, you might
# have decorations with a namespace like this attached to a row:
#
# ```coffee
# [
# {type: 'gutter', namespace: 'myns', class: 'something'},
# {type: 'gutter', namespace: 'myns', class: 'something-else'}
# ]
# ```
#
# You can remove both with:
#
# ```coffee
# editor.removeDecorationForMarker(marker, {namespace: 'myns'})
# ```
#
# marker - the {Marker} to detach from
# decorationPattern - the {Object} decoration type to filter by eg. `{type: 'gutter', class: 'linter-error'}`
#
# Returns nothing
removeDecorationForMarker: (marker, decorationPattern) ->
@displayBuffer.removeDecorationForMarker(marker, decorationPattern)
decorationMatchesType: (decoration, type) ->
@displayBuffer.decorationMatchesType(decoration, type)
decorationForId: (id) ->
@displayBuffer.decorationForId(id)
# Public: Get the {DisplayBufferMarker} for the given marker id.
getMarker: (id) ->
@@ -1250,9 +1241,9 @@ class Editor extends Model
addCursor: (marker) ->
cursor = new Cursor(editor: this, marker: marker)
@cursors.push(cursor)
@addDecorationForMarker(marker, type: 'gutter', class: 'cursor-line')
@addDecorationForMarker(marker, type: 'gutter', class: 'cursor-line-no-selection', onlyHead: true, onlyEmpty: true)
@addDecorationForMarker(marker, type: 'line', class: 'cursor-line', onlyEmpty: true)
@decorateMarker(marker, type: 'gutter', class: 'cursor-line')
@decorateMarker(marker, type: 'gutter', class: 'cursor-line-no-selection', onlyHead: true, onlyEmpty: true)
@decorateMarker(marker, type: 'line', class: 'cursor-line', onlyEmpty: true)
@emit 'cursor-added', cursor
cursor
@@ -1279,7 +1270,6 @@ class Editor extends Model
if selection.intersectsBufferRange(selectionBufferRange)
return selection
else
@addDecorationForMarker(marker, type: 'highlight', class: 'selection')
@emit 'selection-added', selection
selection
@@ -1294,7 +1284,7 @@ class Editor extends Model
addSelectionForBufferRange: (bufferRange, options={}) ->
@markBufferRange(bufferRange, _.defaults(@getSelectionMarkerAttributes(), options))
selection = @getLastSelection()
selection.autoscroll()
selection.autoscroll() if @manageScrollPosition
selection
# Public: Set the selected range in buffer coordinates. If there are multiple
@@ -1502,7 +1492,7 @@ class Editor extends Model
# text - A {String}
#
# Returns the {Range} of the newly-inserted text.
setTextInBufferRange: (range, text) -> @getBuffer().setTextInRange(range, text)
setTextInBufferRange: (range, text, normalizeLineEndings) -> @getBuffer().setTextInRange(range, text, normalizeLineEndings)
# Public: Get the {Range} of the paragraph surrounding the most recently added
# cursor.
+12 -6
Ver Arquivo
@@ -2,6 +2,7 @@ _ = require 'underscore-plus'
React = require 'react-atom-fork'
{div} = require 'reactionary-atom-fork'
{isEqual, isEqualForProperties, multiplyString, toArray} = require 'underscore-plus'
Decoration = require './decoration'
SubscriberMixin = require './subscriber-mixin'
WrapperDiv = document.createElement('div')
@@ -40,6 +41,7 @@ GutterComponent = React.createClass
componentDidMount: ->
@appendDummyLineNumber()
@updateLineNumbers() if @props.renderedRowRange?
# Only update the gutter if the visible row range has changed or if a
# non-zero-delta change to the screen lines has occurred within the current
@@ -153,8 +155,8 @@ GutterComponent = React.createClass
classes = ''
if lineDecorations? and decorations = lineDecorations[screenRow]
for decoration in decorations
if editor.decorationMatchesType(decoration, 'gutter')
for id, decoration of decorations
if Decoration.isType(decoration, 'gutter')
classes += decoration.class + ' '
classes += "foldable " if bufferRow >= 0 and editor.isFoldableAtBufferRow(bufferRow)
@@ -185,12 +187,13 @@ GutterComponent = React.createClass
previousDecorations = @renderedDecorationsByLineNumberId[lineNumberId]
if previousDecorations?
for decoration in previousDecorations
node.classList.remove(decoration.class) if editor.decorationMatchesType(decoration, 'gutter') and not _.deepContains(decorations, decoration)
for id, decoration of previousDecorations
if Decoration.isType(decoration, 'gutter') and not @hasDecoration(decorations, decoration)
node.classList.remove(decoration.class)
if decorations?
for decoration in decorations
if editor.decorationMatchesType(decoration, 'gutter') and not _.deepContains(previousDecorations, decoration)
for id, decoration of decorations
if Decoration.isType(decoration, 'gutter') and not @hasDecoration(previousDecorations, decoration)
node.classList.add(decoration.class)
unless @screenRowsByLineNumberId[lineNumberId] is screenRow
@@ -200,6 +203,9 @@ GutterComponent = React.createClass
@screenRowsByLineNumberId[lineNumberId] = screenRow
@lineNumberIdsByScreenRow[screenRow] = lineNumberId
hasDecoration: (decorations, decoration) ->
decorations? and decorations[decoration.id] is decoration
hasLineNumberNode: (lineNumberId) ->
@lineNumberNodesById.hasOwnProperty(lineNumberId)
+23
Ver Arquivo
@@ -11,12 +11,35 @@ HighlightComponent = React.createClass
className = 'highlight'
className += " #{decoration.class}" if decoration.class?
div {className},
if endPixelPosition.top is startPixelPosition.top
@renderSingleLineRegions()
else
@renderMultiLineRegions()
componentDidMount: ->
{editor, decoration} = @props
if decoration.id?
@decoration = editor.decorationForId(decoration.id)
@decoration.on 'flash', @startFlashAnimation
@startFlashAnimation()
componentWillUnmount: ->
@decoration?.off 'flash', @startFlashAnimation
startFlashAnimation: ->
return unless flash = @decoration.consumeNextFlash()
node = @getDOMNode()
node.classList.remove(flash.class)
requestAnimationFrame =>
node.classList.add(flash.class)
clearTimeout(@flashTimeoutId)
removeFlashClass = -> node.classList.remove(flash.class)
@flashTimeoutId = setTimeout(removeFlashClass, flash.duration)
renderSingleLineRegions: ->
{startPixelPosition, endPixelPosition, lineHeightInPixels} = @props
+2 -2
Ver Arquivo
@@ -12,12 +12,12 @@ HighlightsComponent = React.createClass
@renderHighlights() if @isMounted()
renderHighlights: ->
{highlightDecorations, lineHeightInPixels} = @props
{editor, highlightDecorations, lineHeightInPixels} = @props
highlightComponents = []
for markerId, {startPixelPosition, endPixelPosition, decorations} of highlightDecorations
for decoration in decorations
highlightComponents.push(HighlightComponent({key: "#{markerId}-#{decoration.class}", startPixelPosition, endPixelPosition, decoration, lineHeightInPixels}))
highlightComponents.push(HighlightComponent({editor, key: "#{markerId}-#{decoration.class}", startPixelPosition, endPixelPosition, decoration, lineHeightInPixels}))
highlightComponents
+32 -10
Ver Arquivo
@@ -4,6 +4,7 @@ React = require 'react-atom-fork'
{debounce, isEqual, isEqualForProperties, multiplyString, toArray} = require 'underscore-plus'
{$$} = require 'space-pen'
Decoration = require './decoration'
HighlightsComponent = require './highlights-component'
DummyLineNode = $$(-> @div className: 'line', style: 'position: absolute; visibility: hidden;', => @span 'x')[0]
@@ -134,8 +135,8 @@ LinesComponent = React.createClass
classes = ''
if decorations = lineDecorations[screenRow]
for decoration in decorations
if editor.decorationMatchesType(decoration, 'line')
for id, decoration of decorations
if Decoration.isType(decoration, 'line')
classes += decoration.class + ' '
classes += 'line'
@@ -152,14 +153,31 @@ LinesComponent = React.createClass
lineHTML
buildEmptyLineInnerHTML: (line) ->
{showIndentGuide} = @props
{showIndentGuide, invisibles} = @props
{cr, eol} = invisibles
{indentLevel, tabLength} = line
if showIndentGuide and indentLevel > 0
indentSpan = "<span class='indent-guide'>#{multiplyString(' ', tabLength)}</span>"
multiplyString(indentSpan, indentLevel + 1)
invisiblesToRender = []
invisiblesToRender.push(cr) if cr? and line.lineEnding is '\r\n'
invisiblesToRender.push(eol) if eol?
lineHTML = ''
for i in [0...indentLevel]
lineHTML += "<span class='indent-guide'>"
for j in [0...tabLength]
if invisible = invisiblesToRender.shift()
lineHTML += "<span class='invisible-character'>#{invisible}</span>"
else
lineHTML += ' '
lineHTML += "</span>"
while invisiblesToRender.length
lineHTML += "<span class='invisible-character'>#{invisiblesToRender.shift()}</span>"
lineHTML
else
"&nbsp;"
@buildEndOfLineHTML(line, @props.invisibles)
buildLineInnerHTML: (line) ->
{invisibles, mini, showIndentGuide, invisibles} = @props
@@ -222,12 +240,13 @@ LinesComponent = React.createClass
previousDecorations = @renderedDecorationsByLineId[line.id]
if previousDecorations?
for decoration in previousDecorations
lineNode.classList.remove(decoration.class) if editor.decorationMatchesType(decoration, 'line') and not _.deepContains(decorations, decoration)
for id, decoration of previousDecorations
if Decoration.isType(decoration, 'line') and not @hasDecoration(decorations, decoration)
lineNode.classList.remove(decoration.class)
if decorations?
for decoration in decorations
if editor.decorationMatchesType(decoration, 'line') and not _.deepContains(previousDecorations, decoration)
for id, decoration of decorations
if Decoration.isType(decoration, 'line') and not @hasDecoration(previousDecorations, decoration)
lineNode.classList.add(decoration.class)
lineNode.style.width = lineWidth + 'px' if updateWidth
@@ -238,6 +257,9 @@ LinesComponent = React.createClass
@screenRowsByLineId[line.id] = screenRow
@lineIdsByScreenRow[screenRow] = line.id
hasDecoration: (decorations, decoration) ->
decorations? and decorations[decoration.id] is decoration
lineNodeForScreenRow: (screenRow) ->
@lineNodesByLineId[@lineIdsByScreenRow[screenRow]]
+4
Ver Arquivo
@@ -8,6 +8,8 @@ class PaneContainer extends Model
atom.deserializers.add(this)
Serializable.includeInto(this)
@version: 1
@properties
root: -> new Pane
activePane: null
@@ -27,10 +29,12 @@ class PaneContainer extends Model
deserializeParams: (params) ->
params.root = atom.deserializers.deserialize(params.root, container: this)
params.destroyEmptyPanes = atom.config.get('core.destroyEmptyPanes')
params.activePane = params.root.getPanes().find (pane) -> pane.id is params.activePaneId
params
serializeParams: (params) ->
root: @root?.serialize()
activePaneId: @activePane.id
replaceChild: (oldChild, newChild) ->
throw new Error("Replacing non-existent child") if oldChild isnt @root
+1 -3
Ver Arquivo
@@ -40,14 +40,12 @@ class Pane extends Model
@subscribe @items.onRemoval (item, index) =>
@unsubscribe item if typeof item.on is 'function'
@activate() if params?.active
# Called by the Serializable mixin during serialization.
serializeParams: ->
id: @id
items: compact(@items.map((item) -> item.serialize?()))
activeItemUri: @activeItem?.getUri?()
focused: @focused
active: @active
# Called by the Serializable mixin during deserialization.
deserializeParams: (params) ->
+12 -9
Ver Arquivo
@@ -38,17 +38,20 @@ class ReactEditorView extends View
@overlayer = $(node).find('.lines').addClass('overlayer')
@hiddenInput = $(node).find('.hidden-input')
@gutter = $(node).find('.gutter')
@gutter.removeClassFromAllLines = (klass) =>
@gutter.find('.line-number').removeClass(klass)
# FIXME: there should be a better way to deal with the gutter element
@subscribe atom.config.observe 'editor.showLineNumbers', =>
@gutter = $(node).find('.gutter')
@gutter.getLineNumberElement = (bufferRow) =>
@gutter.find("[data-buffer-row='#{bufferRow}']")
@gutter.removeClassFromAllLines = (klass) =>
@gutter.find('.line-number').removeClass(klass)
@gutter.addClassToLine = (bufferRow, klass) =>
lines = @gutter.find("[data-buffer-row='#{bufferRow}']")
lines.addClass(klass)
lines.length > 0
@gutter.getLineNumberElement = (bufferRow) =>
@gutter.find("[data-buffer-row='#{bufferRow}']")
@gutter.addClassToLine = (bufferRow, klass) =>
lines = @gutter.find("[data-buffer-row='#{bufferRow}']")
lines.addClass(klass)
lines.length > 0
@focus() if @focusOnAttach
+6 -1
Ver Arquivo
@@ -15,6 +15,8 @@ class Selection extends Model
constructor: ({@cursor, @marker, @editor, id}) ->
@assignId(id)
@cursor.selection = this
@decoration = @editor.decorateMarker(@marker, type: 'highlight', class: 'selection')
@marker.on 'changed', => @screenRangeChanged()
@marker.on 'destroyed', =>
@destroyed = true
@@ -76,9 +78,12 @@ class Selection extends Model
options.reversed ?= @isReversed()
@editor.destroyFoldsIntersectingBufferRange(bufferRange) unless options.preserveFolds
@modifySelection =>
needsFlash = options.flash
delete options.flash if options.flash?
@cursor.needsAutoscroll = false if @needsAutoscroll?
@marker.setBufferRange(bufferRange, options)
@autoscroll() if @needsAutoscroll and @editor.manageScrollPosition
@decoration.flash('flash', @editor.selectionFlashDuration) if needsFlash
# Public: Returns the starting and ending buffer rows the selection is
# highlighting.
@@ -315,12 +320,12 @@ class Selection extends Model
wasReversed = @isReversed()
@clear()
@cursor.needsAutoscroll = @cursor.isLastCursor()
@cursor.autoscroll() if @editor.manageScrollPosition and @cursor.isLastCursor()
if options.indentBasis? and not options.autoIndent
text = @normalizeIndents(text, options.indentBasis)
newBufferRange = @editor.buffer.setTextInRange(oldBufferRange, text, pick(options, 'undo'))
if options.select
@setBufferRange(newBufferRange, reversed: wasReversed)
else
+8 -3
Ver Arquivo
@@ -231,22 +231,27 @@ class TokenizedBuffer extends Model
indentLevelForRow: (row) ->
line = @buffer.lineForRow(row)
indentLevel = 0
if line is ''
nextRow = row + 1
lineCount = @getLineCount()
while nextRow < lineCount
nextLine = @buffer.lineForRow(nextRow)
return @indentLevelForLine(nextLine) unless nextLine is ''
unless nextLine is ''
indentLevel = Math.ceil(@indentLevelForLine(nextLine))
break
nextRow++
previousRow = row - 1
while previousRow >= 0
previousLine = @buffer.lineForRow(previousRow)
return @indentLevelForLine(previousLine) unless previousLine is ''
unless previousLine is ''
indentLevel = Math.max(Math.ceil(@indentLevelForLine(previousLine)), indentLevel)
break
previousRow--
0
indentLevel
else
@indentLevelForLine(line)
+7 -7
Ver Arquivo
@@ -64,15 +64,15 @@
}
.btn-toolbar {
> .btn-group {
> .btn-group + .btn-group, > .btn-group + .btn, > .btn + .btn {
float: none;
display: inline-block;
}
> * {
margin-right: 0;
margin-left: @component-padding/2;
}
> *:first-child {
margin-left: 0;
}
> * {
margin-right: @component-padding / 2;
}
> *:last-child {
margin-right: 0;
}
}
+5
Ver Arquivo
@@ -179,6 +179,11 @@
box-shadow: inset 1px 0;
}
.editor .vertical-scrollbar,
.editor .horizontal-scrollbar {
cursor: default;
}
.editor .vertical-scrollbar {
position: absolute;
top: 0;
+14
Ver Arquivo
@@ -19,3 +19,17 @@
}
}
}
.define-selection-flash-color-if-not-defined() { @syntax-selection-flash-color: rgba(100, 255, 100, 0.7); }
.define-selection-flash-color-if-not-defined();
@-webkit-keyframes flash {
from { background-color: @syntax-selection-flash-color; }
to { background-color: null; }
}
.editor .flash.selection .region {
-webkit-animation-name: flash;
-webkit-animation-duration: .5s;
-webkit-animation-iteration-count: 1;
}
+1
Ver Arquivo
@@ -5,6 +5,7 @@
@syntax-text-color: #333;
@syntax-cursor-color: #333;
@syntax-selection-color: #69c;
@syntax-selection-flash-color: #00f; // Color the selection is 'flashed' when you run find next
@syntax-background-color: #fff;
// Guide colors