Comparar commits

...

391 Commits

Autor SHA1 Mensagem Data
Kevin Sawicki a92eed5107 Upgrade to background-tips@0.15 2014-07-02 09:51:09 -07:00
Nathan Sobo 66319ca9c0 Merge pull request #2801 from atom/ns-react-fix-jitter
Fix jitter in React editor
2014-07-02 10:34:01 -06:00
Nathan Sobo 17fa580ecd Ignore 'scroll' events when an update is pending
This prevents feedback loops where we handle stale 'scroll' events
for scrolls requested in the model layer. It prevents jitter when
autoscrolling with the cursor.
2014-07-02 10:11:35 -06:00
probablycorey 2585c10688 Upgrade to language-less@v0.11.0 2014-07-02 09:03:46 -07:00
Nathan Sobo 7202f497db Pause scroll view measurement in requestAnimationFrame helper method 2014-07-02 09:30:44 -06:00
Nathan Sobo 9508909a9f Don't defer updates with setImmediate in animation frames
I previously thought this was okay, but now I'm experiencing jitter when
scrolling with the trackpad when updates are deferred, and the frames
seem jagged. So this commit restores a synchronous approach to display
updates whenever we use animation frames.
2014-07-02 09:26:24 -06:00
Nathan Sobo e5ab2c6507 Pause scroll view measurement when requesting animation frames
We don't want any extra DOM reading that could introduce hitches in
the animation we're running.
2014-07-02 08:47:32 -06:00
Nathan Sobo 8add5ccd7e Remove unused EditorComponent::componentWillUpdate hook 2014-07-02 08:46:56 -06:00
Kevin Sawicki d3829e2fc6 Merge pull request #2792 from atom/document-atom-io-stargazers
Document stargazers endpoint for atom.io
2014-07-01 16:08:32 -07:00
Kevin Sawicki c26f6cc7f7 Add the 2014-07-01 16:08:18 -07:00
Kevin Sawicki 3250888e05 Add missing comma 2014-07-01 15:55:13 -07:00
Kevin Sawicki 2e6ef6848a Fence blocks as JSON 2014-07-01 15:55:02 -07:00
Ben Ogle 74bcbf6291 Upgrade themes to fix blurry tabs
Refs atom/tabs#62
2014-07-01 15:46:47 -07:00
Daniel Hengeveld ab947082dc add stargazers docs for apm 2014-07-01 15:29:04 -07:00
probablycorey 9e31bc5179 Remove runs description 2014-07-01 14:26:44 -07:00
Corey Johnson be1a2f9e30 Merge pull request #2784 from maschs/ms-writingSpecsMD
writing-specs.md: Add examples for async/promise specs
2014-07-01 14:22:12 -07:00
Kevin Sawicki 9fe887191d Upgrade to whitespace@0.23 2014-07-01 13:55:04 -07:00
Ben Ogle b0031e493e Merge pull request #2737 from atom/bo-fix-indent-guide
Fix indent guide
2014-07-01 13:46:25 -07:00
Ben Ogle 1fa6661efd Remove the awkward _.pick 2014-07-01 11:48:36 -07:00
Nathan Sobo 8b57bb3309 Merge pull request #2789 from atom/ns-react-disable-gpu-option
Add editor.gpuDisabled option to prevent React editor from using layers
2014-07-01 12:48:34 -06:00
Kevin Sawicki 8b2e1b088a Merge pull request #2788 from atom/ks-add-chocolatey-ignores
Add chocolatey ignores
2014-07-01 11:48:12 -07:00
Ben Ogle dcb0d9b039 Update editor component specs 2014-07-01 11:41:44 -07:00
Nathan Sobo 4efabd2b5e 💄 method name 2014-07-01 12:34:00 -06:00
Nathan Sobo 18d17b55b5 Pass useHardwareAcceleration property down to CursorComponent instances 2014-07-01 12:33:45 -06:00
Ben Ogle 718e1228bd Add checks for the change event 2014-07-01 11:32:04 -07:00
Kevin Sawicki 22b0a35dba Add comment mentioning chocoloatey 2014-07-01 11:29:33 -07:00
Kevin Sawicki e395b1416a Add chocolatey gui for atom.exe 2014-07-01 11:19:54 -07:00
Nathan Sobo 0edfbaebeb Rename editor option to useHardwareAcceleration 2014-07-01 12:17:43 -06:00
Ben Ogle 3e57fb8e9a 💄 naming 2014-07-01 10:59:42 -07:00
Nathan Sobo 512d4da587 Add editor.gpuDisabled option to prevent React editor from using layers
When gpuDisabled is true, we use `translate` instead of `translate3d`
to position various elements, preventing the creation of GPU layers.
2014-07-01 11:56:05 -06:00
Ben Ogle de0e945c5c More specs in tokenized buffer testing empty line retokenizing 2014-07-01 10:54:37 -07:00
Ben Ogle & Nathan Sobo 4642d96f39 Tokenize empty lines with a changed indent level synchronously 2014-07-01 10:54:37 -07:00
Ben Ogle de2930fe99 💄 2014-07-01 10:54:37 -07:00
Ben Ogle 65c2f26656 Little note 📝 2014-07-01 10:54:36 -07:00
Ben Ogle 8ca709eb6a Fix spec name 2014-07-01 10:54:36 -07:00
Ben Ogle 43e88f6515 Invalidate whitespace lines when their indent level changes
Refs #2376
2014-07-01 10:54:36 -07:00
Ben Ogle d97eacc2f9 Add isOnlyWhitespace() 2014-07-01 10:54:36 -07:00
Kevin Sawicki a70367c70b Add chocolatey ignore for ctags-win32.exe 2014-07-01 10:45:32 -07:00
Ben Ogle d60c718fe2 Merge pull request #2783 from atom/bo-up-scandal
Upgrade scandal to handle file read errors
2014-07-01 10:45:27 -07:00
Kevin Sawicki fe838375a1 Add chocolatey ignore for node.exe 2014-07-01 10:45:25 -07:00
Ben Ogle 06d06d10e0 💄 2014-07-01 10:45:13 -07:00
Ben Ogle de9f070f53 Upgrade find-and-replace
It will display errors from scandal.
2014-07-01 10:45:13 -07:00
Ben Ogle a6e437b9d3 Upgrade scandal
This version emits events when errors are encountered with file reading.
2014-07-01 10:44:30 -07:00
Ben Ogle 44b95fc637 Emit errors from the out of process searches 2014-07-01 10:44:30 -07:00
Nathan Sobo e93e4e9333 Autoscroll to the last cursor in model when inserting text
Fixes #2787
2014-07-01 11:37:17 -06:00
Nathan Sobo d4a7bff525 Merge pull request #2608 from philschatz/ps-dedupe-context-menu
remove duplicate context menu entries
2014-07-01 11:08:18 -06:00
Nathan Sobo 5e78bbf471 Upgrade fuzzy finder to support traversing symlinked directories 2014-07-01 10:53:59 -06:00
Kevin Sawicki 873abd68af Merge pull request #2767 from smashwilson/ignore-desktop
Ignore generated files in resources/linux.
2014-07-01 09:50:11 -07:00
Nathan Sobo d42a064a44 Merge pull request #2773 from atom/ns-react-fix-delete-line-jitter
Fix scroll jitter when deleting a line reduces the maximum allowed scrollTop
2014-07-01 09:27:58 -06:00
Nathan Sobo 32c8a3ce99 Only adjust scrollTop when deleting lines when using the React editor 2014-07-01 09:16:29 -06:00
Nathan Sobo a99bde4e2d Reassign scrollTop if deleting lines decreases the max scrollTop
Fixes #2725
2014-07-01 09:01:04 -06:00
Maximilian Schüßler 5753680b58 Minor changes 2014-07-01 13:26:47 +02:00
Maximilian Schüßler 68ddbd9e75 📝 Add examples for async/promise specs 2014-07-01 02:51:47 +02:00
probablycorey e6725c9fcb Fix prepare docs 2014-06-30 11:48:10 -07:00
Corey Johnson b14317cf50 Merge pull request #2753 from atom/cj-dh-publish-docs
Build and publish API docs
2014-06-30 11:09:05 -07:00
Nathan Sobo bb6a44a757 Hard code node-runas to 0.5.4 trying to fix the build 2014-06-30 17:32:01 +01:00
Nathan Sobo 431fc725ff Interpret editor clicks relative to lines div, not the scrollView div
Fixes #2668

If the scroll view has padding, using it as the basis for locating
clicks relative to the lines is problematic.
2014-06-30 16:24:07 +01:00
Ash Wilson 72d5a4cdae Ignore generated files in resources/linux. 2014-06-29 09:34:24 -04:00
Nathan Sobo f5517bad66 Merge pull request #2757 from atom/ns-better-default-decorations
Improve default decorations for cursor and selection lines in React editor
2014-06-28 16:04:12 +01:00
Kevin Sawicki a63797019d Upgrade to language-less@0.10 2014-06-28 15:57:28 +01:00
Nathan Sobo 324f1392a3 Revert changes related to the .selection-line class
We will introduce .selection-line as part of a separate effort, not the
React switchover.
2014-06-28 15:52:10 +01:00
Nathan Sobo 21ae33f749 Merge pull request #2763 from atom/ns-react-fix-autoscroll
Autoscroll cursor when attempting to move it, even if it doesn't move
2014-06-28 15:42:31 +01:00
Nathan Sobo 15ca3e2a40 Match existing editor's behavior for .cursor-line class 2014-06-28 15:39:22 +01:00
Nathan Sobo ea9f5eb1c7 💄 Unify specs for all line decorations 2014-06-28 15:39:22 +01:00
Nathan Sobo 7f70b41696 Update the specs for .cursor/selection-line decorations 2014-06-28 15:39:22 +01:00
Nathan Sobo 9a6510c938 Add .cursor-line-no-selection decoration for backward compatibility 2014-06-28 15:39:22 +01:00
Nathan Sobo 825910dc1d Add onlyEmpty and onlyNonEmpty decoration options 2014-06-28 15:39:22 +01:00
Nathan Sobo bd238d6885 Add specs for gutter decoration options
- onlyHead
- onlyEmpty
- onlyNonEmpty
2014-06-28 15:39:22 +01:00
Nathan Sobo 8435e0176b Add selection-line class to old editor gutter for forward-compatibility
The React editor does not apply the .cursor-line-no-selection class,
but instead relies on a combination of .cursor-line and .selection-line
for selectors that want to target the cursor line when there is no
selection.

This allows themes to be upgraded to support the React editor and the
old editor at the same time.
2014-06-28 15:39:21 +01:00
Nathan Sobo 5bdaf3cbe4 Make both .cursor-line and .selection-line opaque 2014-06-28 15:39:21 +01:00
Nathan Sobo f5e54b0ba6 Only add 'selection-line' decoration when marker is non-empty 2014-06-28 15:39:21 +01:00
Nathan Sobo fa7e388352 Add 'onlyEmpty' and 'onlyNonEmpty' decoration options 2014-06-28 15:39:21 +01:00
Nathan Sobo 70f352251e Only apply cursor-line decoration to head; Add selected-line decoration.
The cursor-line decoration shouldn't be applied to every line that's
selected. It should only be applied to the location of the cursor. We'll
need to update themes to reflect this.
2014-06-28 15:39:21 +01:00
Nathan Sobo 1b05708d7a Update addDecorationForMarker docs to talk about 'onlyHead' option 2014-06-28 15:39:21 +01:00
Nathan Sobo a2b90cd501 Add 'onlyHead' option for decorations
It only decorates the head position of the decoration's marker.
2014-06-28 15:39:21 +01:00
Nathan Sobo 61c7e797b9 Upgrade markdown-preview to hopefully fix flaky spec 2014-06-28 15:38:59 +01:00
Nathan Sobo b689ffd402 Autoscroll cursor when attempting to move it, even if it doesn't move 2014-06-28 15:26:02 +01:00
Nathan Sobo 71fb063a67 Un-f 2014-06-28 15:24:24 +01:00
Nathan Sobo b376bd8688 Fix scrollbar dragging in React editor
Fixes #2751
2014-06-28 11:33:41 +01:00
probablycorey e068d3d293 Merge remote-tracking branch 'origin/master' into cj-dh-publish-docs 2014-06-27 11:04:23 -07:00
probablycorey a49221e359 Upgrade to language-go@v0.13.0 2014-06-27 10:32:14 -07:00
probablycorey e7aef25f1f Update tokenized buffer specs 2014-06-27 10:18:04 -07:00
probablycorey 071b391994 Describe surrogate pair as UTF-8 surrogate pair 2014-06-27 10:17:28 -07:00
probablycorey 7b11343ea8 Remove semi-colon 2014-06-27 09:37:05 -07:00
probablycorey d25f432400 Upgrade to tree-view@v0.108.0 2014-06-27 09:36:12 -07:00
probablycorey 2e16f2dc3f Upgrade to first-mate@1.7.1 2014-06-27 09:31:19 -07:00
probablycorey f828b91686 Only prepare docs on darwin platforms. 2014-06-27 08:53:43 -07:00
probablycorey 3f4210c293 Only publish build if on janky and using the master branch 2014-06-27 08:52:12 -07:00
Kevin Sawicki 0f7b97821b Upgrade ot markdown-preview@0.85 2014-06-27 12:44:20 +01:00
Kevin Sawicki efa457bade Upgrade to settings-view@0.129 2014-06-27 12:33:06 +01:00
Kevin Sawicki 61188cb05f Upgrade to image-view@0.36 2014-06-27 09:42:26 +01:00
Kevin Sawicki 69c3001836 Upgrade to language-javascript@0.30 2014-06-27 09:35:01 +01:00
probablycorey 81afb89d27 Copy API docs to the build dir 2014-06-26 16:14:54 -07:00
Corey Johnson & Daniel Hengeveld 2107b10778 Add upload-assets grunt task 2014-06-26 15:02:18 -07:00
Corey Johnson & Daniel Hengeveld bc31f94833 Add getAssets method 2014-06-26 15:01:26 -07:00
Corey Johnson & Daniel Hengeveld 58c2cec787 Rename sourceName to sourcePath 2014-06-26 14:37:21 -07:00
Corey Johnson & Daniel Hengeveld 2c95af63e6 Rename zipApp to zipAssets 2014-06-26 14:33:09 -07:00
Corey Johnson & Daniel Hengeveld 8a377c9339 Make docs output dir a config var 2014-06-26 14:30:43 -07:00
Corey Johnson & Daniel Hengeveld e21f561af5 Add Daniel to pairs file 2014-06-26 14:25:40 -07:00
probablycorey ccb01c23d2 💄 Add spacing between packages and languages packages 2014-06-26 11:53:37 -07:00
probablycorey 3bc50c9b2c Upgrade to language-javascript@v0.29.0 2014-06-26 11:52:52 -07:00
probablycorey 18c5f9c8de Upgrade to tree-view@0.107.0 2014-06-26 11:52:06 -07:00
Ben Ogle 7179bc5af1 Merge pull request #2738 from atom/bo-fix-max-scroll-width
Fix max scroll width in react editor
2014-06-25 18:16:32 -07:00
Nathan Sobo 3bf0c73170 Assign line width explicitly to prevent full screen repaints
Fixes #2746
2014-06-25 19:13:50 -06:00
Nathan Sobo 95242c8c82 Merge pull request #2747 from atom/ns-set-immediate
Use setImmediate instead of nextTick to batch React editor updates
2014-06-25 18:48:47 -06:00
Nathan Sobo eb84737109 Fix specs for use of setImmediate instead of nextTick in requestUpdate 2014-06-25 18:38:06 -06:00
Nathan Sobo 2b54c9bebe Use setImmediate to batch all editor updates, even in animation frames
When I was using nextTick to batch updates, there were issues with
flicker. So I was attempting to always update synchronously in animation
frames, which was complicated. setImmediate doesn't cause the flicker
however, so I'm able to remove the special logic for sync updates in
animation frames and just use it across the board.
2014-06-25 18:20:49 -06:00
Nathan Sobo 63e8099088 Allow successive accented characters to be inserted in React editor
Refs #2732

Because we're only checking the length of the input element's selection
in the React editor on textinput events and not also its content, we
were mistaking some IME compositions as accented character menu
insertions. Clearing the content of the input on 'compositionend'
prevents this issue.
2014-06-25 18:19:53 -06:00
Ben Ogle & Nathan Sobo f739dce210 Only recompute scroll width once for each batch of measured chars 2014-06-25 15:26:13 -07:00
Ben Ogle & Nathan Sobo 77389b0518 Update scrollWidth when the max line length / default char width changes 2014-06-25 15:26:13 -07:00
Ben Ogle 809804d0cc 💄 2014-06-25 15:26:13 -07:00
Ben Ogle 8054b769d6 Default scrollWidth to 0 2014-06-25 15:26:13 -07:00
Ben Ogle e3c3779a73 Don’t need to return the list. So just return 2014-06-25 15:26:13 -07:00
Ben Ogle 196f64d846 Fix specs 2014-06-25 15:26:13 -07:00
Ben Ogle 9cc1244f32 Compute the longest line width based on the longest line 2014-06-25 15:26:13 -07:00
Ben Ogle 1c69995bb6 Upgrade command-palette with better description 2014-06-25 15:04:26 -07:00
Kevin Sawicki 7c4cbd8bf9 Upgrade to open-on-github@0.29.0 2014-06-25 13:04:51 -07:00
probablycorey 570f59a7e2 Upgrade to tree-view@0.106.0 2014-06-25 10:06:33 -07:00
Nathan Sobo 8d71e3f69a Merge pull request #2740 from atom/bo-round-scroll-vars
Never allow partial pixel values for scroll
2014-06-25 09:45:47 -06:00
Kevin Sawicki 0263d72551 Upgrade to language-gfm@0.42 2014-06-25 08:30:37 -07:00
Kevin Sawicki 9299ff3404 📝 Remove observeConfig
Replaced with subscribe/atom.config.observe

Closes #2742
2014-06-25 08:11:30 -07:00
Cheng Zhao 7c79643b89 Upgrade to atom-shell@0.13.3 2014-06-25 09:52:51 +08:00
Kevin Sawicki 6a4b4d2efd Upgrade to language-gfm@0.41 2014-06-24 18:24:47 -07:00
Ben Ogle d6f217f80a Never allow partial pixel values for scroll 2014-06-24 18:09:03 -07:00
Nathan Sobo 1f94e89e56 Merge pull request #2739 from atom/ns-react-raf-vs-next-tick
Only perform a single synchronous update inside animation frames
2014-06-24 19:08:10 -06:00
Nathan Sobo 27a959ec16 Combine all updates that occur in an animation frame 2014-06-24 18:48:59 -06:00
Kevin Sawicki 0369d77c85 Ensure grammars are only activated once 2014-06-24 16:21:56 -07:00
Ben Ogle 866bc02d68 💄 Inline the gutter component 2014-06-24 14:47:26 -07:00
Ivan Žužak ae96d9aeaa Upgrade to tree-view@0.105.0 2014-06-24 22:15:42 +02:00
Nathan Sobo 5481b37d01 Merge pull request #2735 from atom/ns-react-precompute-pixel-rects
Compute pixel rects of cursors and highlights in EditorComponent
2014-06-24 13:34:56 -06:00
Nathan Sobo b127155805 Only pause cursor blink when cursors actually move
Not when they are just repositioned due to lineHeight/charWidth changes
2014-06-24 13:26:21 -06:00
Nathan Sobo 74dbfbc956 Add HighlightComponent::shouldComponentUpdate 2014-06-24 13:04:48 -06:00
Nathan Sobo f41a9739ac 💄 2014-06-24 13:02:41 -06:00
Nathan Sobo b75e748ec5 Restore pausing of cursor blink on cursor movement 2014-06-24 12:59:13 -06:00
Nathan Sobo 3f9fdad478 Precompute pixel rects for highlight decorations in EditorComponent 2014-06-24 12:56:52 -06:00
Nathan Sobo 0150b40376 Implement CursorComponent::shouldComponentUpdate
This prevents re-rendering cursors on blink, since only the class on
the outer component changes.
2014-06-24 12:42:58 -06:00
Nathan Sobo d3e6bd038f Precompute cursor pixel rects in EditorComponent and pass them down 2014-06-24 12:40:56 -06:00
Ben Ogle b7d8e581ee Merge pull request #2727 from atom/bo-subscribe-to-marker-changes
Subscribe to marker changes
2014-06-24 11:15:47 -07:00
Kevin Sawicki daaf9be4bf Upgrade to language-java@0.11 2014-06-24 10:50:10 -07:00
Ben Ogle 396b21bc04 Fix specs failures caused by making lines 100% width 2014-06-24 10:32:48 -06:00
Kevin Sawicki d4617f1036 Upgrade to timecop@0.21 2014-06-24 09:04:09 -07:00
Kevin Sawicki 6cb5af0bfc Map ctrl-pageup/down to pane:show-next/previous-item
Closes #2724
2014-06-24 08:44:26 -07:00
Kevin Sawicki 1c2e997415 Merge pull request #2700 from atom/bo-grammar-preload
Preload grammars on deserialization
2014-06-24 08:26:57 -07:00
Kevin Sawicki 148b691734 Test grammars included across multiple packages 2014-06-24 08:14:11 -07:00
Ben Ogle 9b577ecbf8 Make lines 100% of the width of their container
This is part of the solution to #2701. Lines need to be 100% wide in
case a class styles their background.
2014-06-23 22:46:27 -06:00
Ben Ogle d57119793b Properly disable nextTick when calling requestAnimationFrame
My previous commit was nonsense because it set the ::performSyncUpdates
flag back to false before the animation frame callback ever got fired.

/cc again @benogle
2014-06-23 22:35:40 -06:00
Ben Ogle ccada33d57 Remove nextTick in spec 2014-06-23 22:27:40 -06:00
Ben Ogle 1d9514ca81 Don't call nextTick within requestAnimationFrame
This seems to be causing stutter when scrolling on the GPU. When I don't
use nextTick when requesting animation frames, the problem seems to go
away. Maybe there's some issue with the integration between the Node
and Chromium event loops plus sending things to the compositor.

/cc @benogle
2014-06-23 22:21:28 -06:00
Ben Ogle 5ebb17c2e8 Be defensive when iterating through decorations 2014-06-23 18:03:19 -07:00
Kevin Sawicki f741b1d6a6 Store timings for deserializing project and workspace 2014-06-23 17:46:44 -07:00
Ben Ogle 36280bb3a7 Add noop for resetDisplay
fixes #2674
2014-06-23 17:46:35 -07:00
Kevin Sawicki 15ccfac75a 💄 2014-06-23 17:46:31 -07:00
Kevin Sawicki 2e424baf2a Use correct expected call count 2014-06-23 17:41:33 -07:00
Kevin Sawicki 0547d5a78b Assert grammars are sync loaded on deserialize 2014-06-23 17:36:14 -07:00
Kevin Sawicki 5529f13cc6 Only create grammar load promise once 2014-06-23 17:33:05 -07:00
Ben Ogle 058ab7d486 Upgrade find-and-replace to clean up specs 2014-06-23 17:16:07 -07:00
Kevin Sawicki 0a54233ef0 Merge branch 'master' into bo-grammar-preload 2014-06-23 17:05:48 -07:00
Ben Ogle b4f4ef8ec4 💄
Make it not suck.
2014-06-23 17:04:32 -07:00
Kevin Sawicki e11785ce98 Serialize packages names in Workspace 2014-06-23 16:56:46 -07:00
Kevin Sawicki b1d7de8d43 Add spec for serializing active grammars 2014-06-23 16:41:46 -07:00
Kevin Sawicki becdca0858 Store grammars in Atom::unloadEditorWindow 2014-06-23 16:30:02 -07:00
Kevin Sawicki c9e3ca3d69 Remove logging 2014-06-23 16:23:07 -07:00
Kevin Sawicki 6336ffbf44 Store included grammar scopes 2014-06-23 16:22:37 -07:00
Kevin Sawicki 6aeca79d1b Return empty promise when already loaded 2014-06-23 16:13:13 -07:00
Kevin Sawicki e76b24f8ad Catch error 2014-06-23 16:04:25 -07:00
Kevin Sawicki 0304f187dd Remove preload request from deserializeParams 2014-06-23 16:03:56 -07:00
Kevin Sawicki 968ab0e41d Remove unused methods 2014-06-23 16:02:45 -07:00
Kevin Sawicki ea6feddd7b Track duration of grammar preload 2014-06-23 16:00:58 -07:00
Ben Ogle f381abcbad Re-render when a marker changes
fixes #2705
2014-06-23 16:00:36 -07:00
Kevin Sawicki bb5d628397 Track packages to preload in Atom class 2014-06-23 15:59:26 -07:00
Kevin Sawicki f3d87b1653 Set packageName property on Grammar objects 2014-06-23 15:58:06 -07:00
Ben Ogle & Nathan Sobo 76a911f17a Render highlights immediately to support underlayer shim 2014-06-23 16:23:45 -06:00
Ben Ogle 7139fd9f98 Conditionally render the gutter for the showLineNumbers option
Fixes #2707
2014-06-23 15:22:16 -07:00
Kevin Sawicki 64e2b53baa Add cursor with ctrl-click on Windows/Linux
Closes #2105
2014-06-23 14:43:00 -07:00
Kevin Sawicki 78630a14fd Upgrade to language-yaml@0.10 2014-06-23 14:12:50 -07:00
Kevin Sawicki 38fbcbdf89 Upgrade to symbols-view@0.59 2014-06-23 14:11:14 -07:00
probablycorey 6e102c7e1e Rename regex var to a more appropriate name 2014-06-23 10:51:58 -07:00
Kevin Sawicki f40c8a97c0 Upgrade to markdown-preview@0.84 2014-06-23 10:43:40 -07:00
Nathan Sobo b9a3eca091 Correcly handle folds that end where other folds begin
Fixes #2247
2014-06-23 11:29:14 -06:00
Kevin Sawicki f9fcb1767b Upgrade to symbols-view@0.58.0 2014-06-23 10:00:17 -07:00
Kevin Sawicki 433843ba23 📝 Wrap line and use single backticks 2014-06-23 09:36:44 -07:00
Kevin Sawicki 598e752a9d Merge pull request #2713 from Theswweet/patch-1
Update linux.md to accomadate build issues
2014-06-23 09:32:01 -07:00
probablycorey c1142f6c6a Merge branch 'cj-make-sure-editor-events-are-called-in-the-correct-order' 2014-06-23 09:31:12 -07:00
Kevin Sawicki 937ff194b6 Upgrade to language-ruby-on-rails@0.15 2014-06-23 09:18:34 -07:00
probablycorey 9a5da3c27e Add next tick call 2014-06-23 09:13:39 -07:00
probablycorey 43cb9af4a4 Add editor-event spec 2014-06-23 08:51:17 -07:00
James Galizio 843c075779 Fixed typo's for proposed commit. 2014-06-22 11:59:11 -07:00
Ivan Žužak e13cf19daa Upgrade to welcome@0.17.0 2014-06-22 17:52:48 +02:00
Cheng Zhao 0eecf49e61 Merge pull request #2653 from deprint/desktop-file-fix
Fix for installation of desktop file
2014-06-22 11:42:21 +08:00
James Galizio 748d189079 Update linux.md to accomadate build issues
I ran into this when I installed today, and the inscribed method allowed me to complete my atom install on CrunchBang. I've seen a few issues having to do with this, so it might be advisable to have it in the troubleshooting section!
2014-06-21 20:36:55 -07:00
Kevin Sawicki 9d4c4a190f Upgrade to snippets@0.47 2014-06-21 07:14:22 -07:00
Kevin Sawicki ac2b84f21e Upgrade to timecop@0.20 2014-06-21 07:10:25 -07:00
Kevin Sawicki 610f515f68 Upgrade to language-yaml@0.9 2014-06-21 07:06:18 -07:00
Nathan Sobo 5348b912cc Merge pull request #2708 from atom/revert-2699-ns-react-fix-artifacts
Avoid GPU artifacts without rendering selections on another layer
2014-06-21 02:52:51 -06:00
Nathan Sobo 3fd4e57162 Render a dummy highlight decoration to prevent artifacts
When the last highlight gets removed, we get a rendering artifact.
Always rendering an empty dummy at 0,0 ensures that never happens.
2014-06-21 02:23:59 -06:00
Nathan Sobo 7c356d2592 Revert "Render highlights on their own layer to avoid GPU artifacts" 2014-06-21 01:58:11 -06:00
Ben Ogle 0dadce1047 Serialize all included grammar scopes 2014-06-20 17:04:21 -07:00
Ben Ogle 8c3bfaa3a2 Return when grammars are already loaded 2014-06-20 17:04:21 -07:00
Ben Ogle f8b8b22b75 Preload grammars on deserialization 2014-06-20 17:04:21 -07:00
Nathan Sobo e49414d2ec Merge pull request #2699 from atom/ns-react-fix-artifacts
Render highlights on their own layer to avoid GPU artifacts
2014-06-20 17:03:26 -06:00
Nathan Sobo 1361424673 Merge pull request #2702 from atom/ns-react-autoscroll-to-added-selections
Autoscroll to selections in model layer when added
2014-06-20 17:03:12 -06:00
Nathan Sobo e084bebb54 Autoscroll to selections in model layer when added
Fixes #2698
2014-06-20 16:53:46 -06:00
Nathan Sobo df8d014e3c Add a dedicated underlayer to avoid GPU artifacts on wrap guide etc
Trying to make the .highlights layer double as the .underlayer was
causing GPU artifacts on the wrap guide when the last highlight was
removed. This puts it in its own layer to avoid that.
2014-06-20 16:33:08 -06:00
Nathan Sobo d839ea9aa5 Don't render an opaque background behind line numbers
It doesn't help subpixel anti-aliasing like I thought, so screw it.
2014-06-20 16:07:19 -06:00
Nathan Sobo 6cdb1a188a Merge pull request #2681 from atom/ns-react-batch-updates
Batch all editor updates together automatically via process.nextTick
2014-06-20 15:20:25 -06:00
Nathan Sobo 4218e0a037 Render highlights on their own layer to avoid GPU artifacts
Previously, when the last highlight div was removed from the lines
layer, chunks of the lines would sometimes disappear. Since we've
discovered that giving the lines an opaque background doesn't help with
subpixel anti-aliasing anyway, I've found that rendering highlights on
their own layer behind the lines and making the lines layer transparent
avoids the arficacts.
2014-06-20 15:18:19 -06:00
Nathan Sobo 36a0da01cc Update markdown-preview to fix specs 2014-06-20 15:06:16 -06:00
Nathan Sobo ef2bdf6365 Only forceUpdate of EditorComponent on nextTick if it's mounted 2014-06-20 15:06:16 -06:00
Nathan Sobo ef1ec9b693 Emit events *after* update to prevent requesting update during an update
When updating synchronously in specs, we can't get away with requesting
an update before the previous update is completed. If we emit events
before the update, we have the potential for one of those events to
cause this to happen. Moving them to after is more correct anyway.
2014-06-20 15:06:16 -06:00
Nathan Sobo 68d0a99c6e Default EditorComponent to updating synchronously in specs
This commit adds a static property, EditorComponent.performSyncUpdates,
which can be used to control the update behavior of all editor
components. In addition, an instance property called performSyncUpdates
be assigned to control the update behavior of a specific instance.
2014-06-20 15:06:16 -06:00
Nathan Sobo 64f3938f5c Batch all editor updates together automatically via process.nextTick 2014-06-20 15:06:10 -06:00
Kevin Sawicki 3faecb5988 📝 Correct broken references 2014-06-20 13:57:50 -07:00
Kevin Sawicki bf50b4a128 Prepare 0.107 2014-06-20 13:55:56 -07:00
Kevin Sawicki 88df4d2f3e Merge pull request #2692 from atom/ks-select-page-up-down
Select page up/down
2014-06-20 13:22:04 -07:00
Kevin Sawicki 4136ff566b 📝 Correct spec description 2014-06-20 13:09:51 -07:00
Kevin Sawicki 2fe523a664 Add spec for Editor::selectPageUp/Down 2014-06-20 13:09:51 -07:00
Kevin Sawicki 148180adda Implement select page up/down in Editor 2014-06-20 13:09:27 -07:00
Justin Bradford 01a4032895 Add text selection using page up/down keys to the React-based editor 2014-06-20 13:09:16 -07:00
Justin Bradford 2b2b65ec82 Add command to select text using page up/down keys 2014-06-20 13:08:48 -07:00
Ben Ogle 5ffc063f0c Merge pull request #2693 from atom/bo-fix-gutter-prev-decorations
Fix caching of gutter's previous decorations
2014-06-20 12:52:22 -07:00
Ben Ogle dee0771dd7 Use ? in the conditional. 2014-06-20 12:50:42 -07:00
Ben Ogle aef6991ca8 Set the decorations and previousDecorations vars before loops
Both loops use both vars, so both need to be available before the 
diffing!
2014-06-20 11:29:18 -07:00
Ben Ogle e8db3e97ce Remove cached decorations for removed lines 2014-06-20 11:28:01 -07:00
Ben Ogle b1dd4f2e8e Index the previous decoration cache by lineNumberId rather than screenRow
Why? Screen rows change. If some operation (folding?) changes the 
screen rows and the decorations at the same time, the previous 
decorations will no longer be valid and can no longer be diffed against 
the decorations to-be-rendered.
2014-06-20 11:27:39 -07:00
Ben Ogle 633b08b9de Merge pull request #2682 from atom/bo-line-decorations
Render line decorations
2014-06-20 11:02:35 -07:00
Ben Ogle 1228435f9b 💄 2014-06-20 11:00:40 -07:00
Kevin Sawicki 02b5280587 Upgrade to language-ruby@0.30 2014-06-20 10:59:15 -07:00
Ben Ogle 2e47207701 Upgrade to git-diff 0.34.0 to fix spec 2014-06-20 10:54:10 -07:00
Ben Ogle 593b5b4e36 Use _.deepContains 2014-06-20 10:50:12 -07:00
Kevin Sawicki 1896c94775 Upgrade to language-c@0.21 2014-06-20 10:46:50 -07:00
Kevin Sawicki 4dc20e2027 Upgrade to tree-view@0.104 2014-06-20 09:18:53 -07:00
Kevin Sawicki 238e291888 Upgrade to language-javascript@0.28 2014-06-20 09:06:39 -07:00
Kevin Sawicki 5ccac143aa Upgrade to language-c@0.20 2014-06-20 08:38:10 -07:00
Kevin Sawicki ae97244664 📝 Tweak python install location note 2014-06-20 08:06:22 -07:00
Kevin Sawicki 859e3cd038 Merge pull request #2687 from grenade/patch-1
Added a hint about the required Python path.
2014-06-20 08:04:05 -07:00
Rob Thijssen 07577ff944 Added a hint about the required Python path.
In order to alert users that the Atom build scripts expect to find Python in the default installation folder.
2014-06-20 15:19:55 +01:00
Ben Ogle 72b1821828 Render line decorations. 2014-06-19 17:20:05 -07:00
Kevin Sawicki 781a51ac53 Merge pull request #2675 from atom/ks-bundle-dlls
Bundle DLLs
2014-06-19 16:27:38 -07:00
Kevin Sawicki 9055e650c6 Specify full destination path 2014-06-19 16:16:16 -07:00
Kevin Sawicki 5195a4aaa7 Copy dlls during build task 2014-06-19 16:16:16 -07:00
Kevin Sawicki 5e4f34f92c Update dlls 2014-06-19 16:16:16 -07:00
Kevin Sawicki dc7b549017 Add msvcr100.dll to win resources 2014-06-19 16:16:16 -07:00
Kevin Sawicki 29d5f63cd9 Update msvcp100.dll 2014-06-19 16:16:15 -07:00
Kevin Sawicki 33b4ec8e25 Add msvcp100.dll to win resources 2014-06-19 16:16:15 -07:00
Philip Schatz 67a1ed92db 💄 context menu tests 2014-06-19 19:14:34 -04:00
Ben Ogle 85abed2406 Merge pull request #2676 from atom/bo-cursor-gutter
Don’t render decorations on the last empty line when selection not empty
2014-06-19 15:10:18 -07:00
Ben Ogle 520ece4b13 💄 Wording 2014-06-19 15:09:49 -07:00
Ben Ogle 184068dc55 Add handlers for IME composition 2014-06-19 15:03:34 -07:00
Ben Ogle f27b897e91 Change message in scroll canary 2014-06-19 14:27:20 -07:00
Ben Ogle 6e201104bc Only fix the scroll position when the editor is mounted
fixes #2664
2014-06-19 14:24:47 -07:00
Ben Ogle 908a2978ae Don’t render decorations on the last empty line when selection not empty 2014-06-19 14:20:32 -07:00
Ben Ogle 2eb5ef0816 Merge pull request #2665 from atom/bo-gutter-selection
Implement gutter clicking and dragging to change selection on react editor
2014-06-19 13:48:40 -07:00
probablycorey 0c5f2cd067 Upgrade to language-gfm@0.40.0 2014-06-19 13:38:25 -07:00
Kevin Sawicki d1e60fb2a5 Upgrade to language-c@0.19 2014-06-19 13:22:16 -07:00
Nathan Sobo bee7be1d1a Fix errors refreshing directly after adding selection below/above 2014-06-19 13:43:10 -06:00
Ben Ogle bee4c9df8a Revert "Select to the end of the last row rather than beginning of row + 1"
This reverts commit c5815d2af9.
2014-06-19 12:06:09 -07:00
Ben Ogle c5815d2af9 Select to the end of the last row rather than beginning of row + 1 2014-06-19 12:05:17 -07:00
Ben Ogle 77717d3eff Fix spec 2014-06-19 12:05:17 -07:00
Ben Ogle & Nathan Sobo d3e0005b33 💄 Break out separate methods for gutter click and shift-click 2014-06-19 12:05:17 -07:00
Ben Ogle & Nathan Sobo 8295019891 Throw error when no animation frame was requested 2014-06-19 12:05:17 -07:00
Ben Ogle & Nathan Sobo 2edcc517b1 Handle dragging in the gutter
Including shift-click dragging better than the old editor!!!!!!
2014-06-19 12:05:17 -07:00
Ben Ogle & Nathan Sobo 9083103bb3 Add click and shift-click in gutter 2014-06-19 12:04:36 -07:00
Ben Ogle & Nathan Sobo bc391094df 💄 Move helper 2014-06-19 12:03:18 -07:00
Kevin Sawicki ffba81a962 Prepare 0.106 2014-06-19 10:03:26 -07:00
Kevin Sawicki 1e1f4cf173 Merge pull request #2662 from atom/ks-align-hard-tabs
Align hard tabs
2014-06-19 09:41:15 -07:00
Ivan Žužak 7f04149f8d Upgrade to find-and-replace@0.120.0 2014-06-19 18:03:00 +02:00
Nathan Sobo cd1fb99142 Merge pull request #2667 from atom/ns-react-dont-measure-when-hidden
Don't measure character widths when editor is hidden
2014-06-19 06:34:07 -06:00
Nathan Sobo 388763e7cd Wait to measure characters if editor is hidden
Also, when characters *are* measured, request a display update
2014-06-19 04:19:51 -06:00
Nathan Sobo f22e4225c3 Break into separate specs for lineHeight, fontSize, and fontFamily 2014-06-19 03:35:35 -06:00
Cheng Zhao db4b99d27b Merge branch 'atom-shell-v0.13.2' 2014-06-19 15:16:06 +08:00
Nathan Sobo 17f9cc49f2 Honor the center: true option in scrollTo* methods
Fixes #2648
2014-06-18 21:48:14 -06:00
Nathan Sobo 609855af3c Decide to measure gutter's width in gutter
The gutter is in a better position to determine if the max line number
length has changed because it's a property that gets passed in so we
can compare current with previous.

Fixes #2659
2014-06-18 21:07:13 -06:00
Cheng Zhao 8410d8587b Upgrade to atom-shell@0.13.2 2014-06-19 09:38:27 +08:00
Kevin Sawicki 33c9d5ae24 Upgrade to find-and-replace@0.119 2014-06-18 18:17:01 -07:00
Kevin Sawicki 0c48821465 Upgrade to command-palette@0.23 2014-06-18 17:50:46 -07:00
Kevin Sawicki 43259f5c51 Upgrade to link@0.24 2014-06-18 17:47:42 -07:00
Kevin Sawicki fe2cb046c3 Verify token screen and buffer delta 2014-06-18 17:26:38 -07:00
Kevin Sawicki de132d79a4 Add parens for clarity 2014-06-18 17:16:50 -07:00
Kevin Sawicki 5af181ffb5 Default column to 0 2014-06-18 17:11:34 -07:00
Kevin Sawicki 355f54ba00 Test odd-numbered tab length alignment 2014-06-18 17:10:10 -07:00
Kevin Sawicki b56d4c6181 Update more expected tab lengths 2014-06-18 16:54:56 -07:00
Kevin Sawicki ad9e2ab869 Update specs where tab is now only 1 space 2014-06-18 16:48:00 -07:00
Kevin Sawicki a497b0f90f 💄 Use trailing for loop 2014-06-18 16:42:36 -07:00
Kevin Sawicki e4fd80399d Add token value directly to column 2014-06-18 16:41:10 -07:00
Kevin Sawicki c4c5d72bf1 Test multiple tab stops per line 2014-06-18 16:37:23 -07:00
Kevin Sawicki 0504244066 Test multiple tab lengths 2014-06-18 16:25:31 -07:00
Kevin Sawicki 8560526158 Add initial spec of hard tabs aligning 2014-06-18 16:24:35 -07:00
Kevin Sawicki ec8805e99e Merge branch 'master' of https://github.com/a-m-s/atom into ks-align-hard-tabs
Conflicts:
	src/tokenized-line.coffee
2014-06-18 16:09:07 -07:00
Kevin Sawicki f8ec2e6da4 Upgrade to settings-view@0.128 2014-06-18 15:23:46 -07:00
Ben Ogle 2a28eafd04 Merge pull request #2661 from atom/bo-fold-markers
Add fold markers to folded lines
2014-06-18 14:58:32 -07:00
Kevin Sawicki a6bf1af2d5 Upgrade to go-to-line@0.23 2014-06-18 14:26:40 -07:00
Kevin Sawicki 8eae66fc49 Upgrade to git-diff@0.33 2014-06-18 14:23:57 -07:00
Ben Ogle 02757fc2de 💄 2014-06-18 14:22:05 -07:00
Kevin Sawicki fc37ac37bd Upgrade to archive-view@0.33 2014-06-18 14:21:33 -07:00
Ben Ogle 63587abe97 Give fold markers a pointer on hover 2014-06-18 14:21:03 -07:00
Ben Ogle d5ea766541 Make click of fold marker unfold the row 2014-06-18 14:07:55 -07:00
Kevin Sawicki bd0643eda4 Upgrade to apm 0.69 2014-06-18 13:56:18 -07:00
Ben Ogle 7a9710b8c3 Add fold markers to folded lines
Fixes #2634
2014-06-18 13:47:38 -07:00
probablycorey 468c6598db Make sure the overlayer class is only used once.
Using it twice causes context menus with the .overlay selector to
appear twice.
Closes #2601
2014-06-18 13:24:15 -07:00
Ben Ogle ddb3cdc76f Merge pull request #2656 from atom/bo-upgrade-fnr
Upgrade find and replace to use decorations for marker views
2014-06-18 13:11:11 -07:00
Ben Ogle 1c8e716cfd Upgrade find-and-replace to use decorations for marker views 2014-06-18 12:56:05 -07:00
Nathan Sobo f1f83a7d36 Add a comment explaining the .editor-colors class on .lines 2014-06-18 12:36:40 -06:00
Nathan Sobo 8d87eb2ed6 Style the .line-numbers div to be compatible w/ both themes and the GPU
The .line-numbers div has to have an opaque background because it's
sent as a texture to the GPU, and otherwise it will have isuses with
subpixel antialiasing.

However, themes style the background of the .gutter div, which was
getting obscured by the opaque background of the line numbers. This
commit adds the .gutter class to the .line-numbers div as well and
ensures it always fills the entire height of the editor.
2014-06-18 12:36:40 -06:00
Fabian Stiewitz 87aae13c80 Prevent double slash in Atom.desktop 2014-06-18 20:28:38 +02:00
Fabian Stiewitz c735432163 Install with respect to INSTALL_PREFIX 2014-06-18 20:07:29 +02:00
Kevin Sawicki 29d26a4fae Increase timeout on Windows CI 2014-06-18 10:04:41 -07:00
Ben Ogle 5c6f711bf3 Upgrade syntax themes to add css for new find decorations 2014-06-18 09:53:17 -07:00
Nathan Sobo 53c363b853 Merge pull request #2615 from adnelson/feature/delete-to-end-of-line
added delete to end of line
2014-06-18 10:46:48 -06:00
probablycorey bacd612c71 Apply editor-colors style to gutter
Closes #2596
2014-06-18 09:42:33 -07:00
Kevin Sawicki 2cded15c4c Upgrade to language-xml@0.15 2014-06-18 09:30:44 -07:00
Corey Johnson 2e73a46cbc Merge pull request #2603 from atom/cj-expose-resizing-to-editor
Expose resizing to editor
2014-06-18 09:19:43 -07:00
Kevin Sawicki 64ae7bcdcc Upgrade to tabs@0.42 2014-06-18 08:35:08 -07:00
Kevin Sawicki abca7f778c Upgrade to status-bar@0.41 2014-06-18 08:27:10 -07:00
Kevin Sawicki b7197145c8 Upgrade to spell-check@0.38 2014-06-18 08:19:36 -07:00
Kevin Sawicki 7f53bb5753 Upgrade to text-buffer 2.4.1 2014-06-18 08:18:41 -07:00
Kevin Sawicki 8d38fc77d6 Upgrade to snippets@0.46 2014-06-18 08:15:32 -07:00
Philip Schatz 624c0bf9f1 allow multiple labels for the same command 2014-06-17 23:36:59 -04:00
Kevin Sawicki 1975882b9e Upgrade to fuzzy-finder@0.55 2014-06-17 18:16:53 -07:00
Kevin Sawicki 0bd4d31ab0 💄 Remove semicolon 2014-06-17 18:06:38 -07:00
Cheng Zhao 4192c121e5 Merge pull request #2630 from deprint/desktop-file
Install Atom.desktop when installing to /usr/local
2014-06-18 08:58:50 +08:00
Ben Ogle e89e2141d7 Merge pull request #2605 from atom/bo-ns-highlights
Add highlight decorations
2014-06-17 17:42:18 -07:00
Kevin Sawicki 25c5458bd2 Upgrade to wrap-guide@0.19 2014-06-17 17:30:58 -07:00
probablycorey ff0cddfd1d Merge remote-tracking branch 'origin/master' into cj-expose-resizing-to-editor 2014-06-17 17:22:10 -07:00
Ben Ogle a7ec7497e2 nof 2014-06-17 17:09:26 -07:00
Ben Ogle 3790cdb262 Reset highlights so they don’t interfere with styleguide text.highlight 2014-06-17 17:08:53 -07:00
Ben Ogle 4308ce7bb0 Warnings when you pass in a bs marker 2014-06-17 17:08:53 -07:00
Kevin Sawicki b302fdc553 Upgrade to markdown-preview@0.82 2014-06-17 16:41:31 -07:00
Nathan Sobo 2fffbba503 Eliminate Decoration class and use plain objects instead 2014-06-17 17:35:56 -06:00
probablycorey 9be1427891 Request scrollView measurement on resize events 2014-06-17 16:25:47 -07:00
Corey Johnson & Nathan Sobo 4564a39392 Remove measureScrollView helper 2014-06-17 16:09:23 -07:00
Corey Johnson & Nathan Sobo 068c1e6249 Use polling to detect editor resize 2014-06-17 16:07:07 -07:00
Kevin Sawicki 06a55250b9 Upgrade to bookmarks@0.25 2014-06-17 15:11:54 -07:00
Ben Ogle d8240628a7 Update doc comments 2014-06-17 14:53:11 -07:00
Kevin Sawicki eaa7593b27 Add single selection menu item 2014-06-17 14:42:57 -07:00
Kevin Sawicki 72e4be60c0 Upgrade to markdown-preview@0.81 2014-06-17 14:40:49 -07:00
Corey Johnson f3a4d32a32 Remove width setting of overflowExpander 2014-06-17 14:07:26 -07:00
Nathan Sobo edadedce7b Give highlight decorations unique id's to avoid potential React errors
Using the marker's id plus the decoration class can cause an error in
the event we apply a decoration with the same class twice to the same
marker. This is admittedly unlikely, but I think it's cleaner to just
allocate unique id's for decoration objects.
2014-06-17 15:03:45 -06:00
Nathan Sobo 89be77b0a9 💄 2014-06-17 14:47:49 -06:00
Nathan Sobo 99ba20ae0d Don't render empty highlights 2014-06-17 14:47:12 -06:00
Corey Johnson 0255e44f00 Remove suppressUpdates 2014-06-17 13:38:08 -07:00
Nathan Sobo 4832d36ac1 Rename filterDecorationsByScreenRow to getLineDecorations
Also rename local variable to lineDecorations for clarity
2014-06-17 14:35:56 -06:00
Nathan Sobo 5d15af943e Rename filterDecorationsByMarkerId to getHighlightDecorations
And rename local variable to highlightDecorations to clarify intent
2014-06-17 14:31:56 -06:00
Corey Johnson 0a671fc386 Add a div that triggers overflowchanged events on resize 2014-06-17 13:28:05 -07:00
Corey Johnson c06f5911c6 Update editor height change spec 2014-06-17 13:26:56 -07:00
Kevin Sawicki 2af8404ea9 Upgrade to bracket-matcher@0.47 2014-06-17 13:07:58 -07:00
Nathan Sobo 345d20dc4a Prepare 0.105.0 release 2014-06-17 14:05:11 -06:00
Ben Ogle ef09fbbfb2 Remove softWrap decoration option 2014-06-17 11:24:27 -07:00
Ben Ogle a3784500ec Fix editor-view tests 2014-06-17 11:13:15 -07:00
Allen Nelson ef7f0ed9ed updated docstring 2014-06-17 12:18:34 -05:00
Fabian Stiewitz 72c87bfbc9 Install Atom.desktop when installDir is not temporary 2014-06-17 16:25:10 +02:00
Fabian Stiewitz 54c7c1e98d 🐧 Install Atom.desktop when installing to /usr/local 2014-06-17 12:40:10 +02:00
Ben Ogle 359793c0b0 Upgrade git-diff for use with new decoration apis. 2014-06-16 17:47:28 -07:00
Ben Ogle 34ec15862f Filter decorations in the components.
This reduces the number of intermediate objects we need to create. The 
downside is a bit more code complexity in the components.
2014-06-16 16:54:21 -07:00
Ben Ogle 04bbe393d4 Remove log lines 2014-06-16 16:51:46 -07:00
Ben Ogle 5b84aa7b18 💄 per nathan’s request 2014-06-16 16:06:18 -07:00
Ben Ogle 7ba498a170 Fix id generation 2014-06-16 16:06:01 -07:00
Ben Ogle c21f8a5a6c 💄 clean up spec names 2014-06-16 16:05:48 -07:00
Ben Ogle 0312609e19 Make highlights render as absolute position 2014-06-16 15:57:23 -07:00
Ben Ogle 32fba97c3a Add a spec for highlights in folds 2014-06-16 15:56:55 -07:00
Ben Ogle 5259d5b750 Dont render invalid highlight decorations 2014-06-16 15:40:54 -07:00
Ben Ogle dff27eba18 Specs for highlights 2014-06-16 15:36:09 -07:00
Ben Ogle d2908c75fc Rename redundant describe 2014-06-16 15:36:09 -07:00
Nathan Sobo 2c04bff0fa Only return decorations for markers intersecting the screen row range
This relies on a fix to the interval-skip-list provided with the upgrade
to text-buffer@2.4.0.
2014-06-16 15:36:09 -07:00
Ben Ogle 4f2f158d0d Make selection updating work properly 2014-06-16 15:36:09 -07:00
Ben Ogle 351dc58354 Remove getSelectionScreenRanges() 2014-06-16 15:36:09 -07:00
Ben Ogle 2867dd98e5 Remove getGutterDecorations() 2014-06-16 15:36:09 -07:00
Ben Ogle 32a0804b9a Remove Decorations object 2014-06-16 15:36:09 -07:00
Ben Ogle 408e62a993 Pass highlightDecorations into the HighlightsComponent 2014-06-16 15:36:08 -07:00
Ben Ogle d4057d21c7 Pass the decoration hash into the gutterComponent 2014-06-16 15:36:08 -07:00
Ben Ogle 031ec9798a No more typeless decorations
Now you can specify a list of types with your decoration.
2014-06-16 15:36:08 -07:00
Ben Ogle 1ebdd801f5 Use decorations to render selections 2014-06-16 15:36:08 -07:00
Ben Ogle 084632a985 Rename Selection(s)Component to Highlight(s)Component 2014-06-16 15:36:08 -07:00
Ben Ogle 002e14990b Rename bufferRowHasClass 2014-06-16 15:36:08 -07:00
Ben Ogle 3a3fc4b614 Add a spec for screen line changes 2014-06-16 15:36:08 -07:00
Ben Ogle b028673b5d Only render on updates 2014-06-16 15:36:08 -07:00
Ben Ogle 6394814142 Make foldable decorations work again 2014-06-16 15:36:08 -07:00
Ben Ogle e128212410 Fix decoration specs to work with markers only 2014-06-16 15:36:08 -07:00
Ben Ogle 2d4360dcf0 Decorations can now only be attached to markers.
The basics work. It will render them on the gutter.
2014-06-16 15:36:08 -07:00
Ben Ogle & Nathan Sobo 120e2a3bdb Move decoration Editor specs to DisplayBuffer 2014-06-16 15:36:08 -07:00
Ben Ogle & Nathan Sobo 7142022f05 Add intersection support to DisplayBuffer::findMarkers 2014-06-16 15:36:08 -07:00
Ben Ogle & Nathan Sobo 25520a4cad Add containedInScreenRange to DisplayBuffer::findMarkers 2014-06-16 15:36:08 -07:00
Ben Ogle & Nathan Sobo 56da6399b8 Add startScreenRow and endScreenRow to DisplayBuffer::findMarkers 2014-06-16 15:36:08 -07:00
Ben Ogle & Nathan Sobo a7379b067a Use ::getMarker for fold decorations instead of new DisplayBufferMarker 2014-06-16 15:36:07 -07:00
Allen Nelson 8411d41621 deleting only selection if selection is not empty 2014-06-16 16:13:40 -05:00
Allen Nelson fc462fcd21 added delete to end of line 2014-06-16 10:59:55 -05:00
Philip Schatz 2fdcf7a124 remove duplicate context menu entries 2014-06-13 21:30:55 -04:00
Nathan Sobo 9e6756ed6d Don't perform an update in response scroll view dimension changes
We always measure the scroll view in the ::componentWillUpdate hook, so
performing *another* update in response to the measurement causes an
invariant violation in react. Whenever we are measuring, we are always
already updating.
2014-06-13 17:07:41 -06:00
probablycorey 8d84a97b2b Move scroll view measurements to componentWillUpdate 2014-06-13 11:36:40 -07:00
Corey Johnson e96d2dbd17 Add the simplest resize fix that will work. 2014-06-12 16:17:45 -07:00
Corey Johnson 025370b9f8 Add editor component resize spec 2014-06-12 16:17:18 -07:00
Andrew Stubbs 1fe6c498ac Make hard tabs align to columns. 2014-05-14 13:31:03 +01:00
61 arquivos alterados com 2300 adições e 894 exclusões
+2
Ver Arquivo
@@ -13,3 +13,5 @@ debug.log
docs/output
docs/includes
spec/fixtures/evil-files/
resources/linux/Atom.desktop
resources/linux/debian/control
+1
Ver Arquivo
@@ -11,6 +11,7 @@ pairs:
bo: Ben Ogle; benogle
jr: Jason Rudolph; jasonrudolph
jl: Jessica Lord; jlord
dh: Daniel Hengeveld; danielh
email:
domain: github.com
#global: true
+1 -1
Ver Arquivo
@@ -6,6 +6,6 @@
"url": "https://github.com/atom/atom.git"
},
"dependencies": {
"atom-package-manager": "0.68.0"
"atom-package-manager": "0.69.0"
}
}
+2
Ver Arquivo
@@ -121,6 +121,8 @@ module.exports = (grunt) ->
atom: {appDir, appName, symbolsDir, buildDir, contentsDir, installDir, shellAppDir}
docsOutputDir: 'docs/output/api'
coffee: coffeeConfig
less: lessConfig
+9
Ver Arquivo
@@ -86,6 +86,15 @@ module.exports = (grunt) ->
unless /.+\.plist/.test(sourcePath)
grunt.file.copy(sourcePath, path.resolve(appDir, '..', subDirectory, filename))
if process.platform is 'win32'
cp path.join('resources', 'win', 'msvcp100.dll'), path.join(shellAppDir, 'msvcp100.dll')
cp path.join('resources', 'win', 'msvcr100.dll'), path.join(shellAppDir, 'msvcr100.dll')
# Set up chocolatey ignore and gui files
fs.writeFileSync path.join(appDir, 'apm', 'node_modules', 'atom-package-manager', 'bin', 'node.exe.ignore'), ''
fs.writeFileSync path.join(appDir, 'node_modules', 'symbols-view', 'vendor', 'ctags-win32.exe.ignore'), ''
fs.writeFileSync path.join(shellAppDir, 'atom.exe.gui'), ''
dependencies = ['compile', "generate-license:save"]
dependencies.push('copy-info-plist') if process.platform is 'darwin'
dependencies.push('set-exe-icon') if process.platform is 'win32'
+4 -2
Ver Arquivo
@@ -15,15 +15,17 @@ module.exports = (grunt) ->
grunt.registerTask 'build-docs', 'Builds the API docs in src', ->
done = @async()
docsOutputDir = grunt.config.get('docsOutputDir')
downloadIncludes (error, includePaths) ->
if error?
done(error)
else
rm('docs/output/api')
rm(docsOutputDir)
args = [
commonArgs...
'--title', 'Atom API Documentation'
'-o', 'docs/output/api'
'-o', docsOutputDir
'-r', 'docs/README.md'
'--stability', '1'
'src/'
+19
Ver Arquivo
@@ -1,8 +1,14 @@
fs = require 'fs'
path = require 'path'
_ = require 'underscore-plus'
fs = require 'fs-plus'
runas = null
fillTemplate = (filePath, data) ->
template = _.template(String(fs.readFileSync(filePath + '.in')))
filled = template(data)
fs.writeFileSync(filePath, filled)
module.exports = (grunt) ->
{cp, mkdir, rm} = require('./task-helpers')(grunt)
@@ -25,12 +31,25 @@ module.exports = (grunt) ->
binDir = path.join(installDir, 'bin')
shareDir = path.join(installDir, 'share', 'atom')
iconName = path.join(shareDir,'resources','app','resources','atom.png')
desktopFile = path.join('resources', 'linux', 'Atom.desktop')
mkdir binDir
cp 'atom.sh', path.join(binDir, 'atom')
rm shareDir
mkdir path.dirname(shareDir)
cp shellAppDir, shareDir
# Create Atom.desktop if installation not in temporary folder
tmpDir = if process.env.TMPDIR? then process.env.TMPDIR else '/tmp'
desktopInstallFile = path.join(installDir,'share','applications','Atom.desktop')
if installDir.indexOf(tmpDir) isnt 0
mkdir path.dirname(desktopInstallFile)
{description} = grunt.file.readJSON('package.json')
installDir = path.join(installDir,'.') # To prevent "Exec=/usr/local//share/atom/atom"
fillTemplate(desktopFile, {description, installDir, iconName})
cp desktopFile, desktopInstallFile
# Create relative symbol link for apm.
process.chdir(binDir)
rm('apm')
+3 -1
Ver Arquivo
@@ -23,7 +23,9 @@ module.exports = (grunt) ->
{name, version, description} = grunt.file.readJSON('package.json')
section = 'devel'
maintainer = 'GitHub <atom@github.com>'
data = {name, version, description, section, arch, maintainer}
installDir = '/usr'
iconName = 'atom'
data = {name, version, description, section, arch, maintainer, installDir, iconName}
control = path.join('resources', 'linux', 'debian', 'control')
fillTemplate(control, data)
+29 -19
Ver Arquivo
@@ -9,16 +9,6 @@ request = require 'request'
grunt = null
if process.platform is 'darwin'
assets = [
{assetName: 'atom-mac.zip', sourceName: 'Atom.app'}
{assetName: 'atom-mac-symbols.zip', sourceName: 'Atom.breakpad.syms'}
]
else
assets = [
{assetName: 'atom-windows.zip', sourceName: 'Atom'}
]
commitSha = process.env.JANKY_SHA1
token = process.env.ATOM_ACCESS_TOKEN
defaultHeaders =
@@ -30,11 +20,19 @@ module.exports = (gruntObject) ->
grunt.registerTask 'publish-build', 'Publish the built app', ->
return if process.env.JANKY_SHA1 and process.env.JANKY_BRANCH isnt 'master'
tasks = ['upload-assets']
tasks.unshift('build-docs', 'prepare-docs') if process.platform is 'darwin'
grunt.task.run(tasks)
grunt.registerTask 'prepare-docs', 'Move the build docs to the build dir', ->
fs.copySync(grunt.config.get('docsOutputDir'), path.join(grunt.config.get('atom.buildDir'), 'atom-docs'))
grunt.registerTask 'upload-assets', 'Upload the assets to a GitHub release', ->
done = @async()
buildDir = grunt.config.get('atom.buildDir')
assets = getAssets()
zipApps buildDir, assets, (error) ->
zipAssets buildDir, assets, (error) ->
return done(error) if error?
getAtomDraftRelease (error, release) ->
return done(error) if error?
@@ -43,26 +41,38 @@ module.exports = (gruntObject) ->
return done(error) if error?
uploadAssets(release, buildDir, assets, done)
getAssets = ->
if process.platform is 'darwin'
[
{assetName: 'atom-mac.zip', sourcePath: 'Atom.app'}
{assetName: 'atom-mac-symbols.zip', sourcePath: 'Atom.breakpad.syms'}
{assetName: 'atom-docs.zip', sourcePath: 'atom-docs'}
]
else
[
{assetName: 'atom-windows.zip', sourcePath: 'Atom'}
]
logError = (message, error, details) ->
grunt.log.error(message)
grunt.log.error(error.message ? error) if error?
grunt.log.error(details) if details
zipApps = (buildDir, assets, callback) ->
zip = (directory, sourceName, assetName, callback) ->
zipAssets = (buildDir, assets, callback) ->
zip = (directory, sourcePath, assetName, callback) ->
if process.platform is 'win32'
zipCommand = "C:/psmodules/7z.exe a -r #{assetName} #{sourceName}"
zipCommand = "C:/psmodules/7z.exe a -r #{assetName} #{sourcePath}"
else
zipCommand = "zip -r --symlinks #{assetName} #{sourceName}"
zipCommand = "zip -r --symlinks #{assetName} #{sourcePath}"
options = {cwd: directory, maxBuffer: Infinity}
child_process.exec zipCommand, options, (error, stdout, stderr) ->
logError("Zipping #{sourceName} failed", error, stderr) if error?
logError("Zipping #{sourcePath} failed", error, stderr) if error?
callback(error)
tasks = []
for {assetName, sourceName} in assets
for {assetName, sourcePath} in assets
fs.removeSync(path.join(buildDir, assetName))
tasks.push(zip.bind(this, buildDir, sourceName, assetName))
tasks.push(zip.bind(this, buildDir, sourcePath, assetName))
async.parallel(tasks, callback)
getAtomDraftRelease = (callback) ->
@@ -127,7 +137,7 @@ uploadAssets = (release, buildDir, assets, callback) ->
fs.createReadStream(assetPath).pipe(assetRequest)
tasks = []
for {assetName, sourceName} in assets
for {assetName} in assets
assetPath = path.join(buildDir, assetName)
tasks.push(upload.bind(this, release, assetName, assetPath))
async.parallel(tasks, callback)
+12 -22
Ver Arquivo
@@ -11,41 +11,31 @@ value of a namespaced config key with `atom.config.get`:
@showInvisibles() if atom.config.get "editor.showInvisibles"
```
Or you can use the `::observeConfig` to track changes from any view object.
Or you can use the `::subscribe` with `atom.config.observe` to track changes
from any view object.
```coffeescript
class MyView extends View
initialize: ->
@observeConfig 'editor.fontSize', () =>
@subscribe atom.config.observe 'editor.fontSize', (newValue, {previous}) =>
@adjustFontSize()
```
The `::observeConfig` method will call the given callback immediately with the
current value for the specified key path, and it will also call it in the future
whenever the value of that key path changes.
The `atom.config.observe` method will call the given callback immediately with
the current value for the specified key path, and it will also call it in the
future whenever the value of that key path changes.
Subscriptions made with `observeConfig` are automatically canceled when the
Subscriptions made with `::subscribe` are automatically canceled when the
view is removed. You can cancel config subscriptions manually via the
`unobserveConfig` method.
`off` method on the subscription object that `atom.config.observe` returns.
```coffeescript
view1.unobserveConfig() # unobserve all properties
```
fontSizeSubscription = atom.config.observe 'editor.fontSize', (newValue, {previous}) =>
@adjustFontSize()
You can add the ability to observe config values to non-view classes by
extending their prototype with the `ConfigObserver` mixin:
# ... later on
```coffeescript
{ConfigObserver} = require 'atom'
class MyClass
ConfigObserver.includeInto(this)
constructor: ->
@observeConfig 'editor.showInvisibles', -> # ...
destroy: ->
@unobserveConfig()
fontSizeSubscription.off() # Stop observing
```
### Writing Config Settings
+15 -2
Ver Arquivo
@@ -198,6 +198,19 @@ Unstar a package; requires authentication.
Returns 204 No Content.
#### GET /api/packages/:name/stargazers
List the users that have starred a package.
Returns a list of user objects:
```json
[
{"login":"aperson"},
{"login":"anotherperson"},
]
```
### Atom updates
#### GET /api/updates
@@ -206,10 +219,10 @@ Atom update feed, following the format expected by [Squirrel](https://github.com
Returns:
```
```json
{
"name": "0.96.0",
"notes": "[HTML release notes]"
"notes": "[HTML release notes]",
"pub_date": "2014-05-19T15:52:06.000Z",
"url": "https://www.atom.io/api/updates/download"
}
+7
Ver Arquivo
@@ -61,6 +61,13 @@ and restart Atom. If Atom now works fine, you can make this setting permanent:
See also https://github.com/atom/atom/issues/2082.
### /usr/bin/env: node: No such file or directory
If you get this notice when attempting to `script/build`, you either do not
have nodejs installed, or node isn't identified as nodejs on your machine.
If it's the latter, entering `sudo ln -s /usr/bin/nodejs /usr/bin/node` into
your terminal may fix the issue.
### Linux build error reports in atom/atom
* Use [this search](https://github.com/atom/atom/search?q=label%3Abuild-error+label%3Alinux&type=Issues)
to get a list of reports about build errors on Linux.
+5 -2
Ver Arquivo
@@ -9,8 +9,11 @@
* For 64-bit builds of node and native modules you **must** have the
[Windows 7 64-bit SDK](http://www.microsoft.com/en-us/download/details.aspx?id=8279).
You may also need the [compiler update for the Windows SDK 7.1](http://www.microsoft.com/en-us/download/details.aspx?id=4422)
* [Python](http://www.python.org/download/) v2.7.x
* [Python](http://www.python.org/download/) v2.7.
* The python.exe must be available at `%SystemDrive%\Python27\python.exe`.
If it is installed elsewhere, you can create a symbolic link to the
directory containing the python.exe using:
`mklink /d %SystemDrive%\Python27 D:\elsewhere\Python27`
* [GitHub for Windows](http://windows.github.com/)
### On Windows 8
+69 -1
Ver Arquivo
@@ -38,7 +38,7 @@ Atom uses [Jasmine](http://jasmine.github.io/2.0/introduction.html) as its spec
0. Add one or more expectations
The best way to learn about expectations is to read the [jasmine documentation](http://jasmine.github.io/2.0/introduction.html#section-Expectations) about them. Below is a simple example.
The best way to learn about expectations is to read the [jasmine documentation](http://jasmine.github.io/1.3/introduction.html#section-Expectations) about them. Below is a simple example.
```coffee
describe "when a test is written", ->
@@ -47,6 +47,74 @@ Atom uses [Jasmine](http://jasmine.github.io/2.0/introduction.html) as its spec
expect("oranges").not.toEqual("apples")
```
## Asynchronous specs
Writing Asynchronous specs can be tricky at first. Some examples.
0. Promises
Working with promises is rather easy in Atom. You can use our `waitsForPromise` function.
```coffee
describe "when we open a file", ->
it "should be opened in an editor", ->
waitsForPromise ->
atom.workspace.open('c.coffee').then (editor) ->
expect(editor.getPath()).toContain 'c.coffee'
```
This method can be used in the `describe`, `it`, `beforeEach` and `afterEach` functions.
```coffee
describe "when we open a file", ->
beforeEach ->
waitsForPromise ->
atom.workspace.open 'c.coffee'
it "should be opened in an editor", ->
expect(atom.workspace.getActiveEditor().getPath()).toContain 'c.coffee'
```
If you need to wait for multiple promises use a new `waitsForPromise` function for each promise. (Caution: Without `beforeEach` this example will fail!)
```coffee
describe "waiting for the packages to load", ->
beforeEach ->
waitsForPromise ->
atom.workspace.open('sample.js')
waitsForPromise ->
atom.packages.activatePackage('tabs')
waitsForPromise ->
atom.packages.activatePackage('tree-view')
it 'should have waited long enough', ->
expect(atom.packages.isPackageActive('tabs')).toBe true
expect(atom.packages.isPackageActive('tree-view')).toBe true
```
0. Asynchronous functions with callbacks
Specs for asynchronous functions can be done using the `waitsFor` and `runs` functions. A simple example.
```coffee
describe "fs.readdir(path, cb)", ->
it "is async", ->
spy = jasmine.createSpy('fs.readdirSpy')
fs.readdir('/tmp/example', spy)
waitsFor ->
spy.callCount > 0
runs ->
exp = [null, ['example.coffee']]
expect(spy.mostRecentCall.args).toEqual exp
expect(spy).toHaveBeenCalledWith(null, ['example.coffee'])
```
For a more detailed documentation on asynchronous tests please visit the [jasmine documentation](http://jasmine.github.io/1.3/introduction.html#section-Asynchronous_Support).
## Running specs
Most of the time you'll want to run specs by triggering the `window:run-package-specs` command. This command is not only to run package specs, it is also for Atom core specs. This will run all the specs in the current project's spec directory. If you want to run the Atom core specs and **all** the default package specs trigger the `window:run-all-specs` command.
+4
Ver Arquivo
@@ -53,6 +53,8 @@
'shift-down': 'core:select-down'
'shift-left': 'core:select-left'
'shift-right': 'core:select-right'
'shift-pageup': 'core:select-page-up'
'shift-pagedown': 'core:select-page-down'
'delete': 'core:delete'
'shift-delete': 'core:delete'
'pageup': 'core:page-up'
@@ -67,6 +69,8 @@
'cmd-}': 'pane:show-next-item'
'cmd-alt-left': 'pane:show-previous-item'
'cmd-alt-right': 'pane:show-next-item'
'ctrl-pageup': 'pane:show-previous-item'
'ctrl-pagedown': 'pane:show-next-item'
'ctrl-tab': 'pane:show-next-item'
'ctrl-shift-tab': 'pane:show-previous-item'
'cmd-=': 'window:increase-font-size'
+4
Ver Arquivo
@@ -35,6 +35,8 @@
'shift-down': 'core:select-down'
'shift-left': 'core:select-left'
'shift-right': 'core:select-right'
'shift-pageup': 'core:select-page-up'
'shift-pagedown': 'core:select-page-down'
'delete': 'core:delete'
'shift-delete': 'core:delete'
'pageup': 'core:page-up'
@@ -43,6 +45,8 @@
'shift-backspace': 'core:backspace'
'ctrl-tab': 'pane:show-next-item'
'ctrl-shift-tab': 'pane:show-previous-item'
'ctrl-pageup': 'pane:show-previous-item'
'ctrl-pagedown': 'pane:show-next-item'
'ctrl-shift-up': 'core:move-up'
'ctrl-shift-down': 'core:move-down'
'ctrl-=': 'window:increase-font-size'
+4
Ver Arquivo
@@ -37,6 +37,8 @@
'shift-down': 'core:select-down'
'shift-left': 'core:select-left'
'shift-right': 'core:select-right'
'shift-pageup': 'core:select-page-up'
'shift-pagedown': 'core:select-page-down'
'delete': 'core:delete'
'shift-delete': 'core:delete'
'pageup': 'core:page-up'
@@ -45,6 +47,8 @@
'shift-backspace': 'core:backspace'
'ctrl-tab': 'pane:show-next-item'
'ctrl-shift-tab': 'pane:show-previous-item'
'ctrl-pageup': 'pane:show-previous-item'
'ctrl-pagedown': 'pane:show-next-item'
'ctrl-shift-up': 'core:move-up'
'ctrl-shift-down': 'core:move-down'
'ctrl-alt-up': 'editor:add-selection-above'
+1
Ver Arquivo
@@ -109,6 +109,7 @@
submenu: [
{ label: 'Add Selection Above', command: 'editor:add-selection-above' }
{ label: 'Add Selection Below', command: 'editor:add-selection-below' }
{ label: 'Single Selection', command: 'editor:consolidate-selections'}
{ label: 'Split into Lines', command: 'editor:split-selections-into-lines'}
{ type: 'separator' }
{ label: 'Select to Top', command: 'core:select-to-top' }
+1
Ver Arquivo
@@ -108,6 +108,7 @@
{ label: 'Add Selection &Above', command: 'editor:add-selection-above' }
{ label: 'Add Selection &Below', command: 'editor:add-selection-below' }
{ label: 'S&plit into Lines', command: 'editor:split-selections-into-lines'}
{ label: 'Single Selection', command: 'editor:consolidate-selections'}
{ type: 'separator' }
{ label: 'Select to &Top', command: 'core:select-to-top' }
{ label: 'Select to Botto&m', command: 'core:select-to-bottom' }
+1
Ver Arquivo
@@ -127,6 +127,7 @@
{ label: 'Add Selection &Above', command: 'editor:add-selection-above' }
{ label: 'Add Selection &Below', command: 'editor:add-selection-below' }
{ label: 'S&plit into Lines', command: 'editor:split-selections-into-lines'}
{ label: 'Single Selection', command: 'editor:consolidate-selections'}
{ type: 'separator' }
{ label: 'Select to &Top', command: 'core:select-to-top' }
{ label: 'Select to Botto&m', command: 'core:select-to-bottom' }
+49 -48
Ver Arquivo
@@ -1,7 +1,7 @@
{
"name": "atom",
"productName": "Atom",
"version": "0.104.0",
"version": "0.107.0",
"description": "A hackable text editor for the 21st Century.",
"main": "./src/browser/main.js",
"repository": {
@@ -17,7 +17,7 @@
"url": "http://github.com/atom/atom/raw/master/LICENSE.md"
}
],
"atomShellVersion": "0.13.1",
"atomShellVersion": "0.13.3",
"dependencies": {
"async": "0.2.6",
"atom-keymap": "^0.27.0",
@@ -27,7 +27,7 @@
"coffeestack": "0.7.0",
"delegato": "^1",
"emissary": "^1.2.1",
"first-mate": "^1.7",
"first-mate": "^1.7.1",
"fs-plus": "^2.2.3",
"fstream": "0.1.24",
"fuzzaldrin": "^1.1",
@@ -47,8 +47,8 @@
"random-words": "0.0.1",
"react-atom-fork": "^0.10.0",
"reactionary-atom-fork": "^0.9.0",
"runas": "^0.5",
"scandal": "0.15.3",
"runas": "0.5.4",
"scandal": "0.16.0",
"scoped-property-store": "^0.9.0",
"scrollbar-style": "^0.4.0",
"season": "^1.0.2",
@@ -56,77 +56,78 @@
"serializable": "^1",
"space-pen": "3.2.0",
"temp": "0.7.0",
"text-buffer": "^2.3.0",
"text-buffer": "^2.4.2",
"theorist": "^1",
"underscore-plus": "^1.4.1",
"underscore-plus": "^1.5.0",
"vm-compatibility-layer": "0.1.0"
},
"packageDependencies": {
"atom-dark-syntax": "0.16.0",
"atom-dark-ui": "0.29.0",
"atom-light-syntax": "0.17.0",
"atom-light-ui": "0.25.0",
"base16-tomorrow-dark-theme": "0.16.0",
"solarized-dark-syntax": "0.17.0",
"solarized-light-syntax": "0.8.0",
"archive-view": "0.32.0",
"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",
"archive-view": "0.33.0",
"autocomplete": "0.28.0",
"autoflow": "0.17.0",
"autosave": "0.14.0",
"background-tips": "0.14.0",
"bookmarks": "0.24.0",
"bracket-matcher": "0.46.0",
"command-palette": "0.22.0",
"background-tips": "0.15.0",
"bookmarks": "0.25.0",
"bracket-matcher": "0.47.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.117.0",
"fuzzy-finder": "0.54.0",
"git-diff": "0.31.0",
"go-to-line": "0.22.0",
"find-and-replace": "0.122.0",
"fuzzy-finder": "0.56.0",
"git-diff": "0.34.0",
"go-to-line": "0.23.0",
"grammar-selector": "0.27.0",
"image-view": "0.35.0",
"image-view": "0.36.0",
"keybinding-resolver": "0.18.0",
"link": "0.22.0",
"markdown-preview": "0.80.0",
"link": "0.24.0",
"markdown-preview": "0.86.0",
"metrics": "0.32.0",
"open-on-github": "0.28.0",
"open-on-github": "0.29.0",
"package-generator": "0.31.0",
"release-notes": "0.32.0",
"settings-view": "0.127.0",
"snippets": "0.45.0",
"spell-check": "0.37.0",
"status-bar": "0.40.0",
"settings-view": "0.129.0",
"snippets": "0.47.0",
"spell-check": "0.38.0",
"status-bar": "0.41.0",
"styleguide": "0.29.0",
"symbols-view": "0.56.0",
"tabs": "0.41.0",
"timecop": "0.19.0",
"tree-view": "0.103.0",
"symbols-view": "0.59.0",
"tabs": "0.42.0",
"timecop": "0.21.0",
"tree-view": "0.108.0",
"update-package-dependencies": "0.6.0",
"welcome": "0.16.0",
"whitespace": "0.22.0",
"wrap-guide": "0.18.0",
"language-c": "0.18.0",
"welcome": "0.17.0",
"whitespace": "0.23.0",
"wrap-guide": "0.19.0",
"language-c": "0.21.0",
"language-coffee-script": "0.22.0",
"language-css": "0.17.0",
"language-gfm": "0.39.0",
"language-gfm": "0.42.0",
"language-git": "0.9.0",
"language-go": "0.12.0",
"language-go": "0.13.0",
"language-html": "0.22.0",
"language-hyperlink": "0.10.0",
"language-java": "0.10.0",
"language-javascript": "0.27.0",
"language-java": "0.11.0",
"language-javascript": "0.30.0",
"language-json": "0.8.0",
"language-less": "0.9.0",
"language-less": "0.11.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.29.0",
"language-ruby-on-rails": "0.14.0",
"language-ruby": "0.30.0",
"language-ruby-on-rails": "0.15.0",
"language-sass": "0.13.0",
"language-shellscript": "0.8.0",
"language-source": "0.7.0",
@@ -134,8 +135,8 @@
"language-text": "0.6.0",
"language-todo": "0.10.0",
"language-toml": "0.12.0",
"language-xml": "0.14.0",
"language-yaml": "0.7.0"
"language-xml": "0.15.0",
"language-yaml": "0.10.0"
},
"private": true,
"scripts": {
+2 -2
Ver Arquivo
@@ -1,8 +1,8 @@
[Desktop Entry]
Name=Atom
Comment=<%= description %>
Exec=/usr/share/atom/atom %U
Icon=atom
Exec=<%= installDir %>/share/atom/atom %U
Icon=<%= iconName %>
Type=Application
StartupNotify=true
Categories=GNOME;GTK;Utility;TextEditor;
Arquivo binário não exibido.
Arquivo binário não exibido.
+27
Ver Arquivo
@@ -17,6 +17,33 @@ describe "ContextMenuManager", ->
expect(contextMenu.definitions['.selector'][0].label).toEqual 'label'
expect(contextMenu.definitions['.selector'][0].command).toEqual 'command'
it 'does not add duplicate menu items', ->
contextMenu.add 'file-path',
'.selector':
'label': 'command'
contextMenu.add 'file-path',
'.selector':
'label': 'command'
expect(contextMenu.definitions['.selector'][0].label).toEqual 'label'
expect(contextMenu.definitions['.selector'][0].command).toEqual 'command'
expect(contextMenu.definitions['.selector'].length).toBe 1
it 'allows duplicate commands with different labels', ->
contextMenu.add 'file-path',
'.selector':
'label': 'command'
contextMenu.add 'file-path',
'.selector':
'another label': 'command'
expect(contextMenu.definitions['.selector'][0].label).toEqual 'label'
expect(contextMenu.definitions['.selector'][0].command).toEqual 'command'
expect(contextMenu.definitions['.selector'][1].label).toEqual 'another label'
expect(contextMenu.definitions['.selector'][1].command).toEqual 'command'
it "loads submenus", ->
contextMenu.add 'file-path',
'.selector':
+117 -5
Ver Arquivo
@@ -47,6 +47,15 @@ describe "DisplayBuffer", ->
buffer.insert([0,0], oneHundredLines)
expect(displayBuffer.getLineCount()).toBe 100 + originalLineCount
it "reassigns the scrollTop if it exceeds the max possible value after lines are removed", ->
displayBuffer.manageScrollPosition = true
displayBuffer.setHeight(50)
displayBuffer.setLineHeightInPixels(10)
displayBuffer.setScrollTop(80)
buffer.delete([[8, 0], [10, 0]])
expect(displayBuffer.getScrollTop()).toBe 60
describe "soft wrapping", ->
beforeEach ->
displayBuffer.setSoftWrap(true)
@@ -315,6 +324,16 @@ describe "DisplayBuffer", ->
expect(line0.fold).toBe outerFold
expect(line1.fold).toBeUndefined()
describe "when a fold ends where another fold begins", ->
it "continues to hide the lines inside the second fold", ->
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/
describe "when there is another display buffer pointing to the same buffer", ->
it "does not create folds in the other display buffer", ->
otherDisplayBuffer = new DisplayBuffer({buffer, tabLength})
@@ -912,6 +931,42 @@ describe "DisplayBuffer", ->
expect(displayBuffer.findMarkers(class: 'a', startBufferRow: 0, endBufferRow: 3)).toEqual [marker1]
expect(displayBuffer.findMarkers(endBufferRow: 10)).toEqual [marker3]
it "allows the startScreenRow and endScreenRow to be specified", ->
marker1 = displayBuffer.markBufferRange([[6, 0], [7, 0]], class: 'a')
marker2 = displayBuffer.markBufferRange([[9, 0], [10, 0]], class: 'a')
displayBuffer.createFold(4, 7)
expect(displayBuffer.findMarkers(class: 'a', startScreenRow: 6, endScreenRow: 7)).toEqual [marker2]
it "allows intersectsBufferRowRange to be specified", ->
marker1 = displayBuffer.markBufferRange([[5, 0], [5, 0]], class: 'a')
marker2 = displayBuffer.markBufferRange([[8, 0], [8, 0]], class: 'a')
displayBuffer.createFold(4, 7)
expect(displayBuffer.findMarkers(class: 'a', intersectsBufferRowRange: [5, 6])).toEqual [marker1]
it "allows intersectsScreenRowRange to be specified", ->
marker1 = displayBuffer.markBufferRange([[5, 0], [5, 0]], class: 'a')
marker2 = displayBuffer.markBufferRange([[8, 0], [8, 0]], class: 'a')
displayBuffer.createFold(4, 7)
expect(displayBuffer.findMarkers(class: 'a', intersectsScreenRowRange: [5, 10])).toEqual [marker2]
it "allows containedInScreenRange to be specified", ->
marker1 = displayBuffer.markBufferRange([[5, 0], [5, 0]], class: 'a')
marker2 = displayBuffer.markBufferRange([[8, 0], [8, 0]], class: 'a')
displayBuffer.createFold(4, 7)
expect(displayBuffer.findMarkers(class: 'a', containedInScreenRange: [[5, 0], [7, 0]])).toEqual [marker2]
it "allows intersectsBufferRange to be specified", ->
marker1 = displayBuffer.markBufferRange([[5, 0], [5, 0]], class: 'a')
marker2 = displayBuffer.markBufferRange([[8, 0], [8, 0]], class: 'a')
displayBuffer.createFold(4, 7)
expect(displayBuffer.findMarkers(class: 'a', intersectsBufferRange: [[5, 0], [6, 0]])).toEqual [marker1]
it "allows intersectsScreenRange to be specified", ->
marker1 = displayBuffer.markBufferRange([[5, 0], [5, 0]], class: 'a')
marker2 = displayBuffer.markBufferRange([[8, 0], [8, 0]], class: 'a')
displayBuffer.createFold(4, 7)
expect(displayBuffer.findMarkers(class: 'a', intersectsScreenRange: [[5, 0], [10, 0]])).toEqual [marker2]
describe "marker destruction", ->
it "allows markers to be destroyed", ->
marker = displayBuffer.markScreenRange([[5, 4], [5, 10]])
@@ -950,12 +1005,25 @@ describe "DisplayBuffer", ->
displayBuffer.setLineHeightInPixels(20)
displayBuffer.setDefaultCharWidth(10)
displayBuffer.setScopedCharWidths(["source.js", "keyword.control.js"], r: 11, e: 11, t: 11, u: 11, n: 11)
for char in ['r', 'e', 't', 'u', 'r', 'n']
displayBuffer.setScopedCharWidth(["source.js", "keyword.control.js"], char, 11)
{start, end} = marker.getPixelRange()
expect(start.top).toBe 5 * 20
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 = displayBuffer.markBufferRange([[2, 13], [3, 15]])
displayBuffer.addDecorationForMarker(marker, decoration)
expect(displayBuffer.decorationsForScreenRowRange(2, 3)[marker.id][0]).toBe decoration
displayBuffer.removeDecorationForMarker(marker, decoration)
expect(displayBuffer.decorationsForScreenRowRange(2, 3)[marker.id]).not.toBeDefined()
describe "::setScrollTop", ->
beforeEach ->
displayBuffer.manageScrollPosition = true
@@ -997,17 +1065,61 @@ describe "DisplayBuffer", ->
expect(displayBuffer.setScrollLeft(maxScrollLeft + 50)).toBe maxScrollLeft
expect(displayBuffer.getScrollLeft()).toBe maxScrollLeft
describe "::scrollToScreenPosition(position)", ->
it "sets the scroll top and scroll left so the given screen position is in view", ->
describe "::scrollToScreenPosition(position, [options])", ->
beforeEach ->
displayBuffer.manageScrollPosition = true
displayBuffer.setLineHeightInPixels(10)
displayBuffer.setDefaultCharWidth(10)
displayBuffer.setHorizontalScrollbarHeight(0)
displayBuffer.setHeight(50)
displayBuffer.setWidth(50)
maxScrollTop = displayBuffer.getScrollHeight() - displayBuffer.getHeight()
it "sets the scroll top and scroll left so the given screen position is in view", ->
displayBuffer.scrollToScreenPosition([8, 20])
expect(displayBuffer.getScrollBottom()).toBe (9 + displayBuffer.getVerticalScrollMargin()) * 10
expect(displayBuffer.getScrollRight()).toBe (20 + displayBuffer.getHorizontalScrollMargin()) * 10
describe "when the 'center' option is true", ->
it "vertically scrolls to center the given position vertically", ->
displayBuffer.scrollToScreenPosition([8, 20], center: true)
expect(displayBuffer.getScrollTop()).toBe (8 * 10) + 5 - (50 / 2)
expect(displayBuffer.getScrollRight()).toBe (20 + displayBuffer.getHorizontalScrollMargin()) * 10
it "does not scroll vertically if the position is already in view", ->
displayBuffer.scrollToScreenPosition([4, 20], center: true)
expect(displayBuffer.getScrollTop()).toBe 0
describe "scroll width", ->
cursorWidth = 1
beforeEach ->
displayBuffer.setDefaultCharWidth(10)
it "recomputes the scroll width when the default character width changes", ->
expect(displayBuffer.getScrollWidth()).toBe 10 * 65 + cursorWidth
displayBuffer.setDefaultCharWidth(12)
expect(displayBuffer.getScrollWidth()).toBe 12 * 65 + cursorWidth
it "recomputes the scroll width when the max line length changes", ->
buffer.insert([6, 12], ' ')
expect(displayBuffer.getScrollWidth()).toBe 10 * 66 + cursorWidth
buffer.delete([[6, 10], [6, 12]], ' ')
expect(displayBuffer.getScrollWidth()).toBe 10 * 64 + cursorWidth
it "recomputes the scroll width when the scoped character widths change", ->
operatorWidth = 20
displayBuffer.setScopedCharWidth(['source.js', 'keyword.operator.js'], '<', operatorWidth)
expect(displayBuffer.getScrollWidth()).toBe 10 * 64 + operatorWidth + cursorWidth
it "recomputes the scroll width when the scoped character widths change in a batch", ->
operatorWidth = 20
displayBuffer.on 'character-widths-changed', changedSpy = jasmine.createSpy()
displayBuffer.batchCharacterMeasurement ->
displayBuffer.setScopedCharWidth(['source.js', 'keyword.operator.js'], '<', operatorWidth)
displayBuffer.setScopedCharWidth(['source.js', 'keyword.operator.js'], '?', operatorWidth)
expect(displayBuffer.getScrollWidth()).toBe 10 * 63 + operatorWidth * 2 + cursorWidth
expect(changedSpy.callCount).toBe 1
Diferenças do arquivo suprimidas por serem muito extensas Carregar Diff
+79 -103
Ver Arquivo
@@ -1196,6 +1196,7 @@ describe "Editor", ->
editor.setHeight(50)
editor.setWidth(50)
editor.setHorizontalScrollbarHeight(0)
expect(editor.getScrollTop()).toBe 0
editor.setSelectedBufferRange([[5, 6], [6, 8]], autoscroll: true)
@@ -1220,6 +1221,21 @@ describe "Editor", ->
expect(editor.selectMarker(marker)).toBeFalsy()
expect(editor.getSelectedBufferRange()).toEqual [[0, 0], [0, 0]]
describe ".addSelectionForBufferRange(bufferRange)", ->
it "adds a selection for the specified buffer range", ->
editor.addSelectionForBufferRange([[3, 4], [5, 6]])
expect(editor.getSelectedBufferRanges()).toEqual [[[0, 0], [0, 0]], [[3, 4], [5, 6]]]
it "autoscrolls to the added selection if needed", ->
editor.setLineHeightInPixels(10)
editor.setDefaultCharWidth(10)
editor.setHeight(50)
editor.setWidth(50)
editor.addSelectionForBufferRange([[8, 10], [8, 15]])
expect(editor.getScrollTop()).toBe 75
expect(editor.getScrollLeft()).toBe 160
describe ".addSelectionBelow()", ->
describe "when the selection is non-empty", ->
it "selects the same region of the line below current selections if possible", ->
@@ -1467,6 +1483,17 @@ describe "Editor", ->
expect(cursor1.getBufferPosition()).toEqual [1, 5]
expect(cursor2.getBufferPosition()).toEqual [2, 7]
it "autoscrolls to the last cursor", ->
editor.manageScrollPosition = true
editor.setCursorScreenPosition([1, 2])
editor.addCursorAtScreenPosition([10, 4])
editor.setLineHeightInPixels(10)
editor.setHeight(50)
expect(editor.getScrollTop()).toBe 0
editor.insertText('a')
expect(editor.getScrollTop()).toBe 80
describe "when there are multiple non-empty selections", ->
describe "when the selections are on the same line", ->
it "replaces each selection range with the inserted characters", ->
@@ -1831,6 +1858,32 @@ describe "Editor", ->
expect(buffer.lineForRow(1)).toBe ' var sort = function(it) {'
expect(buffer.lineForRow(2)).toBe 'if (items.length <= 1) return items;'
describe '.deleteToEndOfLine()', ->
describe 'when no text is selected', ->
it 'deletes all text between the cursor and the end of the line', ->
editor.setCursorBufferPosition([1, 24])
editor.addCursorAtBufferPosition([2, 5])
[cursor1, cursor2] = editor.getCursors()
editor.deleteToEndOfLine()
expect(buffer.lineForRow(1)).toBe ' var sort = function(it'
expect(buffer.lineForRow(2)).toBe ' i'
expect(cursor1.getBufferPosition()).toEqual [1, 24]
expect(cursor2.getBufferPosition()).toEqual [2, 5]
describe 'when at the end of the line', ->
it 'deletes the next newline', ->
editor.setCursorBufferPosition([1, 30])
editor.deleteToEndOfLine()
expect(buffer.lineForRow(1)).toBe ' var sort = function(items) { if (items.length <= 1) return items;'
describe 'when text is selected', ->
it 'deletes only the text in the selection', ->
editor.setSelectedBufferRanges([[[1, 24], [1, 27]], [[2, 0], [2, 4]]])
editor.deleteToEndOfLine()
expect(buffer.lineForRow(1)).toBe ' var sort = function(it) {'
expect(buffer.lineForRow(2)).toBe 'if (items.length <= 1) return items;'
describe ".deleteToBeginningOfLine()", ->
describe "when no text is selected", ->
it "deletes all text between the cursor and the beginning of the line", ->
@@ -3244,113 +3297,36 @@ describe "Editor", ->
expect(editor.getScrollTop()).toBe 0
expect(editor.getCursorBufferPosition().row).toBe 0
describe "decorations", ->
decoration = null
beforeEach ->
decoration = {type: 'gutter', class: 'one'}
describe ".selectPageUp/Down()", ->
it "selects one screen height of text up or down", ->
editor.manageScrollPosition = true
it "can add decorations to buffer rows and remove them", ->
editor.addDecorationToBufferRow(2, decoration)
editor.addDecorationToBufferRow(2, decoration)
editor.setLineHeightInPixels(10)
editor.setHeight(50)
expect(editor.getScrollHeight()).toBe 130
expect(editor.getCursorBufferPosition().row).toBe 0
decorations = editor.decorationsForBufferRow(2)
expect(decorations).toHaveLength 1
expect(decorations).toContain decoration
editor.selectPageDown()
expect(editor.getScrollTop()).toBe 30
expect(editor.getSelectedBufferRanges()).toEqual [[[0,0], [5,0]]]
editor.removeDecorationFromBufferRow(2, decoration)
decorations = editor.decorationsForBufferRow(2)
expect(decorations).toHaveLength 0
editor.selectPageDown()
expect(editor.getScrollTop()).toBe 80
expect(editor.getSelectedBufferRanges()).toEqual [[[0,0], [10,0]]]
it "can add decorations to buffer row ranges and remove them", ->
editor.addDecorationToBufferRowRange(2, 4, decoration)
expect(editor.decorationsForBufferRow 2).toContain decoration
expect(editor.decorationsForBufferRow 3).toContain decoration
expect(editor.decorationsForBufferRow 4).toContain decoration
editor.selectPageDown()
expect(editor.getScrollTop()).toBe 80
expect(editor.getSelectedBufferRanges()).toEqual [[[0,0], [12,2]]]
editor.removeDecorationFromBufferRowRange(3, 5, decoration)
expect(editor.decorationsForBufferRow 2).toContain decoration
expect(editor.decorationsForBufferRow 3).not.toContain decoration
expect(editor.decorationsForBufferRow 4).not.toContain decoration
editor.moveCursorToBottom()
editor.selectPageUp()
expect(editor.getScrollTop()).toBe 50
expect(editor.getSelectedBufferRanges()).toEqual [[[7,0], [12,2]]]
it "can add decorations associated with markers and remove them", ->
marker = editor.displayBuffer.markBufferRange([[2, 13], [3, 15]], class: 'my-marker', invalidate: 'inside')
editor.selectPageUp()
expect(editor.getScrollTop()).toBe 0
expect(editor.getSelectedBufferRanges()).toEqual [[[2,0], [12,2]]]
editor.addDecorationForMarker(marker, decoration)
expect(editor.decorationsForBufferRow 1).not.toContain decoration
expect(editor.decorationsForBufferRow 2).toContain decoration
expect(editor.decorationsForBufferRow 3).toContain decoration
expect(editor.decorationsForBufferRow 4).not.toContain decoration
editor.getBuffer().insert([0, 0], '\n')
expect(editor.decorationsForBufferRow 2).not.toContain decoration
expect(editor.decorationsForBufferRow 3).toContain decoration
expect(editor.decorationsForBufferRow 4).toContain decoration
expect(editor.decorationsForBufferRow 5).not.toContain decoration
editor.getBuffer().insert([4, 2], 'n')
expect(editor.decorationsForBufferRow 2).not.toContain decoration
expect(editor.decorationsForBufferRow 3).not.toContain decoration
expect(editor.decorationsForBufferRow 4).not.toContain decoration
expect(editor.decorationsForBufferRow 5).not.toContain decoration
editor.getBuffer().undo()
expect(editor.decorationsForBufferRow 2).not.toContain decoration
expect(editor.decorationsForBufferRow 3).toContain decoration
expect(editor.decorationsForBufferRow 4).toContain decoration
expect(editor.decorationsForBufferRow 5).not.toContain decoration
editor.removeDecorationForMarker(marker, decoration)
expect(editor.decorationsForBufferRow 2).not.toContain decoration
expect(editor.decorationsForBufferRow 3).not.toContain decoration
expect(editor.decorationsForBufferRow 4).not.toContain decoration
expect(editor.decorationsForBufferRow 5).not.toContain decoration
describe "decorationsForBufferRow", ->
one = {type: 'one', class: 'one'}
two = {type: 'two', class: 'two'}
typeless = {class: 'typeless'}
beforeEach ->
editor.addDecorationToBufferRow(2, one)
editor.addDecorationToBufferRow(2, two)
editor.addDecorationToBufferRow(2, typeless)
it "returns all decorations with no decorationType specified", ->
decorations = editor.decorationsForBufferRow(2)
expect(decorations).toContain one
expect(decorations).toContain two
expect(decorations).toContain typeless
it "returns typeless decorations with all decorationTypes", ->
decorations = editor.decorationsForBufferRow(2, 'one')
expect(decorations).toContain one
expect(decorations).not.toContain two
expect(decorations).toContain typeless
describe "decorationsForBufferRowRange", ->
one = {type: 'one', class: 'one'}
two = {type: 'two', class: 'two'}
typeless = {class: 'typeless'}
it "returns an object of decorations based on the decorationType", ->
editor.addDecorationToBufferRow(2, one)
editor.addDecorationToBufferRow(3, one)
editor.addDecorationToBufferRow(5, one)
editor.addDecorationToBufferRow(3, two)
editor.addDecorationToBufferRow(4, two)
editor.addDecorationToBufferRow(3, typeless)
editor.addDecorationToBufferRow(5, typeless)
decorations = editor.decorationsForBufferRowRange(2, 5, 'one')
expect(decorations[2]).toContain one
expect(decorations[3]).toContain one
expect(decorations[3]).not.toContain two
expect(decorations[3]).toContain typeless
expect(decorations[4]).toHaveLength 0
expect(decorations[5]).toContain one
expect(decorations[5]).toContain typeless
editor.selectPageUp()
expect(editor.getScrollTop()).toBe 0
expect(editor.getSelectedBufferRanges()).toEqual [[[0,0], [12,2]]]
+5 -5
Ver Arquivo
@@ -1611,7 +1611,7 @@ describe "EditorView", ->
editorView.attachToDom()
expect(atom.config.get("editor.showInvisibles")).toBeFalsy()
expect(editorView.renderedLines.find('.line').text()).toBe " a line with tabs and spaces "
expect(editorView.renderedLines.find('.line').text()).toBe " a line with tabs and spaces "
atom.config.set("editor.showInvisibles", true)
space = editorView.invisibles?.space
@@ -1620,10 +1620,10 @@ describe "EditorView", ->
expect(tab).toBeTruthy()
eol = editorView.invisibles?.eol
expect(eol).toBeTruthy()
expect(editorView.renderedLines.find('.line').text()).toBe "#{space}a line with tabs#{tab} and spaces#{space}#{eol}"
expect(editorView.renderedLines.find('.line').text()).toBe "#{space}a line with tabs#{tab}and spaces#{space}#{eol}"
atom.config.set("editor.showInvisibles", false)
expect(editorView.renderedLines.find('.line').text()).toBe " a line with tabs and spaces "
expect(editorView.renderedLines.find('.line').text()).toBe " a line with tabs and spaces "
it "displays newlines as their own token outside of the other tokens scope", ->
editorView.setShowInvisibles(true)
@@ -1636,7 +1636,7 @@ describe "EditorView", ->
editorView.attachToDom()
atom.config.set("editor.showInvisibles", true)
atom.config.set("editor.invisibles", eol: ";", space: "_", tab: "tab")
expect(editorView.find(".line:first").text()).toBe "_tab _;"
expect(editorView.find(".line:first").text()).toBe "_tab_;"
it "displays trailing carriage return using a visible non-empty value", ->
editor.setText "a line that ends with a carriage return\r\n"
@@ -2082,7 +2082,7 @@ describe "EditorView", ->
tab = miniEditor.invisibles?.tab
expect(tab).toBeTruthy()
miniEditor.getEditor().setText(" a line with tabs\tand spaces ")
expect(miniEditor.renderedLines.find('.line').text()).toBe "#{space}a line with tabs#{tab} and spaces#{space}"
expect(miniEditor.renderedLines.find('.line').text()).toBe "#{space}a line with tabs#{tab}and spaces#{space}"
it "doesn't show the indent guide", ->
atom.config.set "editor.showIndentGuide", true
+11
Ver Arquivo
@@ -205,6 +205,17 @@ describe "Project", ->
fs.writeFileSync(filePath, sampleContent)
fs.writeFileSync(commentFilePath, sampleCommentContent)
describe "when a file doesn't exist", ->
it "calls back with an error", ->
errors = []
waitsForPromise ->
atom.project.replace /items/gi, 'items', ['/not-a-file.js'], (result, error) ->
errors.push(error)
runs ->
expect(errors).toHaveLength 1
expect(errors[0].path).toBe '/not-a-file.js'
describe "when called with unopened files", ->
it "replaces properly", ->
results = []
+9 -1
Ver Arquivo
@@ -15,6 +15,7 @@ Project = require '../src/project'
Editor = require '../src/editor'
EditorView = require '../src/editor-view'
TokenizedBuffer = require '../src/tokenized-buffer'
EditorComponent = require '../src/editor-component'
pathwatcher = require 'pathwatcher'
clipboard = require 'clipboard'
@@ -33,7 +34,12 @@ $(window).on 'unload', ->
$('html,body').css('overflow', 'auto')
jasmine.getEnv().addEqualityTester(_.isEqual) # Use underscore's definition of equality for toEqual assertions
jasmine.getEnv().defaultTimeoutInterval = 5000
if process.platform is 'win32' and process.env.JANKY_SHA1
# Use longer timeout on Windows CI
jasmine.getEnv().defaultTimeoutInterval = 30000
else
jasmine.getEnv().defaultTimeoutInterval = 5000
specPackageName = null
specPackagePath = null
@@ -95,6 +101,8 @@ beforeEach ->
# make editor display updates synchronous
spyOn(EditorView.prototype, 'requestDisplayUpdate').andCallFake -> @updateDisplay()
EditorComponent.performSyncUpdates = true
spyOn(WorkspaceView.prototype, 'setTitle').andCallFake (@title) ->
spyOn(window, "setTimeout").andCallFake window.fakeSetTimeout
spyOn(window, "clearTimeout").andCallFake window.fakeClearTimeout
+135 -4
Ver Arquivo
@@ -335,16 +335,84 @@ describe "TokenizedBuffer", ->
expect(screenLine0.text).toBe "# Econ 101#{tabAsSpaces}"
{ tokens } = screenLine0
expect(tokens.length).toBe 3
expect(tokens.length).toBe 4
expect(tokens[0].value).toBe "#"
expect(tokens[1].value).toBe " Econ 101"
expect(tokens[2].value).toBe tabAsSpaces
expect(tokens[2].scopes).toEqual tokens[1].scopes
expect(tokens[2].isAtomic).toBeTruthy()
expect(tokens[3].value).toBe ""
expect(tokenizedBuffer.lineForScreenRow(2).text).toBe "#{tabAsSpaces} buy()#{tabAsSpaces}while supply > demand"
describe "when the buffer contains surrogate pairs", ->
it "aligns the hard tabs to the correct tab stop column", ->
buffer.setText """
1\t2 \t3\t4
12\t3 \t4\t5
123\t4 \t5\t6
"""
tokenizedBuffer.setTabLength(4)
fullyTokenize(tokenizedBuffer)
expect(tokenizedBuffer.lineForScreenRow(0).text).toBe "1 2 3 4"
expect(tokenizedBuffer.lineForScreenRow(0).tokens[1].bufferDelta).toBe 1
expect(tokenizedBuffer.lineForScreenRow(0).tokens[1].screenDelta).toBe 3
expect(tokenizedBuffer.lineForScreenRow(1).text).toBe "12 3 4 5"
expect(tokenizedBuffer.lineForScreenRow(1).tokens[1].bufferDelta).toBe 1
expect(tokenizedBuffer.lineForScreenRow(1).tokens[1].screenDelta).toBe 2
expect(tokenizedBuffer.lineForScreenRow(2).text).toBe "123 4 5 6"
expect(tokenizedBuffer.lineForScreenRow(2).tokens[1].bufferDelta).toBe 1
expect(tokenizedBuffer.lineForScreenRow(2).tokens[1].screenDelta).toBe 1
tokenizedBuffer.setTabLength(3)
fullyTokenize(tokenizedBuffer)
expect(tokenizedBuffer.lineForScreenRow(0).text).toBe "1 2 3 4"
expect(tokenizedBuffer.lineForScreenRow(0).tokens[1].bufferDelta).toBe 1
expect(tokenizedBuffer.lineForScreenRow(0).tokens[1].screenDelta).toBe 2
expect(tokenizedBuffer.lineForScreenRow(1).text).toBe "12 3 4 5"
expect(tokenizedBuffer.lineForScreenRow(1).tokens[1].bufferDelta).toBe 1
expect(tokenizedBuffer.lineForScreenRow(1).tokens[1].screenDelta).toBe 1
expect(tokenizedBuffer.lineForScreenRow(2).text).toBe "123 4 5 6"
expect(tokenizedBuffer.lineForScreenRow(2).tokens[1].bufferDelta).toBe 1
expect(tokenizedBuffer.lineForScreenRow(2).tokens[1].screenDelta).toBe 3
tokenizedBuffer.setTabLength(2)
fullyTokenize(tokenizedBuffer)
expect(tokenizedBuffer.lineForScreenRow(0).text).toBe "1 2 3 4"
expect(tokenizedBuffer.lineForScreenRow(0).tokens[1].bufferDelta).toBe 1
expect(tokenizedBuffer.lineForScreenRow(0).tokens[1].screenDelta).toBe 1
expect(tokenizedBuffer.lineForScreenRow(1).text).toBe "12 3 4 5"
expect(tokenizedBuffer.lineForScreenRow(1).tokens[1].bufferDelta).toBe 1
expect(tokenizedBuffer.lineForScreenRow(1).tokens[1].screenDelta).toBe 2
expect(tokenizedBuffer.lineForScreenRow(2).text).toBe "123 4 5 6"
expect(tokenizedBuffer.lineForScreenRow(2).tokens[1].bufferDelta).toBe 1
expect(tokenizedBuffer.lineForScreenRow(2).tokens[1].screenDelta).toBe 1
tokenizedBuffer.setTabLength(1)
fullyTokenize(tokenizedBuffer)
expect(tokenizedBuffer.lineForScreenRow(0).text).toBe "1 2 3 4"
expect(tokenizedBuffer.lineForScreenRow(0).tokens[1].bufferDelta).toBe 1
expect(tokenizedBuffer.lineForScreenRow(0).tokens[1].screenDelta).toBe 1
expect(tokenizedBuffer.lineForScreenRow(1).text).toBe "12 3 4 5"
expect(tokenizedBuffer.lineForScreenRow(1).tokens[1].bufferDelta).toBe 1
expect(tokenizedBuffer.lineForScreenRow(1).tokens[1].screenDelta).toBe 1
expect(tokenizedBuffer.lineForScreenRow(2).text).toBe "123 4 5 6"
expect(tokenizedBuffer.lineForScreenRow(2).tokens[1].bufferDelta).toBe 1
expect(tokenizedBuffer.lineForScreenRow(2).tokens[1].screenDelta).toBe 1
describe "when the buffer contains UTF-8 surrogate pairs", ->
beforeEach ->
waitsForPromise ->
atom.packages.activatePackage('language-javascript')
@@ -362,7 +430,7 @@ describe "TokenizedBuffer", ->
tokenizedBuffer.destroy()
buffer.release()
it "renders each surrogate pair as its own atomic token", ->
it "renders each UTF-8 surrogate pair as its own atomic token", ->
screenLine0 = tokenizedBuffer.lineForScreenRow(0)
expect(screenLine0.text).toBe "'abc\uD835\uDF97def'"
{ tokens } = screenLine0
@@ -379,11 +447,12 @@ describe "TokenizedBuffer", ->
expect(screenLine1.text).toBe "//\uD835\uDF97xyz"
{ tokens } = screenLine1
expect(tokens.length).toBe 3
expect(tokens.length).toBe 4
expect(tokens[0].value).toBe '//'
expect(tokens[1].value).toBe '\uD835\uDF97'
expect(tokens[1].value).toBeTruthy()
expect(tokens[2].value).toBe 'xyz'
expect(tokens[3].value).toBe ''
describe "when the grammar is tokenized", ->
it "emits the `tokenized` event", ->
@@ -588,3 +657,65 @@ describe "TokenizedBuffer", ->
buffer.setText('\n\n\n')
expect(tokenizedBuffer.lineForScreenRow(1).indentLevel).toBe 0
describe "when the changed lines are surrounded by whitespace-only lines", ->
it "updates the indentLevel of empty lines that precede the change", ->
expect(tokenizedBuffer.lineForScreenRow(12).indentLevel).toBe 0
buffer.insert([12, 0], '\n')
buffer.insert([13, 0], ' ')
expect(tokenizedBuffer.lineForScreenRow(12).indentLevel).toBe 1
it "updates empty line indent guides when the empty line is the last line", ->
buffer.insert([12, 2], '\n')
# The newline and he tab need to be in two different operations to surface the bug
buffer.insert([12, 0], ' ')
expect(tokenizedBuffer.lineForScreenRow(13).indentLevel).toBe 1
buffer.insert([12, 0], ' ')
expect(tokenizedBuffer.lineForScreenRow(13).indentLevel).toBe 2
expect(tokenizedBuffer.lineForScreenRow(14)).not.toBeDefined()
it "updates the indentLevel of empty lines surrounding a change that inserts lines", ->
# create some new lines
buffer.insert([7, 0], '\n\n')
buffer.insert([5, 0], '\n\n')
expect(tokenizedBuffer.lineForScreenRow(5).indentLevel).toBe 3
expect(tokenizedBuffer.lineForScreenRow(6).indentLevel).toBe 3
expect(tokenizedBuffer.lineForScreenRow(9).indentLevel).toBe 2
expect(tokenizedBuffer.lineForScreenRow(10).indentLevel).toBe 2
expect(tokenizedBuffer.lineForScreenRow(11).indentLevel).toBe 2
tokenizedBuffer.on "changed", changeHandler = jasmine.createSpy('changeHandler')
buffer.setTextInRange([[7, 0], [8, 65]], ' one\n two\n three\n four')
delete changeHandler.argsForCall[0][0].bufferChange
expect(changeHandler).toHaveBeenCalledWith(start: 5, end: 8, 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(13).indentLevel).toBe 2
it "updates the indentLevel of empty lines surrounding a change that removes lines", ->
# create some new lines
buffer.insert([7, 0], '\n\n')
buffer.insert([5, 0], '\n\n')
tokenizedBuffer.on "changed", changeHandler = jasmine.createSpy('changeHandler')
buffer.setTextInRange([[7, 0], [8, 65]], ' ok')
delete changeHandler.argsForCall[0][0].bufferChange
expect(changeHandler).toHaveBeenCalledWith(start: 5, end: 8, delta: -1)
expect(tokenizedBuffer.lineForScreenRow(5).indentLevel).toBe 2
expect(tokenizedBuffer.lineForScreenRow(6).indentLevel).toBe 2
expect(tokenizedBuffer.lineForScreenRow(7).indentLevel).toBe 2 # new text
expect(tokenizedBuffer.lineForScreenRow(8).indentLevel).toBe 2
expect(tokenizedBuffer.lineForScreenRow(9).indentLevel).toBe 2
expect(tokenizedBuffer.lineForScreenRow(10).indentLevel).toBe 2 # }
+14
Ver Arquivo
@@ -4,6 +4,20 @@ describe "TokenizedLine", ->
beforeEach ->
waitsForPromise -> atom.packages.activatePackage('language-coffee-script')
describe "::isOnlyWhitespace()", ->
beforeEach ->
waitsForPromise ->
atom.project.open('coffee.coffee').then (o) -> editor = o
it "returns true when the line is only whitespace", ->
expect(editor.lineForScreenRow(3).isOnlyWhitespace()).toBe true
expect(editor.lineForScreenRow(7).isOnlyWhitespace()).toBe true
expect(editor.lineForScreenRow(23).isOnlyWhitespace()).toBe true
it "returns false when the line is not only whitespace", ->
expect(editor.lineForScreenRow(0).isOnlyWhitespace()).toBe false
expect(editor.lineForScreenRow(2).isOnlyWhitespace()).toBe false
describe "::getScopeTree()", ->
it "returns a tree whose inner nodes are scopes and whose leaf nodes are tokens in those scopes", ->
[tokens, tokenIndex] = []
+25
Ver Arquivo
@@ -309,3 +309,28 @@ describe "Workspace", ->
expect(handler.callCount).toBe 1
editorCopy = editor.copy()
expect(handler.callCount).toBe 2
it "stores the active grammars used by all the open editors", ->
waitsForPromise ->
atom.packages.activatePackage('language-javascript')
waitsForPromise ->
atom.packages.activatePackage('language-coffee-script')
waitsForPromise ->
atom.workspace.open('sample.coffee')
runs ->
atom.workspace.getActiveEditor().setText('i = /test/;')
state = atom.workspace.serialize()
expect(state.packagesWithActiveGrammars).toEqual ['language-coffee-script', 'language-javascript']
jsPackage = atom.packages.getLoadedPackage('language-javascript')
coffeePackage = atom.packages.getLoadedPackage('language-coffee-script')
spyOn(jsPackage, 'loadGrammarsSync')
spyOn(coffeePackage, 'loadGrammarsSync')
workspace2 = Workspace.deserialize(state)
expect(jsPackage.loadGrammarsSync.callCount).toBe 1
expect(coffeePackage.loadGrammarsSync.callCount).toBe 1
+2 -2
Ver Arquivo
@@ -196,14 +196,14 @@ describe "WorkspaceView", ->
atom.workspaceView.height(200)
atom.workspaceView.attachToDom()
rightEditorView = atom.workspaceView.getActiveView()
rightEditorView.getEditor().setText(" \t ")
rightEditorView.getEditor().setText("\t ")
leftEditorView = rightEditorView.splitLeft()
expect(rightEditorView.find(".line:first").text()).toBe " "
expect(leftEditorView.find(".line:first").text()).toBe " "
{invisibles} = rightEditorView.component.state
{space, tab, eol} = invisibles
withInvisiblesShowing = "#{space}#{tab} #{space}#{eol}"
withInvisiblesShowing = "#{tab} #{space}#{space}#{eol}"
atom.workspaceView.trigger "window:toggle-invisibles"
expect(rightEditorView.find(".line:first").text()).toBe withInvisiblesShowing
+8
Ver Arquivo
@@ -258,13 +258,20 @@ class Atom extends Model
deserializeProject: ->
Project = require './project'
startTime = Date.now()
@project ?= @deserializers.deserialize(@state.project) ? new Project(path: @getLoadSettings().initialPath)
@deserializeTimings.project = Date.now() - startTime
deserializeWorkspaceView: ->
Workspace = require './workspace'
WorkspaceView = require './workspace-view'
startTime = Date.now()
@workspace = Workspace.deserialize(@state.workspace) ? new Workspace
@workspaceView = new WorkspaceView(@workspace)
@deserializeTimings.workspace = Date.now() - startTime
@keymaps.defaultTarget = @workspaceView[0]
$(@workspaceViewParentSelector).append(@workspaceView)
@@ -273,6 +280,7 @@ class Atom extends Model
delete @state.packageStates
deserializeEditorWindow: ->
@deserializeTimings = {}
@deserializePackageStates()
@deserializeProject()
@deserializeWorkspaceView()
+2 -1
Ver Arquivo
@@ -60,7 +60,8 @@ class ContextMenuManager
# editor is in dev mode.
addBySelector: (selector, definition, {devMode}={}) ->
definitions = if devMode then @devModeDefinitions else @definitions
(definitions[selector] ?= []).push(definition)
unless _.findWhere(definitions[selector], definition)
(definitions[selector] ?= []).push(definition)
# Returns definitions which match the element and devMode.
definitionsForElement: (element, {devMode}={}) ->
+18 -5
Ver Arquivo
@@ -1,16 +1,29 @@
React = require 'react-atom-fork'
{div} = require 'reactionary-atom-fork'
{isEqualForProperties} = require 'underscore-plus'
module.exports =
CursorComponent = React.createClass
displayName: 'CursorComponent'
render: ->
{editor, screenRange, scrollTop, scrollLeft, defaultCharWidth} = @props
{top, left, height, width} = editor.pixelRectForScreenRange(screenRange)
top -= scrollTop
left -= scrollLeft
{pixelRect, defaultCharWidth} = @props
{height, width} = pixelRect
width = defaultCharWidth if width is 0
WebkitTransform = "translate3d(#{left}px, #{top}px, 0px)"
WebkitTransform = @getTransform()
div className: 'cursor', style: {height, width, WebkitTransform}
getTransform: ->
{pixelRect, scrollTop, scrollLeft, useHardwareAcceleration} = @props
{top, left} = pixelRect
top -= scrollTop
left -= scrollLeft
if useHardwareAcceleration
"translate3d(#{left}px, #{top}px, 0px)"
else
"translate(#{left}px, #{top}px)"
shouldComponentUpdate: (newProps) ->
not isEqualForProperties(newProps, @props, 'pixelRect', 'scrollTop', 'scrollLeft', 'defaultCharWidth')
+4 -5
Ver Arquivo
@@ -29,9 +29,6 @@ class Cursor extends Model
# Supports old editor view
@needsAutoscroll ?= @isLastCursor() and !textChanged
# Supports react editor view
@autoscroll() if @needsAutoscroll and @editor.manageScrollPosition
@goalColumn = null
movedEvent =
@@ -55,8 +52,10 @@ class Cursor extends Model
changePosition: (options, fn) ->
@clearSelection()
@needsAutoscroll = options.autoscroll ? @isLastCursor()
unless fn()
@emit 'autoscrolled' if @needsAutoscroll
fn()
if @needsAutoscroll
@emit 'autoscrolled' # Support legacy editor
@autoscroll() if @needsAutoscroll and @editor.manageScrollPosition # Support react editor view
getPixelRect: ->
@editor.pixelRectForScreenRange(@getScreenRange())
+9 -5
Ver Arquivo
@@ -12,7 +12,7 @@ CursorsComponent = React.createClass
cursorBlinkIntervalHandle: null
render: ->
{editor, cursorScreenRanges, scrollTop, scrollLeft, defaultCharWidth} = @props
{cursorPixelRects, scrollTop, scrollLeft, defaultCharWidth, useHardwareAcceleration} = @props
{blinkOff} = @state
className = 'cursors'
@@ -20,8 +20,8 @@ CursorsComponent = React.createClass
div {className},
if @isMounted()
for key, screenRange of cursorScreenRanges
CursorComponent({key, editor, screenRange, scrollTop, scrollLeft, defaultCharWidth})
for key, pixelRect of cursorPixelRects
CursorComponent({key, pixelRect, scrollTop, scrollLeft, defaultCharWidth, useHardwareAcceleration})
getInitialState: ->
blinkOff: false
@@ -34,10 +34,14 @@ CursorsComponent = React.createClass
shouldComponentUpdate: (newProps, newState) ->
not newState.blinkOff is @state.blinkOff or
not isEqualForProperties(newProps, @props, 'cursorScreenRanges', 'scrollTop', 'scrollLeft', 'lineHeightInPixels', 'defaultCharWidth')
not isEqualForProperties(newProps, @props, 'cursorPixelRects', 'scrollTop', 'scrollLeft', 'defaultCharWidth', 'useHardwareAcceleration')
componentWillUpdate: (newProps) ->
@pauseCursorBlinking() if @props.cursorScreenRanges and not isEqual(newProps.cursorScreenRanges, @props.cursorScreenRanges)
cursorsMoved = @props.cursorPixelRects? and
isEqualForProperties(newProps, @props, 'defaultCharWidth', 'scopedCharacterWidthsChangeCount') and
not isEqual(newProps.cursorPixelRects, @props.cursorPixelRects)
@pauseCursorBlinking() if cursorsMoved
startBlinkingCursors: ->
@toggleCursorBlinkHandle = setInterval(@toggleCursorBlink, @props.cursorBlinkPeriod / 2) if @isMounted()
+126 -89
Ver Arquivo
@@ -29,11 +29,13 @@ class DisplayBuffer extends Model
width: null
scrollTop: 0
scrollLeft: 0
scrollWidth: 0
verticalScrollMargin: 2
horizontalScrollMargin: 6
horizontalScrollbarHeight: 15
verticalScrollbarWidth: 15
scopedCharacterWidthsChangeCount: 0
constructor: ({tabLength, @editorWidthInChars, @tokenizedBuffer, buffer}={}) ->
super
@@ -43,8 +45,9 @@ class DisplayBuffer extends Model
@charWidthsByScope = {}
@markers = {}
@foldsByMarkerId = {}
@decorations = {}
@decorationMarkerSubscriptions = {}
@decorationsByMarkerId = {}
@decorationMarkerChangedSubscriptions = {}
@decorationMarkerDestroyedSubscriptions = {}
@updateAllScreenLines()
@createFoldForMarker(marker) for marker in @buffer.findMarkers(@getFoldMarkerAttributes())
@subscribe @tokenizedBuffer, 'grammar-changed', (grammar) => @emit 'grammar-changed', grammar
@@ -179,9 +182,12 @@ class DisplayBuffer extends Model
getScrollTop: -> @scrollTop
setScrollTop: (scrollTop) ->
if @manageScrollPosition
@scrollTop = Math.max(0, Math.min(@getScrollHeight() - @getClientHeight(), scrollTop))
@scrollTop = Math.round(Math.max(0, Math.min(@getMaxScrollTop(), scrollTop)))
else
@scrollTop = scrollTop
@scrollTop = Math.round(scrollTop)
getMaxScrollTop: ->
@getScrollHeight() - @getClientHeight()
getScrollBottom: -> @scrollTop + @height
setScrollBottom: (scrollBottom) ->
@@ -191,10 +197,10 @@ class DisplayBuffer extends Model
getScrollLeft: -> @scrollLeft
setScrollLeft: (scrollLeft) ->
if @manageScrollPosition
@scrollLeft = Math.max(0, Math.min(@getScrollWidth() - @getClientWidth(), scrollLeft))
@scrollLeft = Math.round(Math.max(0, Math.min(@getScrollWidth() - @getClientWidth(), scrollLeft)))
@scrollLeft
else
@scrollLeft = scrollLeft
@scrollLeft = Math.round(scrollLeft)
getScrollRight: -> @scrollLeft + @width
setScrollRight: (scrollRight) ->
@@ -205,7 +211,11 @@ class DisplayBuffer extends Model
setLineHeightInPixels: (@lineHeightInPixels) -> @lineHeightInPixels
getDefaultCharWidth: -> @defaultCharWidth
setDefaultCharWidth: (@defaultCharWidth) -> @defaultCharWidth
setDefaultCharWidth: (defaultCharWidth) ->
if defaultCharWidth isnt @defaultCharWidth
@defaultCharWidth = defaultCharWidth
@computeScrollWidth()
defaultCharWidth
getCursorWidth: -> 1
@@ -220,11 +230,21 @@ class DisplayBuffer extends Model
scope.charWidths ?= {}
scope.charWidths
batchCharacterMeasurement: (fn) ->
oldChangeCount = @scopedCharacterWidthsChangeCount
@batchingCharacterMeasurement = true
fn()
@batchingCharacterMeasurement = false
@characterWidthsChanged() if oldChangeCount isnt @scopedCharacterWidthsChangeCount
setScopedCharWidth: (scopeNames, char, width) ->
@getScopedCharWidths(scopeNames)[char] = width
@scopedCharacterWidthsChangeCount++
@characterWidthsChanged() unless @batchingCharacterMeasurement
setScopedCharWidths: (scopeNames, charWidths) ->
_.extend(@getScopedCharWidths(scopeNames), charWidths)
characterWidthsChanged: ->
@computeScrollWidth()
@emit 'character-widths-changed', @scopedCharacterWidthsChangeCount
clearScopedCharWidths: ->
@charWidthsByScope = {}
@@ -235,7 +255,7 @@ class DisplayBuffer extends Model
@getLineCount() * @getLineHeightInPixels()
getScrollWidth: ->
(@getMaxLineLength() * @getDefaultCharWidth()) + @getCursorWidth()
@scrollWidth
getVisibleRowRange: ->
return [0, 0] unless @getLineHeightInPixels() > 0
@@ -254,15 +274,23 @@ class DisplayBuffer extends Model
{start, end} = selection.getScreenRange()
@intersectsVisibleRowRange(start.row, end.row + 1)
scrollToScreenRange: (screenRange) ->
scrollToScreenRange: (screenRange, options) ->
verticalScrollMarginInPixels = @getVerticalScrollMargin() * @getLineHeightInPixels()
horizontalScrollMarginInPixels = @getHorizontalScrollMargin() * @getDefaultCharWidth()
{top, left, height, width} = @pixelRectForScreenRange(screenRange)
bottom = top + height
right = left + width
desiredScrollTop = top - verticalScrollMarginInPixels
desiredScrollBottom = bottom + verticalScrollMarginInPixels
if options?.center
desiredScrollCenter = top + height / 2
unless @getScrollTop() < desiredScrollCenter < @getScrollBottom()
desiredScrollTop = desiredScrollCenter - @getHeight() / 2
desiredScrollBottom = desiredScrollCenter + @getHeight() / 2
else
desiredScrollTop = top - verticalScrollMarginInPixels
desiredScrollBottom = bottom + verticalScrollMarginInPixels
desiredScrollLeft = left - horizontalScrollMarginInPixels
desiredScrollRight = right + horizontalScrollMarginInPixels
@@ -276,11 +304,11 @@ class DisplayBuffer extends Model
else if desiredScrollRight > @getScrollRight()
@setScrollRight(desiredScrollRight)
scrollToScreenPosition: (screenPosition) ->
@scrollToScreenRange(new Range(screenPosition, screenPosition))
scrollToScreenPosition: (screenPosition, options) ->
@scrollToScreenRange(new Range(screenPosition, screenPosition), options)
scrollToBufferPosition: (bufferPosition) ->
@scrollToScreenPosition(@screenPositionForBufferPosition(bufferPosition))
scrollToBufferPosition: (bufferPosition, options) ->
@scrollToScreenPosition(@screenPositionForBufferPosition(bufferPosition), options)
pixelRectForScreenRange: (screenRange) ->
if screenRange.end.row > screenRange.start.row
@@ -718,51 +746,19 @@ class DisplayBuffer extends Model
rangeForAllLines: ->
new Range([0, 0], @clipScreenPosition([Infinity, Infinity]))
decorationsForBufferRow: (bufferRow, decorationType) ->
decorations = @decorations[bufferRow] ? []
decorations = (dec for dec in decorations when not dec.type? or dec.type is decorationType) if decorationType?
decorations
decorationsForScreenRowRange: (startScreenRow, endScreenRow) ->
decorationsByMarkerId = {}
decorationsForBufferRowRange: (startBufferRow, endBufferRow, decorationType) ->
decorations = {}
for bufferRow in [startBufferRow..endBufferRow]
decorations[bufferRow] = @decorationsForBufferRow(bufferRow, decorationType)
decorations
for marker in @findMarkers(intersectsScreenRowRange: [startScreenRow, endScreenRow])
if decorations = @decorationsByMarkerId[marker.id]
decorationsByMarkerId[marker.id] = decorations
decorationsByMarkerId
addDecorationToBufferRow: (bufferRow, decoration) ->
@decorations[bufferRow] ?= []
for current in @decorations[bufferRow]
return if _.isEqual(current, decoration)
@decorations[bufferRow].push(decoration)
@emit 'decoration-changed', {bufferRow, decoration, action: 'add'}
removeDecorationFromBufferRow: (bufferRow, decorationPattern) ->
return unless decorations = @decorations[bufferRow]
removed = []
i = decorations.length - 1
while i >= 0
if @decorationMatchesPattern(decorations[i], decorationPattern)
removed.push decorations[i]
decorations.splice(i, 1)
i--
delete @decorations[bufferRow] unless @decorations[bufferRow]?
for decoration in removed
@emit 'decoration-changed', {bufferRow, decoration, action: 'remove'}
removed
addDecorationToBufferRowRange: (startBufferRow, endBufferRow, decoration) ->
for bufferRow in [startBufferRow..endBufferRow]
@addDecorationToBufferRow(bufferRow, decoration)
return
removeDecorationFromBufferRowRange: (startBufferRow, endBufferRow, decoration) ->
for bufferRow in [startBufferRow..endBufferRow]
@removeDecorationFromBufferRow(bufferRow, decoration)
return
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?
@@ -771,43 +767,56 @@ class DisplayBuffer extends Model
true
addDecorationForMarker: (marker, decoration) ->
startRow = marker.getStartBufferPosition().row
endRow = marker.getEndBufferPosition().row
@addDecorationToBufferRowRange(startRow, endRow, decoration)
unless marker?
console.warn 'A null marker cannot be decorated'
return
changedSubscription = @subscribe marker, 'changed', (e) =>
oldStartRow = e.oldHeadBufferPosition.row
oldEndRow = e.oldTailBufferPosition.row
newStartRow = e.newHeadBufferPosition.row
newEndRow = e.newTailBufferPosition.row
marker = @getMarker(marker.id)
# swap so head is always <= than tail
[oldEndRow, oldStartRow] = [oldStartRow, oldEndRow] if oldStartRow > oldEndRow
[newEndRow, newStartRow] = [newStartRow, newEndRow] if newStartRow > newEndRow
@decorationMarkerDestroyedSubscriptions[marker.id] ?= @subscribe marker, 'destroyed', =>
@removeAllDecorationsForMarker(marker)
@removeDecorationFromBufferRowRange(oldStartRow, oldEndRow, decoration)
@addDecorationToBufferRowRange(newStartRow, newEndRow, decoration) if e.isValid
@decorationMarkerChangedSubscriptions[marker.id] ?= @subscribe marker, 'changed', (event) =>
decorations = @decorationsByMarkerId[marker.id]
destroyedSubscription = @subscribe marker, 'destroyed', (e) =>
@removeDecorationForMarker(marker, decoration)
# Why check existence? Markers may get destroyed or decorations removed
# in the change handler. Bookmarks does this.
if decorations?
for decoration in decorations
@emit 'decoration-changed', marker, decoration, event
@decorationMarkerSubscriptions[marker.id] ?= []
@decorationMarkerSubscriptions[marker.id].push {decoration, changedSubscription, destroyedSubscription}
@decorationsByMarkerId[marker.id] ?= []
@decorationsByMarkerId[marker.id].push(decoration)
@emit 'decoration-added', marker, decoration
removeDecorationForMarker: (marker, decorationPattern) ->
return unless @decorationMarkerSubscriptions[marker.id]?
unless marker?
console.warn 'A decoration cannot be removed from a null marker'
return
startRow = marker.getStartBufferPosition().row
endRow = marker.getEndBufferPosition().row
@removeDecorationFromBufferRowRange(startRow, endRow, decorationPattern)
return unless decorations = @decorationsByMarkerId[marker.id]
for subscription in _.clone(@decorationMarkerSubscriptions[marker.id])
if @decorationMatchesPattern(subscription.decoration, decorationPattern)
subscription.changedSubscription.off()
subscription.destroyedSubscription.off()
@decorationMarkerSubscriptions[marker.id] = _.without(@decorationMarkerSubscriptions[marker.id], subscription)
for i in [decorations.length - 1..0]
decoration = decorations[i]
if @decorationMatchesPattern(decoration, decorationPattern)
decorations.splice(i, 1)
@emit 'decoration-removed', marker, decoration
return
@removedAllMarkerDecorations(marker) if decorations.length is 0
removeAllDecorationsForMarker: (marker) ->
decorations = @decorationsByMarkerId[marker.id].slice()
for decoration in decorations
@emit 'decoration-removed', marker, decoration
@removedAllMarkerDecorations(marker)
removedAllMarkerDecorations: (marker) ->
@decorationMarkerChangedSubscriptions[marker.id].off()
@decorationMarkerDestroyedSubscriptions[marker.id].off()
delete @decorationsByMarkerId[marker.id]
delete @decorationMarkerChangedSubscriptions[marker.id]
delete @decorationMarkerDestroyedSubscriptions[marker.id]
# Retrieves a {DisplayBufferMarker} based on its id.
#
@@ -912,13 +921,34 @@ class DisplayBuffer extends Model
key = 'startRow'
when 'endBufferRow'
key = 'endRow'
when 'startScreenRow'
key = 'startRow'
value = @bufferRowForScreenRow(value)
when 'endScreenRow'
key = 'endRow'
value = @bufferRowForScreenRow(value)
when 'intersectsBufferRowRange'
key = 'intersectsRowRange'
when 'intersectsScreenRowRange'
key = 'intersectsRowRange'
[startRow, endRow] = value
value = [@bufferRowForScreenRow(startRow), @bufferRowForScreenRow(endRow)]
when 'containsBufferRange'
key = 'containsRange'
when 'containsBufferPosition'
key = 'containsPosition'
when 'containedInBufferRange'
key = 'containedInRange'
when 'containedInScreenRange'
key = 'containedInRange'
value = @bufferRangeForScreenRange(value)
when 'intersectsBufferRange'
key = 'intersectsRange'
when 'intersectsScreenRange'
key = 'intersectsRange'
value = @bufferRangeForScreenRange(value)
bufferMarkerParams[key] = value
bufferMarkerParams
findFoldMarker: (attributes) ->
@@ -954,6 +984,7 @@ class DisplayBuffer extends Model
handleTokenizedBufferChange: (tokenizedBufferChange) =>
{start, end, delta, bufferChange} = tokenizedBufferChange
@updateScreenLines(start, end + 1, delta, delayChangeEvent: bufferChange?)
@setScrollTop(Math.min(@getScrollTop(), @getMaxScrollTop())) if @manageScrollPosition and delta < 0
updateScreenLines: (startBufferRow, endBufferRow, bufferDelta=0, options={}) ->
startBufferRow = @rowMap.bufferRowRangeForBufferRow(startBufferRow)[0]
@@ -1027,6 +1058,8 @@ class DisplayBuffer extends Model
{screenLines, regions}
findMaxLineLength: (startScreenRow, endScreenRow, newScreenLines) ->
oldMaxLineLength = @maxLineLength
if startScreenRow <= @longestScreenRow < endScreenRow
@longestScreenRow = 0
@maxLineLength = 0
@@ -1042,6 +1075,11 @@ class DisplayBuffer extends Model
@longestScreenRow = maxLengthCandidatesStartRow + screenRow
@maxLineLength = length
@computeScrollWidth() if oldMaxLineLength isnt @maxLineLength
computeScrollWidth: ->
@scrollWidth = @pixelPositionForScreenPosition([@longestScreenRow, @maxLineLength]).left + 1
handleBufferMarkersUpdated: =>
if event = @pendingChangeEvent
@pendingChangeEvent = null
@@ -1052,8 +1090,7 @@ class DisplayBuffer extends Model
@emit 'marker-created', @getMarker(marker.id)
createFoldForMarker: (marker) ->
bufferMarker = new DisplayBufferMarker({bufferMarker: marker, displayBuffer: this})
@addDecorationForMarker(bufferMarker, type: 'gutter', class: 'folded')
@addDecorationForMarker(marker, type: 'gutter', class: 'folded')
new Fold(this, marker)
foldForMarker: (marker) ->
+278 -122
Ver Arquivo
@@ -12,16 +12,22 @@ ScrollbarComponent = require './scrollbar-component'
ScrollbarCornerComponent = require './scrollbar-corner-component'
SubscriberMixin = require './subscriber-mixin'
DummyHighlightDecoration = {id: 'dummy', startPixelPosition: {top: 0, left: 0}, endPixelPosition: {top: 0, left: 0}, decorations: [{class: 'dummy'}]}
module.exports =
EditorComponent = React.createClass
displayName: 'EditorComponent'
mixins: [SubscriberMixin]
statics:
performSyncUpdates: false
pendingScrollTop: null
pendingScrollLeft: null
selectOnMouseMove: false
batchingUpdates: false
updateRequested: false
updatesPaused: false
updateRequestedWhilePaused: false
cursorsMoved: false
selectionChanged: false
selectionAdded: false
@@ -36,10 +42,14 @@ EditorComponent = React.createClass
scrollSensitivity: 0.4
scrollViewMeasurementRequested: false
measureLineHeightAndDefaultCharWidthWhenShown: false
remeasureCharacterWidthsWhenShown: false
inputEnabled: true
scrollViewMeasurementInterval: 100
scopedCharacterWidthsChangeCount: null
scrollViewMeasurementPaused: false
render: ->
{focused, fontSize, lineHeight, fontFamily, showIndentGuide, showInvisibles, visible} = @state
{focused, fontSize, lineHeight, fontFamily, showIndentGuide, showInvisibles, showLineNumbers, visible} = @state
{editor, cursorBlinkPeriod, cursorBlinkResumeDelay} = @props
maxLineNumberDigits = editor.getLineCount().toString().length
invisibles = if showInvisibles then @state.invisibles else {}
@@ -48,9 +58,12 @@ EditorComponent = React.createClass
if @isMounted()
renderedRowRange = @getRenderedRowRange()
[renderedStartRow, renderedEndRow] = renderedRowRange
cursorScreenRanges = @getCursorScreenRanges(renderedRowRange)
selectionScreenRanges = @getSelectionScreenRanges(renderedRowRange)
decorations = @getGutterDecorations(renderedRowRange)
cursorPixelRects = @getCursorPixelRects(renderedRowRange)
decorations = editor.decorationsForScreenRowRange(renderedStartRow, renderedEndRow)
highlightDecorations = @getHighlightDecorations(decorations)
lineDecorations = @getLineDecorations(decorations)
scrollHeight = editor.getScrollHeight()
scrollWidth = editor.getScrollWidth()
scrollTop = editor.getScrollTop()
@@ -58,12 +71,13 @@ EditorComponent = React.createClass
lineHeightInPixels = editor.getLineHeightInPixels()
defaultCharWidth = editor.getDefaultCharWidth()
scrollViewHeight = editor.getHeight()
lineWidth = Math.max(scrollWidth, editor.getWidth())
horizontalScrollbarHeight = editor.getHorizontalScrollbarHeight()
verticalScrollbarWidth = editor.getVerticalScrollbarWidth()
verticallyScrollable = editor.verticallyScrollable()
horizontallyScrollable = editor.horizontallyScrollable()
hiddenInputStyle = @getHiddenInputPosition()
hiddenInputStyle.WebkitTransform = 'translateZ(0)'
hiddenInputStyle.WebkitTransform = 'translateZ(0)' if @useHardwareAcceleration
if @mouseWheelScreenRow? and not (renderedStartRow <= @mouseWheelScreenRow < renderedEndRow)
mouseWheelScreenRow = @mouseWheelScreenRow
@@ -72,11 +86,12 @@ EditorComponent = React.createClass
className += ' has-selection' if hasSelection
div className: className, style: {fontSize, lineHeight, fontFamily}, tabIndex: -1,
GutterComponent {
ref: 'gutter', editor, renderedRowRange, maxLineNumberDigits, scrollTop,
scrollHeight, lineHeightInPixels, @pendingChanges, mouseWheelScreenRow,
decorations
}
if showLineNumbers
GutterComponent {
ref: 'gutter', onMouseDown: @onGutterMouseDown, onWidthChanged: @onGutterWidthChanged,
lineDecorations, defaultCharWidth, editor, renderedRowRange, maxLineNumberDigits, scrollViewHeight,
scrollTop, scrollHeight, lineHeightInPixels, @pendingChanges, mouseWheelScreenRow, @useHardwareAcceleration
}
div ref: 'scrollView', className: 'scroll-view', onMouseDown: @onMouseDown,
InputComponent
@@ -87,14 +102,15 @@ EditorComponent = React.createClass
onBlur: @onInputBlurred
CursorsComponent {
editor, scrollTop, scrollLeft, cursorScreenRanges, cursorBlinkPeriod, cursorBlinkResumeDelay,
lineHeightInPixels, defaultCharWidth
scrollTop, scrollLeft, cursorPixelRects, cursorBlinkPeriod, cursorBlinkResumeDelay,
lineHeightInPixels, defaultCharWidth, @scopedCharacterWidthsChangeCount, @useHardwareAcceleration
}
LinesComponent {
ref: 'lines', editor, lineHeightInPixels, defaultCharWidth,
showIndentGuide, renderedRowRange, @pendingChanges, scrollTop, scrollLeft, @scrollingVertically,
selectionScreenRanges, scrollHeight, scrollWidth, mouseWheelScreenRow, invisibles,
visible, scrollViewHeight
ref: 'lines',
editor, lineHeightInPixels, defaultCharWidth, lineDecorations, highlightDecorations,
showIndentGuide, renderedRowRange, @pendingChanges, scrollTop, scrollLeft,
@scrollingVertically, scrollHeight, scrollWidth, mouseWheelScreenRow, invisibles,
visible, scrollViewHeight, @scopedCharacterWidthsChangeCount, lineWidth, @useHardwareAcceleration
}
ScrollbarComponent
@@ -129,6 +145,10 @@ EditorComponent = React.createClass
height: horizontalScrollbarHeight
width: verticalScrollbarWidth
getPageRows: ->
{editor} = @props
Math.max(1, Math.ceil(editor.getHeight() / editor.getLineHeightInPixels()))
getInitialState: ->
visible: true
@@ -146,6 +166,8 @@ EditorComponent = React.createClass
componentDidMount: ->
{editor} = @props
@scrollViewMeasurementIntervalId = setInterval(@measureScrollView, @scrollViewMeasurementInterval)
@observeEditor()
@listenForDOMEvents()
@listenForCommands()
@@ -155,33 +177,55 @@ EditorComponent = React.createClass
editor.setVisible(true)
editor.batchUpdates =>
@measureLineHeightAndDefaultCharWidth()
@measureScrollView()
@measureScrollbars()
@measureLineHeightAndDefaultCharWidth()
@measureScrollView()
@measureScrollbars()
componentWillUnmount: ->
@unsubscribe()
window.removeEventListener('resize', @onWindowResize)
componentWillUpdate: ->
if @props.editor.isAlive()
@props.parentView.trigger 'cursor:moved' if @cursorsMoved
@props.parentView.trigger 'selection:changed' if @selectionChanged
clearInterval(@scrollViewMeasurementIntervalId)
@scrollViewMeasurementIntervalId = null
componentDidUpdate: (prevProps, prevState) ->
cursorsMoved = @cursorsMoved
selectionChanged = @selectionChanged
@pendingChanges.length = 0
@cursorsMoved = false
@selectionChanged = false
@refreshingScrollbars = false
@updateParentViewFocusedClassIfNeeded(prevState)
if @props.editor.isAlive()
@updateParentViewFocusedClassIfNeeded(prevState)
@props.parentView.trigger 'cursor:moved' if cursorsMoved
@props.parentView.trigger 'selection:changed' if selectionChanged
@props.parentView.trigger 'editor:display-updated'
@measureScrollbars() if @measuringScrollbars
@measureLineHeightAndCharWidthsIfNeeded(prevState)
@props.parentView.trigger 'editor:display-updated'
@remeasureCharacterWidthsIfNeeded(prevState)
requestUpdate: ->
if @batchingUpdates
@updateRequested = true
else
if @updatesPaused
@updateRequestedWhilePaused = true
return
if @performSyncUpdates ? EditorComponent.performSyncUpdates
@forceUpdate()
else unless @updateRequested
@updateRequested = true
setImmediate =>
@updateRequested = false
@forceUpdate() if @isMounted()
requestAnimationFrame: (fn) ->
@updatesPaused = true
@pauseScrollViewMeasurement()
requestAnimationFrame =>
fn()
@updatesPaused = false
if @updateRequestedWhilePaused and @isMounted()
@updateRequestedWhilePaused = false
@forceUpdate()
getRenderedRowRange: ->
{editor, lineOverdrawMargin} = @props
@@ -215,43 +259,78 @@ EditorComponent = React.createClass
cursorScreenRanges[cursor.id] = screenRange
cursorScreenRanges
getSelectionScreenRanges: (renderedRowRange) ->
getCursorPixelRects: (renderedRowRange) ->
{editor} = @props
[renderedStartRow, renderedEndRow] = renderedRowRange
selectionScreenRanges = {}
for selection, index in editor.getSelections()
screenRange = selection.getScreenRange()
cursorPixelRects = {}
for selection in editor.getSelections() when selection.isEmpty()
{cursor} = selection
screenRange = cursor.getScreenRange()
if renderedStartRow <= screenRange.start.row < renderedEndRow
cursorPixelRects[cursor.id] = editor.pixelRectForScreenRange(screenRange)
cursorPixelRects
if not screenRange.isEmpty() and screenRange.intersectsRowRange(renderedStartRow, renderedEndRow)
selectionScreenRanges[selection.id] = screenRange
else if index is 0 # Rendering artifacts occur on the lines GPU layer if we remove the last selection
selectionScreenRanges[selection.id] = new Range(new Point(renderedStartRow, 0), new Point(renderedStartRow, 0))
selectionScreenRanges
getGutterDecorations: (renderedRowRange) ->
getLineDecorations: (decorationsByMarkerId) ->
{editor} = @props
[renderedStartRow, renderedEndRow] = renderedRowRange
decorationsByScreenRow = {}
for markerId, decorations of decorationsByMarkerId
marker = editor.getMarker(markerId)
screenRange = null
headScreenRow = null
if marker.isValid()
for decoration in decorations
if editor.decorationMatchesType(decoration, 'gutter') or editor.decorationMatchesType(decoration, 'line')
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
if screenRange.isEmpty()
continue if decoration.onlyNonEmpty
else
continue if decoration.onlyEmpty
bufferRows = editor.bufferRowsForScreenRows(renderedStartRow, renderedEndRow - 1)
decorationsByScreenRow[screenRow] ?= []
decorationsByScreenRow[screenRow].push decoration
decorations = {}
for bufferRow in bufferRows
decorations[bufferRow] = editor.decorationsForBufferRow(bufferRow, 'gutter')
decorations[bufferRow].push {class: 'foldable'} if editor.isFoldableAtBufferRow(bufferRow)
decorations
decorationsByScreenRow
getHighlightDecorations: (decorationsByMarkerId) ->
{editor} = @props
filteredDecorations = {}
for markerId, decorations of decorationsByMarkerId
marker = editor.getMarker(markerId)
screenRange = marker.getScreenRange()
if marker.isValid() and not screenRange.isEmpty()
for decoration in decorations
if editor.decorationMatchesType(decoration, 'highlight')
filteredDecorations[markerId] ?=
id: markerId
startPixelPosition: editor.pixelPositionForScreenPosition(screenRange.start)
endPixelPosition: editor.pixelPositionForScreenPosition(screenRange.end)
decorations: []
filteredDecorations[markerId].decorations.push decoration
# At least in Chromium 31, removing the last highlight causes a rendering
# artifact where chunks of the lines disappear, so we always leave this
# dummy highlight in place to prevent that.
filteredDecorations['dummy'] = DummyHighlightDecoration
filteredDecorations
observeEditor: ->
{editor} = @props
@subscribe editor, 'batched-updates-started', @onBatchedUpdatesStarted
@subscribe editor, 'batched-updates-ended', @onBatchedUpdatesEnded
@subscribe editor, 'screen-lines-changed', @onScreenLinesChanged
@subscribe editor, 'cursors-moved', @onCursorsMoved
@subscribe editor, 'selection-removed selection-screen-range-changed', @onSelectionChanged
@subscribe editor, 'selection-added', @onSelectionAdded
@subscribe editor, 'decoration-added', @onDecorationChanged
@subscribe editor, 'decoration-removed', @onDecorationChanged
@subscribe editor, 'decoration-changed', @onDecorationChanged
@subscribe editor, 'character-widths-changed', @onCharacterWidthsChanged
@subscribe editor.$scrollTop.changes, @onScrollTopChanged
@subscribe editor.$scrollLeft.changes, @requestUpdate
@subscribe editor.$height.changes, @requestUpdate
@@ -266,9 +345,36 @@ EditorComponent = React.createClass
node.addEventListener 'textInput', @onTextInput
scrollViewNode = @refs.scrollView.getDOMNode()
scrollViewNode.addEventListener 'overflowchanged', @onScrollViewOverflowChanged
scrollViewNode.addEventListener 'scroll', @onScrollViewScroll
window.addEventListener('resize', @onWindowResize)
window.addEventListener 'resize', @requestScrollViewMeasurement
@listenForIMEEvents()
listenForIMEEvents: ->
node = @getDOMNode()
{editor} = @props
# The IME composition events work like this:
#
# User types 's', chromium pops up the completion helper
# 1. compositionstart fired
# 2. compositionupdate fired; event.data == 's'
# User hits arrow keys to move around in completion helper
# 3. compositionupdate fired; event.data == 's' for each arry key press
# User escape to cancel
# 4. compositionend fired
# OR User chooses a completion
# 4. compositionend fired
# 5. textInput fired; event.data == the completion string
selectedText = null
node.addEventListener 'compositionstart', ->
selectedText = editor.getSelectedText()
node.addEventListener 'compositionupdate', (event) ->
editor.insertText(event.data, select: true, undo: 'skip')
node.addEventListener 'compositionend', (event) ->
editor.insertText(selectedText, select: true, undo: 'skip')
event.target.value = ''
listenForCommands: ->
{parentView, editor, mini} = @props
@@ -291,6 +397,7 @@ EditorComponent = React.createClass
'editor:consolidate-selections': @consolidateSelections
'editor:delete-to-beginning-of-word': => editor.deleteToBeginningOfWord()
'editor:delete-to-beginning-of-line': => editor.deleteToBeginningOfLine()
'editor:delete-to-end-of-line': => editor.deleteToEndOfLine()
'editor:delete-to-end-of-word': => editor.deleteToEndOfWord()
'editor:delete-line': => editor.deleteLine()
'editor:cut-to-end-of-line': => editor.cutToEndOfLine()
@@ -327,10 +434,14 @@ EditorComponent = React.createClass
'core:move-down': => editor.moveCursorDown()
'core:move-to-top': => editor.moveCursorToTop()
'core:move-to-bottom': => editor.moveCursorToBottom()
'core:page-up': => editor.pageUp()
'core:page-down': => editor.pageDown()
'core:select-up': => editor.selectUp()
'core:select-down': => editor.selectDown()
'core:select-to-top': => editor.selectToTop()
'core:select-to-bottom': => editor.selectToBottom()
'core:select-page-up': => editor.selectPageUp()
'core:select-page-down': => editor.selectPageDown()
'editor:indent': => editor.indent()
'editor:auto-indent': => editor.autoIndentSelectedRows()
'editor:indent-selected-rows': => editor.indentSelectedRows()
@@ -368,8 +479,6 @@ EditorComponent = React.createClass
'editor:toggle-indent-guide': => atom.config.toggle('editor.showIndentGuide')
'editor:toggle-line-numbers': => atom.config.toggle('editor.showLineNumbers')
'editor:scroll-to-cursor': => editor.scrollToCursorPosition()
'core:page-up': => editor.pageUp()
'core:page-down': => editor.pageDown()
'benchmark:scroll': @runScrollBenchmark
addCommandListeners: (listenersByCommandName) ->
@@ -385,7 +494,9 @@ EditorComponent = React.createClass
@subscribe atom.config.observe 'editor.showIndentGuide', @setShowIndentGuide
@subscribe atom.config.observe 'editor.invisibles', @setInvisibles
@subscribe atom.config.observe 'editor.showInvisibles', @setShowInvisibles
@subscribe atom.config.observe 'editor.showLineNumbers', @setShowLineNumbers
@subscribe atom.config.observe 'editor.scrollSensitivity', @setScrollSensitivity
@subscribe atom.config.observe 'editor.useHardwareAcceleration', @setUseHardwareAcceleration
onFocus: ->
@refs.input.focus()
@@ -419,24 +530,25 @@ EditorComponent = React.createClass
onVerticalScroll: (scrollTop) ->
{editor} = @props
return if scrollTop is editor.getScrollTop()
return if @updateRequested or scrollTop is editor.getScrollTop()
animationFramePending = @pendingScrollTop?
@pendingScrollTop = scrollTop
unless animationFramePending
requestAnimationFrame =>
@props.editor.setScrollTop(@pendingScrollTop)
@requestAnimationFrame =>
pendingScrollTop = @pendingScrollTop
@pendingScrollTop = null
@props.editor.setScrollTop(pendingScrollTop)
onHorizontalScroll: (scrollLeft) ->
{editor} = @props
return if scrollLeft is editor.getScrollLeft()
return if @updateRequested or scrollLeft is editor.getScrollLeft()
animationFramePending = @pendingScrollLeft?
@pendingScrollLeft = scrollLeft
unless animationFramePending
requestAnimationFrame =>
@requestAnimationFrame =>
@props.editor.setScrollLeft(@pendingScrollLeft)
@pendingScrollLeft = null
@@ -457,35 +569,35 @@ EditorComponent = React.createClass
@clearMouseWheelScreenRowAfterDelay()
unless animationFramePending
requestAnimationFrame =>
@requestAnimationFrame =>
{editor} = @props
editor.setScrollTop(editor.getScrollTop() + @pendingVerticalScrollDelta)
editor.setScrollLeft(editor.getScrollLeft() + @pendingHorizontalScrollDelta)
@pendingVerticalScrollDelta = 0
@pendingHorizontalScrollDelta = 0
onScrollViewOverflowChanged: ->
@requestScrollViewMeasurement()
onWindowResize: ->
@requestScrollViewMeasurement()
onScrollViewScroll: ->
console.warn "EditorScrollView scroll position changed, and it shouldn't have. If you can reproduce this, please report it."
scrollViewNode = @refs.scrollView.getDOMNode()
scrollViewNode.scrollTop = 0
scrollViewNode.scrollLeft = 0
if @isMounted()
console.warn "EditorScrollView scrolled when it shouldn't have."
scrollViewNode = @refs.scrollView.getDOMNode()
scrollViewNode.scrollTop = 0
scrollViewNode.scrollLeft = 0
onMouseDown: (event) ->
return unless event.button is 0 # only handle the left mouse button
{editor} = @props
{detail, shiftKey, metaKey} = event
{detail, shiftKey, metaKey, ctrlKey} = event
screenPosition = @screenPositionForMouseEvent(event)
if event.target?.classList.contains('fold-marker')
bufferRow = editor.bufferRowForScreenRow(screenPosition.row)
editor.unfoldBufferRow(bufferRow)
return
if shiftKey
editor.selectToScreenPosition(screenPosition)
else if metaKey
else if metaKey or (ctrlKey and process.platform isnt 'darwin')
editor.addCursorAtScreenPosition(screenPosition)
else
editor.setCursorScreenPosition(screenPosition)
@@ -493,21 +605,50 @@ EditorComponent = React.createClass
when 2 then editor.selectWord()
when 3 then editor.selectLine()
@selectToMousePositionUntilMouseUp(event)
@handleDragUntilMouseUp event, (screenPosition) ->
editor.selectToScreenPosition(screenPosition)
onGutterMouseDown: (event) ->
return unless event.button is 0 # only handle the left mouse button
if event.shiftKey
@onGutterShiftClick(event)
else
@onGutterClick(event)
onGutterClick: (event) ->
{editor} = @props
clickedRow = @screenPositionForMouseEvent(event).row
editor.setCursorScreenPosition([clickedRow, 0])
@handleDragUntilMouseUp event, (screenPosition) ->
dragRow = screenPosition.row
if dragRow < clickedRow # dragging up
editor.setSelectedScreenRange([[dragRow, 0], [clickedRow + 1, 0]])
else
editor.setSelectedScreenRange([[clickedRow, 0], [dragRow + 1, 0]])
onGutterShiftClick: (event) ->
{editor} = @props
clickedRow = @screenPositionForMouseEvent(event).row
tailPosition = editor.getSelection().getTailScreenPosition()
if clickedRow < tailPosition.row
editor.selectToScreenPosition([clickedRow, 0])
else
editor.selectToScreenPosition([clickedRow + 1, 0])
@handleDragUntilMouseUp event, (screenPosition) ->
dragRow = screenPosition.row
if dragRow < tailPosition.row # dragging up
editor.setSelectedScreenRange([[dragRow, 0], tailPosition])
else
editor.setSelectedScreenRange([tailPosition, [dragRow + 1, 0]])
onStylesheetsChanged: (stylesheet) ->
@refreshScrollbars() if @containsScrollbarSelector(stylesheet)
onBatchedUpdatesStarted: ->
@batchingUpdates = true
onBatchedUpdatesEnded: ->
updateRequested = @updateRequested
@updateRequested = false
@batchingUpdates = false
if updateRequested
@requestUpdate()
onScreenLinesChanged: (change) ->
{editor} = @props
@pendingChanges.push(change)
@@ -529,7 +670,7 @@ EditorComponent = React.createClass
onScrollTopChanged: ->
@scrollingVertically = true
@requestUpdate()
@onStoppedScrollingAfterDelay ?= debounce(@onStoppedScrolling, 100)
@onStoppedScrollingAfterDelay ?= debounce(@onStoppedScrolling, 200)
@onStoppedScrollingAfterDelay()
onStoppedScrolling: ->
@@ -546,19 +687,20 @@ EditorComponent = React.createClass
@requestUpdate()
onDecorationChanged: ->
@decorationChangedImmediate ?= setImmediate =>
@requestUpdate() if @isMounted()
@decorationChangedImmediate = null
@requestUpdate()
selectToMousePositionUntilMouseUp: (event) ->
onCharacterWidthsChanged: (@scopedCharacterWidthsChangeCount) ->
@requestUpdate()
handleDragUntilMouseUp: (event, dragHandler) ->
{editor} = @props
dragging = false
lastMousePosition = {}
animationLoop = =>
requestAnimationFrame =>
@requestAnimationFrame =>
if dragging
@selectToMousePosition(lastMousePosition)
screenPosition = @screenPositionForMouseEvent(lastMousePosition)
dragHandler(screenPosition)
animationLoop()
onMouseMove = (event) ->
@@ -582,11 +724,18 @@ EditorComponent = React.createClass
window.addEventListener('mousemove', onMouseMove)
window.addEventListener('mouseup', onMouseUp)
selectToMousePosition: (event) ->
@props.editor.selectToScreenPosition(@screenPositionForMouseEvent(event))
pauseScrollViewMeasurement: ->
@scrollViewMeasurementPaused = true
@resumeScrollViewMeasurementAfterDelay ?= debounce(@resumeScrollViewMeasurement, 100)
@resumeScrollViewMeasurementAfterDelay()
resumeScrollViewMeasurement: ->
@scrollViewMeasurementPaused = false
resumeScrollViewMeasurementAfterDelay: null # created lazily
requestScrollViewMeasurement: ->
return if @measurementPending
return if @scrollViewMeasurementRequested
@scrollViewMeasurementRequested = true
requestAnimationFrame =>
@@ -598,6 +747,7 @@ EditorComponent = React.createClass
# and use the scrollHeight / scrollWidth as its height and width in
# calculations.
measureScrollView: ->
return if @scrollViewMeasurementPaused
return unless @isMounted()
{editor} = @props
@@ -616,20 +766,10 @@ EditorComponent = React.createClass
measureLineHeightAndCharWidthsIfNeeded: (prevState) ->
if not isEqualForProperties(prevState, @state, 'lineHeight', 'fontSize', 'fontFamily')
{editor} = @props
editor.batchUpdates =>
oldDefaultCharWidth = editor.getDefaultCharWidth()
if @state.visible
@measureLineHeightAndDefaultCharWidth()
else
@measureLineHeightAndDefaultCharWidthWhenShown = true
unless oldDefaultCharWidth is editor.getDefaultCharWidth()
@remeasureCharacterWidths()
@measureGutter()
if @state.visible
@measureLineHeightAndDefaultCharWidth()
else
@measureLineHeightAndDefaultCharWidthWhenShown = true
else if @measureLineHeightAndDefaultCharWidthWhenShown and @state.visible and not prevState.visible
@measureLineHeightAndDefaultCharWidth()
@@ -637,13 +777,21 @@ EditorComponent = React.createClass
@measureLineHeightAndDefaultCharWidthWhenShown = false
@refs.lines.measureLineHeightAndDefaultCharWidth()
remeasureCharacterWidthsIfNeeded: (prevState) ->
if not isEqualForProperties(prevState, @state, 'fontSize', 'fontFamily')
if @state.visible
@remeasureCharacterWidths()
else
@remeasureCharacterWidthsWhenShown = true
else if @remeasureCharacterWidthsWhenShown and @state.visible and not prevState.visible
@remeasureCharacterWidths()
remeasureCharacterWidths: ->
@remeasureCharacterWidthsWhenShown = false
@refs.lines.remeasureCharacterWidths()
measureGutter: ->
oldGutterWidth = @gutterWidth
@gutterWidth = @refs.gutter.getDOMNode().offsetWidth
@requestUpdate() if @gutterWidth isnt oldGutterWidth
onGutterWidthChanged: (@gutterWidth) ->
@requestUpdate()
measureScrollbars: ->
@measuringScrollbars = false
@@ -669,17 +817,17 @@ EditorComponent = React.createClass
# visible, so first we need to hide scrollbars so we can redisplay them and
# force Chromium to apply updates.
@refreshingScrollbars = true
@requestUpdate()
@forceUpdate()
# Next, we display only the scrollbar corner so we can measure the new
# scrollbar dimensions. The ::measuringScrollbars property will be set back
# to false after the scrollbars are measured.
@measuringScrollbars = true
@requestUpdate()
@forceUpdate()
# Finally, we restore the scrollbars based on the newly-measured dimensions
# if the editor's content and dimensions require them to be visible.
@requestUpdate()
@forceUpdate()
clearMouseWheelScreenRow: ->
if @mouseWheelScreenRow?
@@ -745,10 +893,18 @@ EditorComponent = React.createClass
setShowInvisibles: (showInvisibles) ->
@setState({showInvisibles})
setShowLineNumbers: (showLineNumbers) ->
@setState({showLineNumbers})
setScrollSensitivity: (scrollSensitivity) ->
if scrollSensitivity = parseInt(scrollSensitivity)
@scrollSensitivity = Math.abs(scrollSensitivity) / 100
setUseHardwareAcceleration: (useHardwareAcceleration=true) ->
unless @useHardwareAcceleration is useHardwareAcceleration
@useHardwareAcceleration = useHardwareAcceleration
@requestUpdate()
screenPositionForMouseEvent: (event) ->
pixelPosition = @pixelPositionForMouseEvent(event)
@props.editor.screenPositionForPixelPosition(pixelPosition)
@@ -757,9 +913,9 @@ EditorComponent = React.createClass
{editor} = @props
{clientX, clientY} = event
scrollViewClientRect = @refs.scrollView.getDOMNode().getBoundingClientRect()
top = clientY - scrollViewClientRect.top + editor.getScrollTop()
left = clientX - scrollViewClientRect.left + editor.getScrollLeft()
linesClientRect = @refs.lines.getDOMNode().getBoundingClientRect()
top = clientY - linesClientRect.top
left = clientX - linesClientRect.left
{top, left}
getModel: ->
+5 -1
Ver Arquivo
@@ -57,6 +57,7 @@ class EditorView extends View
softTabs: true
softWrapAtPreferredLineLength: false
scrollSensitivity: 40
useHardwareAcceleration: true
@nextEditorId: 1
@@ -157,6 +158,7 @@ class EditorView extends View
'editor:consolidate-selections': (event) => @consolidateSelections(event)
'editor:delete-to-beginning-of-word': => @editor.deleteToBeginningOfWord()
'editor:delete-to-beginning-of-line': => @editor.deleteToBeginningOfLine()
'editor:delete-to-end-of-line': => @editor.deleteToEndOfLine()
'editor:delete-to-end-of-word': => @editor.deleteToEndOfWord()
'editor:delete-line': => @editor.deleteLine()
'editor:cut-to-end-of-line': => @editor.cutToEndOfLine()
@@ -193,12 +195,14 @@ class EditorView extends View
'core:move-down': => @editor.moveCursorDown()
'core:move-to-top': => @editor.moveCursorToTop()
'core:move-to-bottom': => @editor.moveCursorToBottom()
'core:page-down': => @pageDown()
'core:page-up': => @pageUp()
'core:page-down': => @pageDown()
'core:select-up': => @editor.selectUp()
'core:select-down': => @editor.selectDown()
'core:select-to-top': => @editor.selectToTop()
'core:select-to-bottom': => @editor.selectToBottom()
'core:select-page-up': => @editor.selectUp(@getPageRows())
'core:select-page-down': => @editor.selectDown(@getPageRows())
'editor:indent': => @editor.indent()
'editor:auto-indent': => @editor.autoIndentSelectedRows()
'editor:indent-selected-rows': => @editor.indentSelectedRows()
+80 -91
Ver Arquivo
@@ -112,6 +112,7 @@ TextMateScopeSelector = require('first-mate').ScopeSelector
# - {::deleteToBeginningOfWord}
# - {::deleteToBeginningOfLine}
# - {::delete}
# - {::deleteToEndOfLine}
# - {::deleteToEndOfWord}
# - {::deleteLine}
# - {::cutSelectedText}
@@ -214,7 +215,10 @@ class Editor extends Model
@subscribe @displayBuffer, 'grammar-changed', => @handleGrammarChange()
@subscribe @displayBuffer, 'tokenized', => @handleTokenization()
@subscribe @displayBuffer, 'soft-wrap-changed', (args...) => @emit 'soft-wrap-changed', args...
@subscribe @displayBuffer, "decoration-changed", (e) => @emit 'decoration-changed', e
@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, "character-widths-changed", (changeCount) => @emit 'character-widths-changed', changeCount
getViewClass: ->
if atom.config.get('core.useReactEditor')
@@ -689,6 +693,13 @@ class Editor extends Model
delete: ->
@mutateSelectedText (selection) -> selection.delete()
# Public: For each selection, if the selection is not empty, deletes the
# selection; otherwise, deletes all characters of the containing line
# following the cursor. If the cursor is already at the end of the line,
# deletes the following newline.
deleteToEndOfLine: ->
@mutateSelectedText (selection) -> selection.deleteToEndOfLine()
# Public: For each selection, if the selection is empty, delete all characters
# of the containing word following the cursor. Otherwise delete the selected
# text.
@@ -843,6 +854,10 @@ class Editor extends Model
isFoldableAtBufferRow: (bufferRow) ->
@languageMode.isFoldableAtBufferRow(bufferRow)
isFoldableAtScreenRow: (screenRow) ->
bufferRow = @displayBuffer.bufferRowForScreenRow(screenRow)
@isFoldableAtBufferRow(bufferRow)
# TODO: Rename to foldRowRange?
createFold: (startRow, endRow) ->
@displayBuffer.createFold(startRow, endRow)
@@ -1058,41 +1073,50 @@ class Editor extends Model
selection.insertText(fn(text))
selection.setBufferRange(range)
# Public: Get all the decorations for a buffer row.
# Public: Get all the decorations within a screen row range.
#
# bufferRow - the {int} buffer row
# decorationType - the {String} decoration type to filter by eg. 'gutter'
# startScreenRow - the {Number} beginning screen row
# endScreenRow - the {Number} end screen row (inclusive)
#
# Returns an {Array} of decorations in the form `[{type: 'gutter', class: 'someclass'}, ...]`
# Returns an empty array when no decorations are found
decorationsForBufferRow: (bufferRow, decorationType) ->
@displayBuffer.decorationsForBufferRow(bufferRow, decorationType)
# 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 empty object when no decorations are found
decorationsForScreenRowRange: (startScreenRow, endScreenRow) ->
@displayBuffer.decorationsForScreenRowRange(startScreenRow, endScreenRow)
# Public: Get all the decorations for a range of buffer rows (inclusive)
# Public: Adds a decoration that tracks a {Marker}. When the marker moves,
# is invalidated, or is destroyed, the decoration will be updated to reflect
# the marker's state.
#
# startBufferRow - the {int} start of the buffer row range
# endBufferRow - the {int} end of the buffer row range (inclusive)
# decorationType - the {String} decoration type to filter by eg. 'gutter'
#
# Returns an {Object} of decorations in the form `{23: [{type: 'gutter', class: 'someclass'}, ...], 24: [...]}`
# Returns an {Object} with keyed with all buffer rows in the range containing empty {Array}s when no decorations are found
decorationsForBufferRowRange: (startBufferRow, endBufferRow, decorationType) ->
@displayBuffer.decorationsForBufferRowRange(startBufferRow, endBufferRow, decorationType)
# 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)
# Public: Adds a decoration to a buffer row. For example, use to mark a gutter
# line number with a class by using the form `{type: 'gutter', class: 'linter-error'}`
#
# bufferRow - the {int} buffer row
# decoration - the {Object} decoration type to filter by eg. `{type: 'gutter', class: 'linter-error'}`
#
# Returns nothing
addDecorationToBufferRow: (bufferRow, decoration) ->
@displayBuffer.addDecorationToBufferRow(bufferRow, decoration)
# Public: Removes a decoration from a buffer row.
# Public: Removes all decorations associated with a {Marker} that match a
# `decorationPattern` and stop tracking the {Marker}.
#
# ```coffee
# editor.removeDecorationFromBufferRow(2, {type: 'gutter', class: 'linter-error'})
# 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
@@ -1108,49 +1132,9 @@ class Editor extends Model
# You can remove both with:
#
# ```coffee
# editor.removeDecorationFromBufferRow(2, {namespace: 'myns'})
# editor.removeDecorationForMarker(marker, {namespace: 'myns'})
# ```
#
# bufferRow - the {int} buffer row
# decorationPattern - the {Object} decoration type to filter by eg. `{type: 'gutter', class: 'linter-error'}`
#
# Returns an {Array} of the removed decorations
removeDecorationFromBufferRow: (bufferRow, decorationPattern) ->
@displayBuffer.removeDecorationFromBufferRow(bufferRow, decorationPattern)
# Public: Adds a decoration to line numbers in a buffer row range
#
# startBufferRow - the {int} start of the buffer row range
# endBufferRow - the {int} end of the buffer row range (inclusive)
# decoration - the {Object} decoration type to filter by eg. `{type: 'gutter', class: 'linter-error'}`
#
# Returns nothing
addDecorationToBufferRowRange: (startBufferRow, endBufferRow, decoration) ->
@displayBuffer.addDecorationToBufferRowRange(startBufferRow, endBufferRow, decoration)
# Public: Removes a decoration from line numbers in a buffer row range
#
# startBufferRow - the {int} start of the buffer row range
# endBufferRow - the {int} end of the buffer row range (inclusive)
# decoration - the {Object} decoration type to filter by eg. `{type: 'gutter', class: 'linter-error'}`
#
# Returns nothing
removeDecorationFromBufferRowRange: (startBufferRow, endBufferRow, decoration) ->
@displayBuffer.removeDecorationFromBufferRowRange(startBufferRow, endBufferRow, decoration)
# Public: Adds a decoration that tracks a {Marker}. When the marker moves,
# is invalidated, or is destroyed, the decoration will be updated to reflect the marker's state.
#
# marker - the {Marker} you want this decoration to follow
# decoration - the {Object} decoration type to filter by eg. `{type: 'gutter', class: 'linter-error'}`
#
# Returns nothing
addDecorationForMarker: (marker, decoration) ->
@displayBuffer.addDecorationForMarker(marker, decoration)
# Public: Removes all decorations associated with a {Marker} that match a
# `decorationPattern` and stop tracking the {Marker}.
#
# marker - the {Marker} to detach from
# decorationPattern - the {Object} decoration type to filter by eg. `{type: 'gutter', class: 'linter-error'}`
#
@@ -1158,6 +1142,9 @@ class Editor extends Model
removeDecorationForMarker: (marker, decorationPattern) ->
@displayBuffer.removeDecorationForMarker(marker, decorationPattern)
decorationMatchesType: (decoration, type) ->
@displayBuffer.decorationMatchesType(decoration, type)
# Public: Get the {DisplayBufferMarker} for the given marker id.
getMarker: (id) ->
@displayBuffer.getMarker(id)
@@ -1263,7 +1250,9 @@ class Editor extends Model
addCursor: (marker) ->
cursor = new Cursor(editor: this, marker: marker)
@cursors.push(cursor)
@addDecorationForMarker(marker, {class: 'cursor-line'})
@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)
@emit 'cursor-added', cursor
cursor
@@ -1290,6 +1279,7 @@ class Editor extends Model
if selection.intersectsBufferRange(selectionBufferRange)
return selection
else
@addDecorationForMarker(marker, type: 'highlight', class: 'selection')
@emit 'selection-added', selection
selection
@@ -1303,7 +1293,9 @@ class Editor extends Model
# Returns the added {Selection}.
addSelectionForBufferRange: (bufferRange, options={}) ->
@markBufferRange(bufferRange, _.defaults(@getSelectionMarkerAttributes(), options))
@getLastSelection()
selection = @getLastSelection()
selection.autoscroll()
selection
# Public: Set the selected range in buffer coordinates. If there are multiple
# selections, they are reduced to a single selection with the given range.
@@ -1614,17 +1606,22 @@ class Editor extends Model
@moveCursorDown(@getRowsPerPage())
@setScrollTop(newScrollTop)
selectPageUp: ->
@selectUp(@getRowsPerPage())
selectPageDown: ->
@selectDown(@getRowsPerPage())
# Returns the number of rows per page
getRowsPerPage: ->
Math.max(1, Math.ceil(@getHeight() / @getLineHeightInPixels()))
moveCursors: (fn) ->
@movingCursors = true
@batchUpdates =>
fn(cursor) for cursor in @getCursors()
@mergeCursors()
@movingCursors = false
@emit 'cursors-moved'
fn(cursor) for cursor in @getCursors()
@mergeCursors()
@movingCursors = false
@emit 'cursors-moved'
cursorMoved: (event) ->
@emit 'cursor-moved', event
@@ -1944,9 +1941,7 @@ class Editor extends Model
# execution and revert any changes performed up to the abortion.
#
# fn - A {Function} to call inside the transaction.
transact: (fn) ->
@batchUpdates =>
@buffer.transact(fn)
transact: (fn) -> @buffer.transact(fn)
# Public: Start an open-ended transaction.
#
@@ -1966,14 +1961,6 @@ class Editor extends Model
# within the transaction.
abortTransaction: -> @buffer.abortTransaction()
batchUpdates: (fn) ->
@emit 'batched-updates-started' if @updateBatchDepth is 0
@updateBatchDepth++
result = fn()
@updateBatchDepth--
@emit 'batched-updates-ended' if @updateBatchDepth is 0
result
inspect: ->
"<Editor #{@id}>"
@@ -2002,6 +1989,8 @@ class Editor extends Model
getLineHeightInPixels: -> @displayBuffer.getLineHeightInPixels()
setLineHeightInPixels: (lineHeightInPixels) -> @displayBuffer.setLineHeightInPixels(lineHeightInPixels)
batchCharacterMeasurement: (fn) -> @displayBuffer.batchCharacterMeasurement(fn)
getScopedCharWidth: (scopeNames, char) -> @displayBuffer.getScopedCharWidth(scopeNames, char)
setScopedCharWidth: (scopeNames, char, width) -> @displayBuffer.setScopedCharWidth(scopeNames, char, width)
@@ -2049,11 +2038,11 @@ class Editor extends Model
pixelRectForScreenRange: (screenRange) -> @displayBuffer.pixelRectForScreenRange(screenRange)
scrollToScreenRange: (screenRange) -> @displayBuffer.scrollToScreenRange(screenRange)
scrollToScreenRange: (screenRange, options) -> @displayBuffer.scrollToScreenRange(screenRange, options)
scrollToScreenPosition: (screenPosition) -> @displayBuffer.scrollToScreenPosition(screenPosition)
scrollToScreenPosition: (screenPosition, options) -> @displayBuffer.scrollToScreenPosition(screenPosition, options)
scrollToBufferPosition: (bufferPosition) -> @displayBuffer.scrollToBufferPosition(bufferPosition)
scrollToBufferPosition: (bufferPosition, options) -> @displayBuffer.scrollToBufferPosition(bufferPosition, options)
horizontallyScrollable: -> @displayBuffer.horizontallyScrollable()
+5
Ver Arquivo
@@ -35,6 +35,11 @@ class Fold
# Returns a {Range}.
getBufferRange: ({includeNewline}={}) ->
range = @marker.getRange()
if range.end.row > range.start.row and nextFold = @displayBuffer.largestFoldStartingAtBufferRow(range.end.row)
nextRange = nextFold.getBufferRange()
range = new Range(range.start, nextRange.end)
if includeNewline
range = range.copy()
range.end.row++
+54 -29
Ver Arquivo
@@ -12,20 +12,31 @@ GutterComponent = React.createClass
mixins: [SubscriberMixin]
dummyLineNumberNode: null
measuredWidth: null
render: ->
{scrollHeight, scrollTop} = @props
{scrollHeight, scrollViewHeight, onMouseDown} = @props
div className: 'gutter', onClick: @onClick,
div className: 'line-numbers editor-colors', ref: 'lineNumbers', style:
height: scrollHeight
WebkitTransform: "translate3d(0px, #{-scrollTop}px, 0px)"
div className: 'gutter', onClick: @onClick, onMouseDown: onMouseDown,
# The line-numbers div must have the 'editor-colors' class so it has an
# opaque background to avoid sub-pixel anti-aliasing problems on the GPU
div className: 'gutter line-numbers editor-colors', ref: 'lineNumbers', style:
height: Math.max(scrollHeight, scrollViewHeight)
WebkitTransform: @getTransform()
getTransform: ->
{scrollTop, useHardwareAcceleration} = @props
if useHardwareAcceleration
"translate3d(0px, #{-scrollTop}px, 0px)"
else
"translate(0px, #{-scrollTop}px)"
componentWillMount: ->
@lineNumberNodesById = {}
@lineNumberIdsByScreenRow = {}
@screenRowsByLineNumberId = {}
@previousDecorations = {}
@renderedDecorationsByLineNumberId = {}
componentDidMount: ->
@appendDummyLineNumber()
@@ -35,22 +46,24 @@ GutterComponent = React.createClass
# visible row range.
shouldComponentUpdate: (newProps) ->
return true unless isEqualForProperties(newProps, @props,
'renderedRowRange', 'scrollTop', 'lineHeightInPixels', 'mouseWheelScreenRow'
'renderedRowRange', 'scrollTop', 'lineHeightInPixels', 'mouseWheelScreenRow', 'lineDecorations',
'scrollViewHeight', 'useHardwareAcceleration'
)
{renderedRowRange, pendingChanges, decorations} = newProps
{renderedRowRange, pendingChanges, lineDecorations} = newProps
for change in pendingChanges when Math.abs(change.screenDelta) > 0 or Math.abs(change.bufferDelta) > 0
return true unless change.end <= renderedRowRange.start or renderedRowRange.end <= change.start
return true unless _.isEqual(@previousDecorations, decorations)
false
componentDidUpdate: (oldProps) ->
unless oldProps.maxLineNumberDigits is @props.maxLineNumberDigits
unless isEqualForProperties(oldProps, @props, 'maxLineNumberDigits')
@updateDummyLineNumber()
@removeLineNumberNodes()
unless isEqualForProperties(oldProps, @props, 'maxLineNumberDigits', 'defaultCharWidth')
@measureWidth()
@clearScreenRowCaches() unless oldProps.lineHeightInPixels is @props.lineHeightInPixels
@updateLineNumbers()
@@ -74,7 +87,7 @@ GutterComponent = React.createClass
@removeLineNumberNodes(lineNumberIdsToPreserve)
appendOrUpdateVisibleLineNumberNodes: ->
{editor, renderedRowRange, scrollTop, maxLineNumberDigits, decorations} = @props
{editor, renderedRowRange, scrollTop, maxLineNumberDigits, lineDecorations} = @props
[startRow, endRow] = renderedRowRange
newLineNumberIds = null
@@ -95,15 +108,17 @@ GutterComponent = React.createClass
visibleLineNumberIds.add(id)
if @hasLineNumberNode(id)
@updateLineNumberNode(id, bufferRow, screenRow, wrapCount > 0, decorations[bufferRow])
@updateLineNumberNode(id, bufferRow, screenRow, wrapCount > 0)
else
newLineNumberIds ?= []
newLineNumbersHTML ?= ""
newLineNumberIds.push(id)
newLineNumbersHTML += @buildLineNumberHTML(bufferRow, wrapCount > 0, maxLineNumberDigits, screenRow, decorations[bufferRow])
newLineNumbersHTML += @buildLineNumberHTML(bufferRow, wrapCount > 0, maxLineNumberDigits, screenRow)
@screenRowsByLineNumberId[id] = screenRow
@lineNumberIdsByScreenRow[screenRow] = id
@renderedDecorationsByLineNumberId[id] = lineDecorations[screenRow]
if newLineNumberIds?
WrapperDiv.innerHTML = newLineNumbersHTML
newLineNumberNodes = toArray(WrapperDiv.children)
@@ -114,7 +129,6 @@ GutterComponent = React.createClass
@lineNumberNodesById[lineNumberId] = lineNumberNode
node.appendChild(lineNumberNode)
@previousDecorations = decorations
visibleLineNumberIds
removeLineNumberNodes: (lineNumberIdsToPreserve) ->
@@ -126,20 +140,24 @@ GutterComponent = React.createClass
delete @lineNumberNodesById[lineNumberId]
delete @lineNumberIdsByScreenRow[screenRow] if @lineNumberIdsByScreenRow[screenRow] is lineNumberId
delete @screenRowsByLineNumberId[lineNumberId]
delete @renderedDecorationsByLineNumberId[lineNumberId]
node.removeChild(lineNumberNode)
buildLineNumberHTML: (bufferRow, softWrapped, maxLineNumberDigits, screenRow, decorations) ->
buildLineNumberHTML: (bufferRow, softWrapped, maxLineNumberDigits, screenRow) ->
{editor, lineHeightInPixels, lineDecorations} = @props
if screenRow?
{lineHeightInPixels} = @props
style = "position: absolute; top: #{screenRow * lineHeightInPixels}px;"
else
style = "visibility: hidden;"
innerHTML = @buildLineNumberInnerHTML(bufferRow, softWrapped, maxLineNumberDigits)
classes = ''
if decorations?
if lineDecorations? and decorations = lineDecorations[screenRow]
for decoration in decorations
classes += decoration.class + ' ' if not softWrapped or softWrapped and decoration.softWrap
if editor.decorationMatchesType(decoration, 'gutter')
classes += decoration.class + ' '
classes += "foldable " if bufferRow >= 0 and editor.isFoldableAtBufferRow(bufferRow)
classes += "line-number line-number-#{bufferRow}"
"<div class=\"#{classes}\" style=\"#{style}\" data-buffer-row=\"#{bufferRow}\" data-screen-row=\"#{screenRow}\">#{innerHTML}</div>"
@@ -154,17 +172,25 @@ GutterComponent = React.createClass
iconHTML = '<div class="icon-right"></div>'
padding + lineNumber + iconHTML
updateLineNumberNode: (lineNumberId, bufferRow, screenRow, softWrapped, decorations) ->
updateLineNumberNode: (lineNumberId, bufferRow, screenRow, softWrapped) ->
{editor, lineDecorations} = @props
node = @lineNumberNodesById[lineNumberId]
previousDecorations = @previousDecorations[bufferRow]
if editor.isFoldableAtBufferRow(bufferRow)
node.classList.add('foldable')
else
node.classList.remove('foldable')
decorations = lineDecorations[screenRow]
previousDecorations = @renderedDecorationsByLineNumberId[lineNumberId]
if previousDecorations?
for decoration in previousDecorations
node.classList.remove(decoration.class) if not contains(decorations, decoration)
node.classList.remove(decoration.class) if editor.decorationMatchesType(decoration, 'gutter') and not _.deepContains(decorations, decoration)
if decorations?
for decoration in decorations
if not contains(previousDecorations, decoration) and (not softWrapped or softWrapped and decoration.softWrap)
if editor.decorationMatchesType(decoration, 'gutter') and not _.deepContains(previousDecorations, decoration)
node.classList.add(decoration.class)
unless @screenRowsByLineNumberId[lineNumberId] is screenRow
@@ -192,9 +218,8 @@ GutterComponent = React.createClass
else
editor.foldBufferRow(bufferRow)
# Created because underscore uses === not _.isEqual, which we need
contains = (array, target) ->
return false unless array?
for object in array
return true if _.isEqual(object, target)
false
measureWidth: ->
width = @getDOMNode().offsetWidth
unless width is @measuredWidth
@measuredWidth = width
@props.onWidthChanged?(width)
@@ -1,25 +1,24 @@
React = require 'react-atom-fork'
{div} = require 'reactionary-atom-fork'
{isEqualForProperties} = require 'underscore-plus'
module.exports =
SelectionComponent = React.createClass
displayName: 'SelectionComponent'
HighlightComponent = React.createClass
displayName: 'HighlightComponent'
render: ->
{editor, screenRange, lineHeightInPixels} = @props
{start, end} = screenRange
rowCount = end.row - start.row + 1
startPixelPosition = editor.pixelPositionForScreenPosition(start)
endPixelPosition = editor.pixelPositionForScreenPosition(end)
{startPixelPosition, endPixelPosition, decoration} = @props
div className: 'selection',
if rowCount is 1
@renderSingleLineRegions(startPixelPosition, endPixelPosition)
className = 'highlight'
className += " #{decoration.class}" if decoration.class?
div {className},
if endPixelPosition.top is startPixelPosition.top
@renderSingleLineRegions()
else
@renderMultiLineRegions(startPixelPosition, endPixelPosition, rowCount)
@renderMultiLineRegions()
renderSingleLineRegions: (startPixelPosition, endPixelPosition) ->
{lineHeightInPixels} = @props
renderSingleLineRegions: ->
{startPixelPosition, endPixelPosition, lineHeightInPixels} = @props
[
div className: 'region', key: 0, style:
@@ -29,8 +28,8 @@ SelectionComponent = React.createClass
width: endPixelPosition.left - startPixelPosition.left
]
renderMultiLineRegions: (startPixelPosition, endPixelPosition, rowCount) ->
{lineHeightInPixels} = @props
renderMultiLineRegions: ->
{startPixelPosition, endPixelPosition, lineHeightInPixels} = @props
regions = []
index = 0
@@ -44,11 +43,11 @@ SelectionComponent = React.createClass
)
# Middle rows, extending from left side to right side of screen
if rowCount > 2
if endPixelPosition.top - startPixelPosition.top > lineHeightInPixels
regions.push(
div className: 'region', key: index++, style:
top: startPixelPosition.top + lineHeightInPixels
height: (rowCount - 2) * lineHeightInPixels
height: endPixelPosition.top - startPixelPosition.top - lineHeightInPixels
left: 0
right: 0
)
@@ -63,3 +62,6 @@ SelectionComponent = React.createClass
)
regions
shouldComponentUpdate: (newProps) ->
not isEqualForProperties(newProps, @props, 'startPixelPosition', 'endPixelPosition', 'lineHeightInPixels')
+25
Ver Arquivo
@@ -0,0 +1,25 @@
React = require 'react-atom-fork'
{div} = require 'reactionary-atom-fork'
{isEqualForProperties} = require 'underscore-plus'
HighlightComponent = require './highlight-component'
module.exports =
HighlightsComponent = React.createClass
displayName: 'HighlightsComponent'
render: ->
div className: 'highlights',
@renderHighlights() if @isMounted()
renderHighlights: ->
{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
shouldComponentUpdate: (newProps) ->
not isEqualForProperties(newProps, @props, 'highlightDecorations', 'lineHeightInPixels', 'defaultCharWidth', 'scopedCharacterWidthsChangeCount')
+67 -24
Ver Arquivo
@@ -1,9 +1,10 @@
_ = require 'underscore-plus'
React = require 'react-atom-fork'
{div, span} = require 'reactionary-atom-fork'
{debounce, isEqual, isEqualForProperties, multiplyString, toArray} = require 'underscore-plus'
{$$} = require 'space-pen'
SelectionsComponent = require './selections-component'
HighlightsComponent = require './highlights-component'
DummyLineNode = $$(-> @div className: 'line', style: 'position: absolute; visibility: hidden;', => @span 'x')[0]
AcceptFilter = {acceptNode: -> NodeFilter.FILTER_ACCEPT}
@@ -15,26 +16,38 @@ LinesComponent = React.createClass
render: ->
if @isMounted()
{editor, selectionScreenRanges, scrollTop, scrollLeft, scrollHeight, scrollWidth, lineHeightInPixels, defaultCharWidth, scrollViewHeight} = @props
{editor, highlightDecorations, scrollHeight, scrollWidth} = @props
{lineHeightInPixels, defaultCharWidth, scrollViewHeight, scopedCharacterWidthsChangeCount} = @props
style =
height: Math.max(scrollHeight, scrollViewHeight)
width: scrollWidth
WebkitTransform: "translate3d(#{-scrollLeft}px, #{-scrollTop}px, 0px)"
WebkitTransform: @getTransform()
# The lines div must have the 'editor-colors' class so it has an opaque
# background to avoid sub-pixel anti-aliasing problems on the GPU
div {className: 'lines editor-colors', style},
SelectionsComponent({editor, selectionScreenRanges, lineHeightInPixels, defaultCharWidth}) if @isMounted()
HighlightsComponent({editor, highlightDecorations, lineHeightInPixels, defaultCharWidth, scopedCharacterWidthsChangeCount})
getTransform: ->
{scrollTop, scrollLeft, useHardwareAcceleration} = @props
if useHardwareAcceleration
"translate3d(#{-scrollLeft}px, #{-scrollTop}px, 0px)"
else
"translate(#{-scrollLeft}px, #{-scrollTop}px)"
componentWillMount: ->
@measuredLines = new WeakSet
@lineNodesByLineId = {}
@screenRowsByLineId = {}
@lineIdsByScreenRow = {}
@renderedDecorationsByLineId = {}
shouldComponentUpdate: (newProps) ->
return true unless isEqualForProperties(newProps, @props,
'renderedRowRange', 'selectionScreenRanges', 'lineHeightInPixels', 'defaultCharWidth',
'renderedRowRange', 'lineDecorations', 'highlightDecorations', 'lineHeightInPixels', 'defaultCharWidth',
'scrollTop', 'scrollLeft', 'showIndentGuide', 'scrollingVertically', 'invisibles', 'visible',
'scrollViewHeight', 'mouseWheelScreenRow'
'scrollViewHeight', 'mouseWheelScreenRow', 'scopedCharacterWidthsChangeCount', 'lineWidth', 'useHardwareAcceleration'
)
{renderedRowRange, pendingChanges} = newProps
@@ -49,20 +62,20 @@ LinesComponent = React.createClass
@clearScreenRowCaches() unless prevProps.lineHeightInPixels is @props.lineHeightInPixels
@removeLineNodes() unless isEqualForProperties(prevProps, @props, 'showIndentGuide', 'invisibles')
@updateLines()
@updateLines(@props.lineWidth isnt prevProps.lineWidth)
@measureCharactersInNewLines() if visible and not scrollingVertically
clearScreenRowCaches: ->
@screenRowsByLineId = {}
@lineIdsByScreenRow = {}
updateLines: ->
{editor, renderedRowRange, showIndentGuide, selectionChanged} = @props
updateLines: (updateWidth) ->
{editor, renderedRowRange, showIndentGuide, selectionChanged, lineDecorations} = @props
[startRow, endRow] = renderedRowRange
visibleLines = editor.linesForScreenRows(startRow, endRow - 1)
@removeLineNodes(visibleLines)
@appendOrUpdateVisibleLineNodes(visibleLines, startRow)
@appendOrUpdateVisibleLineNodes(visibleLines, startRow, updateWidth)
removeLineNodes: (visibleLines=[]) ->
{mouseWheelScreenRow} = @props
@@ -75,9 +88,12 @@ LinesComponent = React.createClass
delete @lineNodesByLineId[lineId]
delete @lineIdsByScreenRow[screenRow] if @lineIdsByScreenRow[screenRow] is lineId
delete @screenRowsByLineId[lineId]
delete @renderedDecorationsByLineId[lineId]
node.removeChild(lineNode)
appendOrUpdateVisibleLineNodes: (visibleLines, startRow) ->
appendOrUpdateVisibleLineNodes: (visibleLines, startRow, updateWidth) ->
{lineDecorations} = @props
newLines = null
newLinesHTML = null
@@ -85,7 +101,7 @@ LinesComponent = React.createClass
screenRow = startRow + index
if @hasLineNode(line.id)
@updateLineNode(line, screenRow)
@updateLineNode(line, screenRow, updateWidth)
else
newLines ?= []
newLinesHTML ?= ""
@@ -94,6 +110,8 @@ LinesComponent = React.createClass
@screenRowsByLineId[line.id] = screenRow
@lineIdsByScreenRow[screenRow] = line.id
@renderedDecorationsByLineId[line.id] = lineDecorations[screenRow]
return unless newLines?
WrapperDiv.innerHTML = newLinesHTML
@@ -108,17 +126,25 @@ LinesComponent = React.createClass
@lineNodesByLineId.hasOwnProperty(lineId)
buildLineHTML: (line, screenRow) ->
{editor, mini, showIndentGuide, lineHeightInPixels} = @props
{editor, mini, showIndentGuide, lineHeightInPixels, lineDecorations, lineWidth} = @props
{tokens, text, lineEnding, fold, isSoftWrapped, indentLevel} = line
classes = ''
if decorations = lineDecorations[screenRow]
for decoration in decorations
if editor.decorationMatchesType(decoration, 'line')
classes += decoration.class + ' '
classes += 'line'
top = screenRow * lineHeightInPixels
lineHTML = "<div class=\"line\" style=\"position: absolute; top: #{top}px;\" data-screen-row=\"#{screenRow}\">"
lineHTML = "<div class=\"#{classes}\" style=\"position: absolute; top: #{top}px; width: #{lineWidth}px;\" data-screen-row=\"#{screenRow}\">"
if text is ""
lineHTML += @buildEmptyLineInnerHTML(line)
else
lineHTML += @buildLineInnerHTML(line)
lineHTML += '<span class="fold-marker"></span>' if fold
lineHTML += "</div>"
lineHTML
@@ -185,10 +211,25 @@ LinesComponent = React.createClass
scopeStack.push(scope)
"<span class=\"#{scope.replace(/\.+/g, ' ')}\">"
updateLineNode: (line, screenRow) ->
updateLineNode: (line, screenRow, updateWidth) ->
{editor, lineHeightInPixels, lineDecorations, lineWidth} = @props
lineNode = @lineNodesByLineId[line.id]
decorations = lineDecorations[screenRow]
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)
if decorations?
for decoration in decorations
if editor.decorationMatchesType(decoration, 'line') and not _.deepContains(previousDecorations, decoration)
lineNode.classList.add(decoration.class)
lineNode.style.width = lineWidth + 'px' if updateWidth
unless @screenRowsByLineId[line.id] is screenRow
{lineHeightInPixels} = @props
lineNode = @lineNodesByLineId[line.id]
lineNode.style.top = screenRow * lineHeightInPixels + 'px'
lineNode.dataset.screenRow = screenRow
@screenRowsByLineId[line.id] = screenRow
@@ -205,22 +246,24 @@ LinesComponent = React.createClass
node.removeChild(DummyLineNode)
{editor} = @props
editor.batchUpdates ->
editor.setLineHeightInPixels(lineHeightInPixels)
editor.setDefaultCharWidth(charWidth)
editor.setLineHeightInPixels(lineHeightInPixels)
editor.setDefaultCharWidth(charWidth)
remeasureCharacterWidths: ->
@clearScopedCharWidths()
@measureCharactersInNewLines()
measureCharactersInNewLines: ->
{editor} = @props
[visibleStartRow, visibleEndRow] = @props.renderedRowRange
node = @getDOMNode()
for tokenizedLine in @props.editor.linesForScreenRows(visibleStartRow, visibleEndRow - 1)
unless @measuredLines.has(tokenizedLine)
lineNode = @lineNodesByLineId[tokenizedLine.id]
@measureCharactersInLine(tokenizedLine, lineNode)
editor.batchCharacterMeasurement =>
for tokenizedLine in editor.linesForScreenRows(visibleStartRow, visibleEndRow - 1)
unless @measuredLines.has(tokenizedLine)
lineNode = @lineNodesByLineId[tokenizedLine.id]
@measureCharactersInLine(tokenizedLine, lineNode)
return
measureCharactersInLine: (tokenizedLine, lineNode) ->
{editor} = @props
+24 -4
Ver Arquivo
@@ -67,7 +67,6 @@ class Package
@loadKeymaps()
@loadMenus()
@loadStylesheets()
@grammarsPromise = @loadGrammars()
@scopedPropertiesPromise = @loadScopedProperties()
@requireMainModule() unless @hasActivationEvents()
@@ -83,6 +82,8 @@ class Package
@scopedProperties = []
activate: ->
@grammarsPromise ?= @loadGrammars()
unless @activationDeferred?
@activationDeferred = Q.defer()
@measure 'activateTime', =>
@@ -128,8 +129,9 @@ class Package
atom.contextMenu.add(menuPath, map['context-menu']) for [menuPath, map] in @menus
atom.menu.add(map.menu) for [menuPath, map] in @menus when map.menu
grammar.activate() for grammar in @grammars
@grammarsActivated = true
unless @grammarsActivated
grammar.activate() for grammar in @grammars
@grammarsActivated = true
scopedProperties.activate() for scopedProperties in @scopedProperties
@scopedPropertiesActivated = true
@@ -173,14 +175,32 @@ class Package
else
fs.listSync(stylesheetDirPath, ['css', 'less'])
loadGrammarsSync: ->
return if @grammarsLoaded
grammarsDirPath = path.join(@path, 'grammars')
grammarPaths = fs.listSync(grammarsDirPath, ['json', 'cson'])
for grammarPath in grammarPaths
try
grammar = atom.syntax.readGrammarSync(grammarPath)
grammar.packageName = @name
@grammars.push(grammar)
grammar.activate()
catch error
console.warn("Failed to load grammar: #{grammarPath}", error.stack ? error)
@grammarsLoaded = true
@grammarsActivated = true
loadGrammars: ->
@grammars = []
return Q() if @grammarsLoaded
loadGrammar = (grammarPath, callback) =>
atom.syntax.readGrammar grammarPath, (error, grammar) =>
if error?
console.warn("Failed to load grammar: #{grammarPath}", error.stack ? error)
else
grammar.packageName = @name
@grammars.push(grammar)
grammar.activate() if @grammarsActivated
callback()
+4
Ver Arquivo
@@ -239,6 +239,9 @@ class Project extends Model
task.on 'scan:result-found', (result) =>
iterator(result) unless @isPathModified(result.filePath)
task.on 'scan:file-error', (error) ->
iterator(null, error)
if _.isFunction(options.onPathsSearched)
task.on 'scan:paths-searched', (numberOfPathsSearched) ->
options.onPathsSearched(numberOfPathsSearched)
@@ -283,6 +286,7 @@ class Project extends Model
checkFinished()
task.on 'replace:path-replaced', iterator
task.on 'replace:file-error', (error) -> iterator(null, error)
for buffer in @getBuffers()
continue unless buffer.getPath() in filePaths
+8 -8
Ver Arquivo
@@ -5,9 +5,7 @@ EditorComponent = require './editor-component'
module.exports =
class ReactEditorView extends View
# The `overlayer` class is included for backwards compatibility with
# context menus. It should be removed in v1.0.0
@content: -> @div class: 'editor react overlayer'
@content: -> @div class: 'editor react'
focusOnAttach: false
@@ -36,7 +34,7 @@ class ReactEditorView extends View
node = @component.getDOMNode()
@scrollView = $(node).find('.scroll-view')
@underlayer = $(node).find('.selections').addClass('underlayer')
@underlayer = $(node).find('.highlights').addClass('underlayer')
@overlayer = $(node).find('.lines').addClass('overlayer')
@hiddenInput = $(node).find('.hidden-input')
@@ -71,11 +69,11 @@ class ReactEditorView extends View
scrollToBottom: ->
@editor.setScrollBottom(Infinity)
scrollToScreenPosition: (screenPosition) ->
@editor.scrollToScreenPosition(screenPosition)
scrollToScreenPosition: (screenPosition, options) ->
@editor.scrollToScreenPosition(screenPosition, options)
scrollToBufferPosition: (bufferPosition) ->
@editor.scrollToBufferPosition(bufferPosition)
scrollToBufferPosition: (bufferPosition, options) ->
@editor.scrollToBufferPosition(bufferPosition, options)
scrollToCursorPosition: ->
@editor.scrollToCursorPosition()
@@ -204,4 +202,6 @@ class ReactEditorView extends View
updateDisplay: -> # No-op shim for package specs
resetDisplay: -> # No-op shim for package specs
redraw: -> # No-op shim
+4 -2
Ver Arquivo
@@ -6,8 +6,10 @@ module.exports = (filePaths, regexSource, regexFlags, replacementText) ->
replacer = new PathReplacer()
regex = new RegExp(regexSource, regexFlags)
replacer.on 'file-error', ({code, path, message}) ->
emit('replace:file-error', {code, path, message})
replacer.on 'path-replaced', (result) ->
emit('replace:path-replaced', result)
replacer.replacePaths regex, replacementText, filePaths, ->
callback()
replacer.replacePaths(regex, replacementText, filePaths, -> callback())
+3
Ver Arquivo
@@ -9,6 +9,9 @@ module.exports = (rootPath, regexSource, options) ->
searcher = new PathSearcher()
scanner = new PathScanner(rootPath, options)
searcher.on 'file-error', ({code, path, message}) ->
emit('scan:file-error', {code, path, message})
searcher.on 'results-found', (result) ->
emit('scan:result-found', result)
+24 -1
Ver Arquivo
@@ -91,6 +91,18 @@ class Selection extends Model
end = Math.max(start, end - 1) if range.end.column == 0
[start, end]
getTailScreenPosition: ->
@marker.getTailScreenPosition()
getTailBufferPosition: ->
@marker.getTailBufferPosition()
getHeadScreenPosition: ->
@marker.getHeadScreenPosition()
getHeadBufferPosition: ->
@marker.getHeadBufferPosition()
autoscroll: ->
@editor.scrollToScreenRange(@getScreenRange())
@@ -266,7 +278,8 @@ class Selection extends Model
# FIXME: I have no idea what this does.
getGoalBufferRange: ->
@marker.getAttributes().goalBufferRange
if goalBufferRange = @marker.getAttributes().goalBufferRange
Range.fromObject(goalBufferRange)
# Public: Moves the selection up one row.
addSelectionAbove: ->
@@ -302,6 +315,7 @@ 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)
@@ -430,6 +444,15 @@ class Selection extends Model
@selectRight()
@deleteSelectedText()
# Public: If the selection is empty, removes all text from the cursor to the
# end of the line. If the cursor is already at the end of the line, it
# removes the following newline. If the selection isn't empty, only deletes
# the contents of the selection.
deleteToEndOfLine: ->
return @delete() if @isEmpty() and @cursor.isAtEndOfLine()
@selectToEndOfLine() if @isEmpty()
@deleteSelectedText()
# Public: Removes the selection or all characters from the start of the
# selection to the end of the current word if nothing is selected.
deleteToEndOfWord: ->
-25
Ver Arquivo
@@ -1,25 +0,0 @@
React = require 'react-atom-fork'
{div} = require 'reactionary-atom-fork'
{isEqualForProperties} = require 'underscore-plus'
SelectionComponent = require './selection-component'
module.exports =
SelectionsComponent = React.createClass
displayName: 'SelectionsComponent'
render: ->
div className: 'selections', @renderSelections()
renderSelections: ->
{editor, selectionScreenRanges, lineHeightInPixels} = @props
selectionComponents = []
for selectionId, screenRange of selectionScreenRanges
selectionComponents.push(SelectionComponent({key: selectionId, screenRange, editor, lineHeightInPixels}))
selectionComponents
componentWillMount: ->
@selectionRanges = {}
shouldComponentUpdate: (newProps) ->
not isEqualForProperties(newProps, @props, 'selectionScreenRanges', 'lineHeightInPixels', 'defaultCharWidth')
+22 -15
Ver Arquivo
@@ -2,8 +2,8 @@ _ = require 'underscore-plus'
textUtils = require './text-utils'
WhitespaceRegexesByTabLength = {}
LeadingWhitespaceRegex = /^[ ]+/
TrailingWhitespaceRegex = /[ ]+$/
LeadingSpaceRegex = /^[ ]+/
TrailingSpaceRegex = /[ ]+$/
EscapeRegex = /[&"'<>]/g
CharacterRegex = /./g
StartCharacterRegex = /^./
@@ -42,16 +42,18 @@ class Token
whitespaceRegexForTabLength: (tabLength) ->
WhitespaceRegexesByTabLength[tabLength] ?= new RegExp("([ ]{#{tabLength}})|(\t)|([^\t]+)", "g")
breakOutAtomicTokens: (tabLength, breakOutLeadingSoftTabs) ->
breakOutAtomicTokens: (tabLength, breakOutLeadingSoftTabs, startColumn) ->
if @hasSurrogatePair
outputTokens = []
column = startColumn
for token in @breakOutSurrogatePairs()
if token.isAtomic
outputTokens.push(token)
else
outputTokens.push(token.breakOutAtomicTokens(tabLength, breakOutLeadingSoftTabs)...)
outputTokens.push(token.breakOutAtomicTokens(tabLength, breakOutLeadingSoftTabs, column)...)
breakOutLeadingSoftTabs = token.isOnlyWhitespace() if breakOutLeadingSoftTabs
column += token.value.length
outputTokens
else
@@ -64,17 +66,21 @@ class Token
outputTokens = []
regex = @whitespaceRegexForTabLength(tabLength)
column = startColumn
while match = regex.exec(@value)
[fullMatch, softTab, hardTab] = match
token = null
if softTab and breakOutLeadingSoftTabs
outputTokens.push(@buildSoftTabToken(tabLength))
token = @buildSoftTabToken(tabLength)
else if hardTab
breakOutLeadingSoftTabs = false
outputTokens.push(@buildHardTabToken(tabLength))
token = @buildHardTabToken(tabLength, column)
else
breakOutLeadingSoftTabs = false
value = match[0]
outputTokens.push(new Token({value, @scopes}))
token = new Token({value, @scopes})
column += token.value.length
outputTokens.push(token)
outputTokens
@@ -105,17 +111,18 @@ class Token
isAtomic: true
)
buildHardTabToken: (tabLength) ->
@buildTabToken(tabLength, true)
buildHardTabToken: (tabLength, column) ->
@buildTabToken(tabLength, true, column)
buildSoftTabToken: (tabLength) ->
@buildTabToken(tabLength, false)
@buildTabToken(tabLength, false, 0)
buildTabToken: (tabLength, isHardTab) ->
buildTabToken: (tabLength, isHardTab, column=0) ->
tabStop = tabLength - (column % tabLength)
new Token(
value: _.multiplyString(" ", tabLength)
value: _.multiplyString(" ", tabStop)
scopes: @scopes
bufferDelta: if isHardTab then 1 else tabLength
bufferDelta: if isHardTab then 1 else tabStop
isAtomic: true
isHardTab: isHardTab
)
@@ -144,7 +151,7 @@ class Token
leadingHtml = ''
trailingHtml = ''
if @hasLeadingWhitespace and match = LeadingWhitespaceRegex.exec(@value)
if @hasLeadingWhitespace and match = LeadingSpaceRegex.exec(@value)
classes = 'leading-whitespace'
classes += ' indent-guide' if hasIndentGuide
classes += ' invisible-character' if invisibles.space
@@ -154,7 +161,7 @@ class Token
startIndex = match[0].length
if @hasTrailingWhitespace and match = TrailingWhitespaceRegex.exec(@value)
if @hasTrailingWhitespace and match = TrailingSpaceRegex.exec(@value)
tokenIsOnlyWhitespace = match[0].length is @value.length
classes = 'trailing-whitespace'
classes += ' indent-guide' if hasIndentGuide and not @hasLeadingWhitespace and tokenIsOnlyWhitespace
+14 -1
Ver Arquivo
@@ -161,13 +161,26 @@ class TokenizedBuffer extends Model
previousEndStack = @stackForRow(end) # used in spill detection below
newTokenizedLines = @buildTokenizedLinesForRows(start, end + delta, @stackForRow(start - 1))
_.spliceWithArray(@tokenizedLines, start, end - start + 1, newTokenizedLines)
newEndStack = @stackForRow(end + delta)
start = @retokenizeWhitespaceRowsIfIndentLevelChanged(start - 1, -1)
end = @retokenizeWhitespaceRowsIfIndentLevelChanged(newRange.end.row + 1, 1) - delta
newEndStack = @stackForRow(end + delta)
if newEndStack and not _.isEqual(newEndStack, previousEndStack)
@invalidateRow(end + delta + 1)
@emit "changed", { start, end, delta, bufferChange: e }
retokenizeWhitespaceRowsIfIndentLevelChanged: (row, increment) ->
line = @tokenizedLines[row]
if line?.isOnlyWhitespace() and @indentLevelForRow(row) isnt line.indentLevel
while line?.isOnlyWhitespace()
@tokenizedLines[row] = @buildTokenizedTokenizedLineForRow(row, @stackForRow(row - 1))
row += increment
line = @tokenizedLines[row]
row - increment
buildTokenizedLinesForRows: (startRow, endRow, startingStack) ->
ruleStack = startingStack
stopTokenizingAt = startRow + @chunkSize
+13 -2
Ver Arquivo
@@ -5,8 +5,8 @@ idCounter = 1
module.exports =
class TokenizedLine
constructor: ({tokens, @lineEnding, @ruleStack, @startBufferColumn, @fold, @tabLength, @indentLevel}) ->
@tokens = @breakOutAtomicTokens(tokens)
@startBufferColumn ?= 0
@tokens = @breakOutAtomicTokens(tokens)
@text = @buildText()
@bufferDelta = @buildBufferDelta()
@@ -124,8 +124,11 @@ class TokenizedLine
breakOutAtomicTokens: (inputTokens) ->
outputTokens = []
breakOutLeadingSoftTabs = true
column = @startBufferColumn
for token in inputTokens
outputTokens.push(token.breakOutAtomicTokens(@tabLength, breakOutLeadingSoftTabs)...)
newTokens = token.breakOutAtomicTokens(@tabLength, breakOutLeadingSoftTabs, column)
column += newToken.value.length for newToken in newTokens
outputTokens.push(newTokens...)
breakOutLeadingSoftTabs = token.isOnlyWhitespace() if breakOutLeadingSoftTabs
outputTokens
@@ -149,6 +152,14 @@ class TokenizedLine
break
false
isOnlyWhitespace: ->
if @text == ''
true
else
for token in @tokens
return false unless token.isOnlyWhitespace()
true
tokenAtIndex: (index) ->
@tokens[index]
+18
Ver Arquivo
@@ -46,6 +46,9 @@ class Workspace extends Model
# Called by the Serializable mixin during deserialization
deserializeParams: (params) ->
for packageName in params.packagesWithActiveGrammars ? []
atom.packages.getLoadedPackage(packageName)?.loadGrammarsSync()
params.paneContainer = PaneContainer.deserialize(params.paneContainer)
params
@@ -53,6 +56,21 @@ class Workspace extends Model
serializeParams: ->
paneContainer: @paneContainer.serialize()
fullScreen: atom.isFullScreen()
packagesWithActiveGrammars: @getPackageNamesWithActiveGrammars()
getPackageNamesWithActiveGrammars: ->
packageNames = []
addGrammar = ({includedGrammarScopes, packageName}={}) ->
return unless packageName
# Prevent cycles
return if packageNames.indexOf(packageName) isnt -1
packageNames.push(packageName)
for scopeName in includedGrammarScopes ? []
addGrammar(atom.syntax.grammarForScopeName(scopeName))
addGrammar(editor.getGrammar()) for editor in @getEditors()
_.uniq(packageNames)
editorAdded: (editor) ->
@emit 'editor-created', editor
+10
Ver Arquivo
@@ -151,6 +151,10 @@
}
}
.editor .fold-marker {
cursor: default;
}
.editor .fold-marker:after {
.icon(0.8em, inline);
content: @ellipsis;
@@ -251,6 +255,12 @@
width: 1px;
}
.editor .highlight {
background: none;
padding: 0;
}
.editor .highlight .region,
.editor .selection .region {
position: absolute;
pointer-events: none;