Merge remote-tracking branch 'origin/master' into cj-paragraph-test

This commit is contained in:
Corey Johnson
2014-05-23 09:23:30 -07:00
29 changed files with 343 additions and 116 deletions

View File

@@ -38,7 +38,7 @@ For more information on how to work with Atom's official packages, see
[JavaScript](https://github.com/styleguide/javascript),
and [CSS](https://github.com/styleguide/css) styleguides.
* Include thoughtfully-worded, well-structured
[Jasmine](http://pivotal.github.com/jasmine) specs.
[Jasmine](http://jasmine.github.io/) specs.
* Document new code based on the
[Documentation Styleguide](#documentation-styleguide)
* End files with a newline.

View File

@@ -6,6 +6,6 @@
"url": "https://github.com/atom/atom.git"
},
"dependencies": {
"atom-package-manager": "0.56.0"
"atom-package-manager": "0.57.0"
}
}

View File

@@ -143,7 +143,7 @@ downloadFileFromRepo = ({repo, file}, callback) ->
downloadIncludes = (callback) ->
includes = [
{repo: 'atom-keymap', file: 'src/keymap.coffee'}
{repo: 'atom-keymap', file: 'src/keymap-manager.coffee'}
{repo: 'atom-keymap', file: 'src/key-binding.coffee'}
{repo: 'first-mate', file: 'src/grammar.coffee'}
{repo: 'first-mate', file: 'src/grammar-registry.coffee'}

View File

@@ -10,6 +10,7 @@ Ubuntu LTS 12.04 64-bit is the recommended platform.
* libgnome-keyring-dev `sudo apt-get install libgnome-keyring-dev` (refer to your distribution's manual on how to install packages if you are not on Debian or Ubuntu-based systems)
* `npm config set python /usr/bin/python2 -g` to ensure that gyp uses Python 2
## Instructions
```sh
@@ -20,4 +21,29 @@ Ubuntu LTS 12.04 64-bit is the recommended platform.
script/grunt mkdeb # Generates a .deb package at $TMPDIR/atom-build
```
## Troubleshooting
### Exception: "TypeError: Unable to watch path"
If you get following error with a big traceback right after Atom starts:
```
TypeError: Unable to watch path
```
you have to increase number of watched files by inotify. For testing if
this is the reason for this error you can issue
```sh
sudo sysctl fs.inotify.max_user_watches=32768
```
and restart Atom. If Atom now works fine, you can make this setting permanent:
```sh
echo 32768 > /proc/sys/fs/inotify/max_user_watches
```
See also https://github.com/atom/atom/issues/2082.

View File

@@ -3,7 +3,7 @@
## Requirements
* Windows 7 or later
* [Visual C++ 2010 SP1 Express](http://www.visualstudio.com/en-us/downloads/download-visual-studio-vs#DownloadFamilies_4)
* [Visual C++ 2010 Express](http://www.visualstudio.com/en-us/downloads/download-visual-studio-vs#DownloadFamilies_4) with [SP1](http://www.microsoft.com/en-us/download/details.aspx?id=23691)
* [node.js](http://nodejs.org/download/) v0.10.x
* [Python](http://www.python.org/download/) v2.7.x
* [GitHub for Windows](http://windows.github.com/)
@@ -16,7 +16,7 @@
cd C:\
git clone https://github.com/atom/atom/
cd atom
script\build
script/build
```
## Why do I have to use GitHub for Windows?

View File

@@ -5,6 +5,7 @@
* [Creating a Package](creating-a-package.md)
* [Creating a Theme](creating-a-theme.md)
* [Publishing a Package](publishing-a-package.md)
* [Writing Specs](writing-specs.md)
* [Converting a TextMate Bundle](converting-a-text-mate-bundle.md)
* [Converting a TextMate Theme](converting-a-text-mate-theme.md)
* [Contributing](contributing.md)

61
docs/writing-specs.md Normal file
View File

@@ -0,0 +1,61 @@
# Writting specs
Atom uses [Jasmine](http://jasmine.github.io/2.0/introduction.html) as its spec framework. Any new functionality should have specs to guard against regressions.
## Create a new spec
[Atom specs](https://github.com/atom/atom/tree/master/spec) and [package specs](https://github.com/atom/markdown-preview/tree/master/spec) are added to their respective `spec` directory. The example below creates a spec for Atom core.
0. Create a spec file
Spec files **must** end with `-spec` so add `sample-spec.coffee` to `atom/spec`.
0. Add one or more `describe` method
The `describe` method takes two arguments, a description and a function. If the description explains a behavior it typically begins with `when` if it is more like a unit test it begins with the method name.
```coffee
describe "when a test is written", ->
# contents
```
or
```coffee
describe "Editor::moveUp", ->
# contents
```
0. Add one or more `it` method
The `it` method also takes two arugments, a description and a function. Try and make the description flow with the `it` method. For example, a description of `this should work` doesn't read well as `it this should work`. But a description of `should work` sounds great as `it should work`.
```coffee
describe "when a test is written", ->
it "has some expectations that should pass", ->
# Expectations
```
0. Add one or more expectations
The best way to learn about expectations is to read the [jamsine documentation](http://jasmine.github.io/2.0/introduction.html#section-Expectations) about them. Below is a simple example.
```coffee
describe "when a test is written", ->
it "has some expectations that should pass", ->
expect("apples").toEqual("apples")
expect("oranges").not.toEqual("apples")
```
## Runnings 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.
To run a limited subset of specs use the `fdescribe` or `fit` methods. You can use those to focus a single spec or several specs. In the example above, focusing an individual spec looks like this:
```coffee
describe "when a test is written", ->
fit "has some expectations that should pass", ->
expect("apples").toEqual("apples")
expect("oranges").not.toEqual("apples")
```

View File

@@ -149,6 +149,8 @@ ASCII art professional!
* [Getting your project on GitHub guide](http://guides.github.com/overviews/desktop)
* [Writing specs](writing-specs.md) for your package
* [Creating a package guide](creating-a-package.html) for more information
on the mechanics of packages

View File

@@ -1,7 +1,7 @@
{
"name": "atom",
"productName": "Atom",
"version": "0.97.0",
"version": "0.98.0",
"description": "A hackable text editor for the 21st Century.",
"main": "./src/browser/main.js",
"repository": {
@@ -20,7 +20,7 @@
"atomShellVersion": "0.12.5",
"dependencies": {
"async": "0.2.6",
"atom-keymap": "^0.21.0",
"atom-keymap": "^0.22.0",
"bootstrap": "git+https://github.com/atom/bootstrap.git#6af81906189f1747fd6c93479e3d998ebe041372",
"clear-cut": "0.4.0",
"coffee-script": "1.7.0",
@@ -45,8 +45,8 @@
"property-accessors": "^1",
"q": "^1.0.1",
"random-words": "0.0.1",
"react": "^0.10.0",
"reactionary": "^0.9.0",
"react-atom-fork": "^0.10.0",
"reactionary-atom-fork": "^0.9.0",
"runas": "^0.5",
"scandal": "0.15.2",
"scoped-property-store": "^0.9.0",
@@ -54,7 +54,7 @@
"season": "^1.0.2",
"semver": "1.1.4",
"serializable": "^1",
"space-pen": "3.1.1",
"space-pen": "3.2.0",
"temp": "0.5.0",
"text-buffer": "^2.2.2",
"theorist": "^1",
@@ -85,7 +85,7 @@
"fuzzy-finder": "0.51.0",
"git-diff": "0.28.0",
"go-to-line": "0.21.0",
"grammar-selector": "0.26.0",
"grammar-selector": "0.27.0",
"image-view": "0.33.0",
"keybinding-resolver": "0.17.0",
"link": "0.22.0",
@@ -94,7 +94,7 @@
"open-on-github": "0.28.0",
"package-generator": "0.30.0",
"release-notes": "0.31.0",
"settings-view": "0.115.0",
"settings-view": "0.116.0",
"snippets": "0.43.0",
"spell-check": "0.35.0",
"status-bar": "0.40.0",

View File

@@ -948,7 +948,7 @@ describe "DisplayBuffer", ->
it "returns the start and end positions of the marker based on the line height and character widths assigned to the DisplayBuffer", ->
marker = displayBuffer.markScreenRange([[5, 10], [6, 4]])
displayBuffer.setLineHeight(20)
displayBuffer.setLineHeightInPixels(20)
displayBuffer.setDefaultCharWidth(10)
displayBuffer.setScopedCharWidths(["source.js", "keyword.control.js"], r: 11, e: 11, t: 11, u: 11, n: 11)
@@ -959,7 +959,7 @@ describe "DisplayBuffer", ->
describe "::setScrollTop", ->
beforeEach ->
displayBuffer.manageScrollPosition = true
displayBuffer.setLineHeight(10)
displayBuffer.setLineHeightInPixels(10)
it "disallows negative values", ->
displayBuffer.setHeight(displayBuffer.getScrollHeight() + 100)
@@ -979,7 +979,7 @@ describe "DisplayBuffer", ->
describe "::setScrollLeft", ->
beforeEach ->
displayBuffer.manageScrollPosition = true
displayBuffer.setLineHeight(10)
displayBuffer.setLineHeightInPixels(10)
displayBuffer.setDefaultCharWidth(10)
it "disallows negative values", ->
@@ -1000,7 +1000,7 @@ describe "DisplayBuffer", ->
describe "::scrollToScreenPosition(position)", ->
it "sets the scroll top and scroll left so the given screen position is in view", ->
displayBuffer.manageScrollPosition = true
displayBuffer.setLineHeight(10)
displayBuffer.setLineHeightInPixels(10)
displayBuffer.setDefaultCharWidth(10)
displayBuffer.setHorizontalScrollbarHeight(0)

View File

@@ -39,7 +39,7 @@ describe "EditorComponent", ->
component.setLineHeight(1.3)
component.setFontSize(20)
lineHeightInPixels = editor.getLineHeight()
lineHeightInPixels = editor.getLineHeightInPixels()
charWidth = editor.getDefaultCharWidth()
node = component.getDOMNode()
verticalScrollbarNode = node.querySelector('.vertical-scrollbar')
@@ -90,6 +90,43 @@ describe "EditorComponent", ->
expect(component.lineNodeForScreenRow(3).offsetTop).toBe 3 * lineHeightInPixels
expect(component.lineNodeForScreenRow(4).offsetTop).toBe 4 * lineHeightInPixels
it "updates the top position of lines when the line height changes", ->
initialLineHeightInPixels = editor.getLineHeightInPixels()
component.setLineHeight(2)
newLineHeightInPixels = editor.getLineHeightInPixels()
expect(newLineHeightInPixels).not.toBe initialLineHeightInPixels
expect(component.lineNodeForScreenRow(1).offsetTop).toBe 1 * newLineHeightInPixels
it "updates the top position of lines when the font size changes", ->
initialLineHeightInPixels = editor.getLineHeightInPixels()
component.setFontSize(10)
newLineHeightInPixels = editor.getLineHeightInPixels()
expect(newLineHeightInPixels).not.toBe initialLineHeightInPixels
expect(component.lineNodeForScreenRow(1).offsetTop).toBe 1 * newLineHeightInPixels
it "updates the top position of lines when the font family changes", ->
# Can't find a font that changes the line height, but we think one might exist
linesComponent = component.refs.scrollView.refs.lines
spyOn(linesComponent, 'measureLineHeightInPixelsAndCharWidth').andCallFake -> editor.setLineHeightInPixels(10)
initialLineHeightInPixels = editor.getLineHeightInPixels()
component.setFontFamily('sans-serif')
expect(linesComponent.measureLineHeightInPixelsAndCharWidth).toHaveBeenCalled()
newLineHeightInPixels = editor.getLineHeightInPixels()
expect(newLineHeightInPixels).not.toBe initialLineHeightInPixels
expect(component.lineNodeForScreenRow(1).offsetTop).toBe 1 * newLineHeightInPixels
it "renders the .lines div at the full height of the editor if there aren't enough lines to scroll vertically", ->
editor.setText('')
node.style.height = '300px'
component.measureHeightAndWidth()
linesNode = node.querySelector('.lines')
expect(linesNode.offsetHeight).toBe 300
describe "when showInvisibles is enabled", ->
invisibles = null
@@ -764,3 +801,24 @@ describe "EditorComponent", ->
expect(editor.consolidateSelections).toHaveBeenCalled()
expect(event.abortKeyBinding).toHaveBeenCalled()
describe "hiding and showing the editor", ->
describe "when fontSize, fontFamily, or lineHeight changes while the editor is hidden", ->
it "does not attempt to measure the lineHeight and defaultCharWidth until the editor becomes visible again", ->
wrapperView.hide()
initialLineHeightInPixels = editor.getLineHeightInPixels()
initialCharWidth = editor.getDefaultCharWidth()
component.setLineHeight(2)
expect(editor.getLineHeightInPixels()).toBe initialLineHeightInPixels
expect(editor.getDefaultCharWidth()).toBe initialCharWidth
component.setFontSize(22)
expect(editor.getLineHeightInPixels()).toBe initialLineHeightInPixels
expect(editor.getDefaultCharWidth()).toBe initialCharWidth
component.setFontFamily('monospace')
expect(editor.getLineHeightInPixels()).toBe initialLineHeightInPixels
expect(editor.getDefaultCharWidth()).toBe initialCharWidth
wrapperView.show()
expect(editor.getLineHeightInPixels()).not.toBe initialLineHeightInPixels
expect(editor.getDefaultCharWidth()).not.toBe initialCharWidth

View File

@@ -728,7 +728,7 @@ describe "Editor", ->
editor.manageScrollPosition = true
editor.setVerticalScrollMargin(2)
editor.setHorizontalScrollMargin(2)
editor.setLineHeight(10)
editor.setLineHeightInPixels(10)
editor.setDefaultCharWidth(10)
editor.setHorizontalScrollbarHeight(0)
editor.setHeight(5.5 * 10)
@@ -1167,7 +1167,7 @@ describe "Editor", ->
describe "when the 'autoscroll' option is true", ->
it "autoscrolls to the selection", ->
editor.manageScrollPosition = true
editor.setLineHeight(10)
editor.setLineHeightInPixels(10)
editor.setDefaultCharWidth(10)
editor.setHeight(50)
editor.setWidth(50)
@@ -3155,7 +3155,7 @@ describe "Editor", ->
describe ".scrollToCursorPosition()", ->
it "scrolls the last cursor into view", ->
editor.setCursorScreenPosition([8, 8])
editor.setLineHeight(10)
editor.setLineHeightInPixels(10)
editor.setDefaultCharWidth(10)
editor.setHeight(50)
editor.setWidth(50)
@@ -3171,7 +3171,7 @@ describe "Editor", ->
it "scrolls one screen height up or down", ->
editor.manageScrollPosition = true
editor.setLineHeight(10)
editor.setLineHeightInPixels(10)
editor.setHeight(50)
expect(editor.getScrollHeight()).toBe 130

View File

@@ -24,7 +24,7 @@ WindowEventHandler = require './window-event-handler'
# * `atom.config` - A {Config} instance
# * `atom.contextMenu` - A {ContextMenuManager} instance
# * `atom.deserializers` - A {DeserializerManager} instance
# * `atom.keymaps` - A {Keymap} instance
# * `atom.keymaps` - A {KeymapManager} instance
# * `atom.menu` - A {MenuManager} instance
# * `atom.packages` - A {PackageManager} instance
# * `atom.project` - A {Project} instance
@@ -38,8 +38,8 @@ class Atom extends Model
# Public: Load or create the Atom environment in the given mode.
#
# - mode: Pass 'editor' or 'spec' depending on the kind of environment you
# want to build.
# mode - Pass 'editor' or 'spec' depending on the kind of environment you
# want to build.
#
# Returns an Atom instance, fully initialized
@loadOrCreate: (mode) ->
@@ -212,11 +212,11 @@ class Atom extends Model
# in the dimensions parameter. If x or y are omitted the window will be
# centered. If height or width are omitted only the position will be changed.
#
# * dimensions:
# + x: The new x coordinate.
# + y: The new y coordinate.
# + width: The new width.
# + height: The new height.
# dimensions - An {Object} with the following keys:
# :x - The new x coordinate.
# :y - The new y coordinate.
# :width - The new width.
# :height - The new height.
setWindowDimensions: ({x, y, width, height}) ->
if width? and height?
@setSize(width, height)

View File

@@ -1,5 +1,5 @@
React = require 'react'
{div} = require 'reactionary'
React = require 'react-atom-fork'
{div} = require 'reactionary-atom-fork'
module.exports =
CursorComponent = React.createClass

View File

@@ -1,5 +1,5 @@
React = require 'react'
{div} = require 'reactionary'
React = require 'react-atom-fork'
{div} = require 'reactionary-atom-fork'
{debounce, toArray} = require 'underscore-plus'
SubscriberMixin = require './subscriber-mixin'
CursorComponent = require './cursor-component'

View File

@@ -23,7 +23,7 @@ class DisplayBuffer extends Model
manageScrollPosition: false
softWrap: null
editorWidthInChars: null
lineHeight: null
lineHeightInPixels: null
defaultCharWidth: null
height: null
width: null
@@ -198,8 +198,8 @@ class DisplayBuffer extends Model
@setScrollLeft(scrollRight - @width)
@getScrollRight()
getLineHeight: -> @lineHeight
setLineHeight: (@lineHeight) -> @lineHeight
getLineHeightInPixels: -> @lineHeightInPixels
setLineHeightInPixels: (@lineHeightInPixels) -> @lineHeightInPixels
getDefaultCharWidth: -> @defaultCharWidth
setDefaultCharWidth: (@defaultCharWidth) -> @defaultCharWidth
@@ -227,20 +227,20 @@ class DisplayBuffer extends Model
@charWidthsByScope = {}
getScrollHeight: ->
unless @getLineHeight() > 0
throw new Error("You must assign lineHeight before calling ::getScrollHeight()")
unless @getLineHeightInPixels() > 0
throw new Error("You must assign lineHeightInPixels before calling ::getScrollHeight()")
@getLineCount() * @getLineHeight()
@getLineCount() * @getLineHeightInPixels()
getScrollWidth: ->
(@getMaxLineLength() * @getDefaultCharWidth()) + @getCursorWidth()
getVisibleRowRange: ->
unless @getLineHeight() > 0
throw new Error("You must assign a non-zero lineHeight before calling ::getVisibleRowRange()")
unless @getLineHeightInPixels() > 0
throw new Error("You must assign a non-zero lineHeightInPixels before calling ::getVisibleRowRange()")
heightInLines = Math.ceil(@getHeight() / @getLineHeight()) + 1
startRow = Math.floor(@getScrollTop() / @getLineHeight())
heightInLines = Math.ceil(@getHeight() / @getLineHeightInPixels()) + 1
startRow = Math.floor(@getScrollTop() / @getLineHeightInPixels())
endRow = Math.min(@getLineCount(), startRow + heightInLines)
[startRow, endRow]
@@ -254,7 +254,7 @@ class DisplayBuffer extends Model
@intersectsVisibleRowRange(start.row, end.row + 1)
scrollToScreenRange: (screenRange) ->
verticalScrollMarginInPixels = @getVerticalScrollMargin() * @getLineHeight()
verticalScrollMarginInPixels = @getVerticalScrollMargin() * @getLineHeightInPixels()
horizontalScrollMarginInPixels = @getHorizontalScrollMargin() * @getDefaultCharWidth()
{top, left, height, width} = @pixelRectForScreenRange(screenRange)
@@ -285,11 +285,11 @@ class DisplayBuffer extends Model
if screenRange.end.row > screenRange.start.row
top = @pixelPositionForScreenPosition(screenRange.start).top
left = 0
height = (screenRange.end.row - screenRange.start.row + 1) * @getLineHeight()
height = (screenRange.end.row - screenRange.start.row + 1) * @getLineHeightInPixels()
width = @getScrollWidth()
else
{top, left} = @pixelPositionForScreenPosition(screenRange.start)
height = @getLineHeight()
height = @getLineHeightInPixels()
width = @pixelPositionForScreenPosition(screenRange.end).left - left
{top, left, width, height}
@@ -512,7 +512,7 @@ class DisplayBuffer extends Model
targetColumn = screenPosition.column
defaultCharWidth = @defaultCharWidth
top = targetRow * @lineHeight
top = targetRow * @lineHeightInPixels
left = 0
column = 0
for token in @lineForRow(targetRow).tokens
@@ -527,7 +527,7 @@ class DisplayBuffer extends Model
targetTop = pixelPosition.top
targetLeft = pixelPosition.left
defaultCharWidth = @defaultCharWidth
row = Math.floor(targetTop / @getLineHeight())
row = Math.floor(targetTop / @getLineHeightInPixels())
row = Math.min(row, @getLastRow())
row = Math.max(0, row)

View File

@@ -1,5 +1,5 @@
React = require 'react'
{div, span} = require 'reactionary'
React = require 'react-atom-fork'
{div, span} = require 'reactionary-atom-fork'
{debounce, defaults} = require 'underscore-plus'
scrollbarStyle = require 'scrollbar-style'
@@ -31,7 +31,7 @@ EditorComponent = React.createClass
mouseWheelScreenRow: null
render: ->
{focused, fontSize, lineHeight, fontFamily, showIndentGuide, showInvisibles} = @state
{focused, fontSize, lineHeight, fontFamily, showIndentGuide, showInvisibles, visible} = @state
{editor, cursorBlinkPeriod, cursorBlinkResumeDelay} = @props
maxLineNumberDigits = editor.getScreenLineCount().toString().length
invisibles = if showInvisibles then @state.invisibles else {}
@@ -42,7 +42,8 @@ EditorComponent = React.createClass
scrollWidth = editor.getScrollWidth()
scrollTop = editor.getScrollTop()
scrollLeft = editor.getScrollLeft()
lineHeightInPixels = editor.getLineHeight()
lineHeightInPixels = editor.getLineHeightInPixels()
scrollViewHeight = editor.getHeight()
horizontalScrollbarHeight = editor.getHorizontalScrollbarHeight()
verticalScrollbarWidth = editor.getVerticalScrollbarWidth()
verticallyScrollable = editor.verticallyScrollable()
@@ -54,17 +55,17 @@ EditorComponent = React.createClass
div className: className, style: {fontSize, lineHeight, fontFamily}, tabIndex: -1,
GutterComponent {
ref: 'gutter', editor, renderedRowRange, maxLineNumberDigits,
scrollTop, scrollHeight, lineHeight: lineHeightInPixels, fontSize, fontFamily,
scrollTop, scrollHeight, lineHeight, lineHeightInPixels, fontSize, fontFamily,
@pendingChanges, onWidthChanged: @onGutterWidthChanged, @mouseWheelScreenRow
}
EditorScrollViewComponent {
ref: 'scrollView', editor, fontSize, fontFamily, showIndentGuide,
lineHeight: lineHeightInPixels, renderedRowRange, @pendingChanges,
lineHeight, lineHeightInPixels, renderedRowRange, @pendingChanges,
scrollTop, scrollLeft, scrollHeight, scrollWidth, @scrollingVertically,
@cursorsMoved, @selectionChanged, @selectionAdded, cursorBlinkPeriod,
cursorBlinkResumeDelay, @onInputFocused, @onInputBlurred, @mouseWheelScreenRow,
invisibles
invisibles, visible, scrollViewHeight
}
ScrollbarComponent
@@ -106,7 +107,8 @@ EditorComponent = React.createClass
renderedEndRow = Math.min(editor.getScreenLineCount(), visibleEndRow + lineOverdrawMargin)
[renderedStartRow, renderedEndRow]
getInitialState: -> {}
getInitialState: ->
visible: true
getDefaultProps: ->
cursorBlinkPeriod: 800
@@ -157,7 +159,7 @@ EditorComponent = React.createClass
@subscribe editor.$height.changes, @requestUpdate
@subscribe editor.$width.changes, @requestUpdate
@subscribe editor.$defaultCharWidth.changes, @requestUpdate
@subscribe editor.$lineHeight.changes, @requestUpdate
@subscribe editor.$lineHeightInPixels.changes, @requestUpdate
listenForDOMEvents: ->
node = @getDOMNode()
@@ -262,6 +264,7 @@ EditorComponent = React.createClass
'editor:scroll-to-cursor': => editor.scrollToCursorPosition()
'core:page-up': => editor.pageUp()
'core:page-down': => editor.pageDown()
'benchmark:scroll': @runScrollBenchmark
addCommandListeners: (listenersByCommandName) ->
{parentView} = @props
@@ -272,6 +275,7 @@ EditorComponent = React.createClass
observeConfig: ->
@subscribe atom.config.observe 'editor.fontFamily', @setFontFamily
@subscribe atom.config.observe 'editor.fontSize', @setFontSize
@subscribe atom.config.observe 'editor.lineHeight', @setLineHeight
@subscribe atom.config.observe 'editor.showIndentGuide', @setShowIndentGuide
@subscribe atom.config.observe 'editor.invisibles', @setInvisibles
@subscribe atom.config.observe 'editor.showInvisibles', @setShowInvisibles
@@ -469,3 +473,44 @@ EditorComponent = React.createClass
lineNodeForScreenRow: (screenRow) -> @refs.scrollView.lineNodeForScreenRow(screenRow)
lineNumberNodeForScreenRow: (screenRow) -> @refs.gutter.lineNumberNodeForScreenRow(screenRow)
hide: ->
@setState(visible: false)
show: ->
@setState(visible: true)
runScrollBenchmark: ->
unless process.env.NODE_ENV is 'production'
ReactPerf = require 'react-atom-fork/lib/ReactDefaultPerf'
ReactPerf.start()
node = @getDOMNode()
scroll = (delta, done) ->
dispatchMouseWheelEvent = ->
node.dispatchEvent(new WheelEvent('mousewheel', wheelDeltaX: -0, wheelDeltaY: -delta))
stopScrolling = ->
clearInterval(interval)
done?()
interval = setInterval(dispatchMouseWheelEvent, 10)
setTimeout(stopScrolling, 500)
console.timeline('scroll')
scroll 50, ->
scroll 100, ->
scroll 200, ->
scroll 400, ->
scroll 800, ->
scroll 1600, ->
console.timelineEnd('scroll')
unless process.env.NODE_ENV is 'production'
ReactPerf.stop()
console.log "Inclusive"
ReactPerf.printInclusive()
console.log "Exclusive"
ReactPerf.printExclusive()
console.log "Wasted"
ReactPerf.printWasted()

View File

@@ -1,5 +1,5 @@
React = require 'react'
{div} = require 'reactionary'
React = require 'react-atom-fork'
{div} = require 'reactionary-atom-fork'
{debounce} = require 'underscore-plus'
InputComponent = require './input-component'
@@ -16,8 +16,8 @@ EditorScrollViewComponent = React.createClass
overflowChangedWhilePaused: false
render: ->
{editor, fontSize, fontFamily, lineHeight, showIndentGuide, invisibles} = @props
{renderedRowRange, pendingChanges, scrollTop, scrollLeft, scrollHeight, scrollWidth, scrollingVertically, mouseWheelScreenRow} = @props
{editor, fontSize, fontFamily, lineHeight, lineHeightInPixels, showIndentGuide, invisibles, visible} = @props
{renderedRowRange, pendingChanges, scrollTop, scrollLeft, scrollHeight, scrollWidth, scrollViewHeight, scrollingVertically, mouseWheelScreenRow} = @props
{selectionChanged, selectionAdded, cursorBlinkPeriod, cursorBlinkResumeDelay, cursorsMoved, onInputFocused, onInputBlurred} = @props
if @isMounted()
@@ -35,9 +35,10 @@ EditorScrollViewComponent = React.createClass
CursorsComponent({editor, scrollTop, scrollLeft, cursorsMoved, selectionAdded, cursorBlinkPeriod, cursorBlinkResumeDelay})
LinesComponent {
ref: 'lines', editor, fontSize, fontFamily, lineHeight, showIndentGuide,
renderedRowRange, pendingChanges, scrollTop, scrollLeft, scrollingVertically,
selectionChanged, scrollHeight, scrollWidth, mouseWheelScreenRow, invisibles
ref: 'lines', editor, fontSize, fontFamily, lineHeight, lineHeightInPixels,
showIndentGuide, renderedRowRange, pendingChanges, scrollTop, scrollLeft, scrollingVertically,
selectionChanged, scrollHeight, scrollWidth, mouseWheelScreenRow, invisibles,
visible, scrollViewHeight
}
componentDidMount: ->

View File

@@ -149,7 +149,7 @@ class Editor extends Model
'autoDecreaseIndentForBufferRow', 'toggleLineCommentForBufferRow', 'toggleLineCommentsForBufferRows',
toProperty: 'languageMode'
@delegatesProperties '$lineHeight', '$defaultCharWidth', '$height', '$width',
@delegatesProperties '$lineHeightInPixels', '$defaultCharWidth', '$height', '$width',
'$scrollTop', '$scrollLeft', 'manageScrollPosition', toProperty: 'displayBuffer'
constructor: ({@softTabs, initialLine, initialColumn, tabLength, softWrap, @displayBuffer, buffer, registerEditor, suppressCursorCreation}) ->
@@ -1867,8 +1867,8 @@ class Editor extends Model
getHorizontalScrollMargin: -> @displayBuffer.getHorizontalScrollMargin()
setHorizontalScrollMargin: (horizontalScrollMargin) -> @displayBuffer.setHorizontalScrollMargin(horizontalScrollMargin)
getLineHeight: -> @displayBuffer.getLineHeight()
setLineHeight: (lineHeight) -> @displayBuffer.setLineHeight(lineHeight)
getLineHeightInPixels: -> @displayBuffer.getLineHeightInPixels()
setLineHeightInPixels: (lineHeightInPixels) -> @displayBuffer.setLineHeightInPixels(lineHeightInPixels)
getScopedCharWidth: (scopeNames, char) -> @displayBuffer.getScopedCharWidth(scopeNames, char)
setScopedCharWidth: (scopeNames, char, width) -> @displayBuffer.setScopedCharWidth(scopeNames, char, width)

View File

@@ -1,5 +1,5 @@
React = require 'react'
{div} = require 'reactionary'
React = require 'react-atom-fork'
{div} = require 'reactionary-atom-fork'
{isEqual, isEqualForProperties, multiplyString, toArray} = require 'underscore-plus'
SubscriberMixin = require './subscriber-mixin'
@@ -33,7 +33,7 @@ GutterComponent = React.createClass
# non-zero-delta change to the screen lines has occurred within the current
# visible row range.
shouldComponentUpdate: (newProps) ->
return true unless isEqualForProperties(newProps, @props, 'renderedRowRange', 'scrollTop', 'lineHeight', 'fontSize')
return true unless isEqualForProperties(newProps, @props, 'renderedRowRange', 'scrollTop', 'lineHeightInPixels', 'fontSize')
{renderedRowRange, pendingChanges} = newProps
for change in pendingChanges when Math.abs(change.screenDelta) > 0 or Math.abs(change.bufferDelta) > 0
@@ -47,7 +47,7 @@ GutterComponent = React.createClass
@removeLineNumberNodes()
@measureWidth() unless @lastMeasuredWidth? and isEqualForProperties(oldProps, @props, 'maxLineNumberDigits', 'fontSize', 'fontFamily')
@clearScreenRowCaches() unless oldProps.lineHeight is @props.lineHeight
@clearScreenRowCaches() unless oldProps.lineHeightInPixels is @props.lineHeightInPixels
@updateLineNumbers()
clearScreenRowCaches: ->
@@ -125,8 +125,8 @@ GutterComponent = React.createClass
buildLineNumberHTML: (bufferRow, softWrapped, maxLineNumberDigits, screenRow) ->
if screenRow?
{lineHeight} = @props
style = "position: absolute; top: #{screenRow * lineHeight}px;"
{lineHeightInPixels} = @props
style = "position: absolute; top: #{screenRow * lineHeightInPixels}px;"
else
style = "visibility: hidden;"
innerHTML = @buildLineNumberInnerHTML(bufferRow, softWrapped, maxLineNumberDigits)
@@ -145,8 +145,8 @@ GutterComponent = React.createClass
updateLineNumberNode: (lineNumberId, screenRow) ->
unless @screenRowsByLineNumberId[lineNumberId] is screenRow
{lineHeight} = @props
@lineNumberNodesById[lineNumberId].style.top = screenRow * lineHeight + 'px'
{lineHeightInPixels} = @props
@lineNumberNodesById[lineNumberId].style.top = screenRow * lineHeightInPixels + 'px'
@lineNumberNodesById[lineNumberId].dataset.screenRow = screenRow
@screenRowsByLineNumberId[lineNumberId] = screenRow
@lineNumberIdsByScreenRow[screenRow] = lineNumberId

View File

@@ -1,7 +1,7 @@
punycode = require 'punycode'
{last, isEqual} = require 'underscore-plus'
React = require 'react'
{input} = require 'reactionary'
React = require 'react-atom-fork'
{input} = require 'reactionary-atom-fork'
module.exports =
InputComponent = React.createClass

View File

@@ -1,5 +1,5 @@
React = require 'react'
{div, span} = require 'reactionary'
React = require 'react-atom-fork'
{div, span} = require 'reactionary-atom-fork'
{debounce, isEqual, isEqualForProperties, multiplyString, toArray} = require 'underscore-plus'
{$$} = require 'space-pen'
@@ -13,16 +13,18 @@ module.exports =
LinesComponent = React.createClass
displayName: 'LinesComponent'
measureWhenShown: false
render: ->
if @isMounted()
{editor, scrollTop, scrollLeft, scrollHeight, scrollWidth, lineHeight} = @props
{editor, scrollTop, scrollLeft, scrollHeight, scrollWidth, lineHeightInPixels, scrollViewHeight} = @props
style =
height: scrollHeight
height: Math.max(scrollHeight, scrollViewHeight)
width: scrollWidth
WebkitTransform: "translate3d(#{-scrollLeft}px, #{-scrollTop}px, 0px)"
div {className: 'lines', style},
SelectionsComponent({editor, lineHeight}) if @isMounted()
SelectionsComponent({editor, lineHeightInPixels}) if @isMounted()
componentWillMount: ->
@measuredLines = new WeakSet
@@ -31,11 +33,15 @@ LinesComponent = React.createClass
@lineIdsByScreenRow = {}
componentDidMount: ->
@measureLineHeightAndCharWidth()
@measureLineHeightInPixelsAndCharWidth()
shouldComponentUpdate: (newProps) ->
return true if newProps.selectionChanged
return true unless isEqualForProperties(newProps, @props, 'renderedRowRange', 'fontSize', 'fontFamily', 'lineHeight', 'scrollTop', 'scrollLeft', 'showIndentGuide', 'scrollingVertically', 'invisibles')
return true unless isEqualForProperties(newProps, @props,
'renderedRowRange', 'fontSize', 'fontFamily', 'lineHeight', 'lineHeightInPixels',
'scrollTop', 'scrollLeft', 'showIndentGuide', 'scrollingVertically', 'invisibles',
'visible', 'scrollViewHeight'
)
{renderedRowRange, pendingChanges} = newProps
for change in pendingChanges
@@ -44,8 +50,8 @@ LinesComponent = React.createClass
false
componentDidUpdate: (prevProps) ->
@measureLineHeightAndCharWidth() unless isEqualForProperties(prevProps, @props, 'fontSize', 'fontFamily', 'lineHeight')
@clearScreenRowCaches() unless prevProps.lineHeight is @props.lineHeight
@measureLineHeightInPixelsAndCharWidthIfNeeded(prevProps)
@clearScreenRowCaches() unless prevProps.lineHeightInPixels is @props.lineHeightInPixels
@removeLineNodes() unless isEqualForProperties(prevProps, @props, 'showIndentGuide', 'invisibles')
@updateLines()
@clearScopedCharWidths() unless isEqualForProperties(prevProps, @props, 'fontSize', 'fontFamily')
@@ -77,7 +83,6 @@ LinesComponent = React.createClass
node.removeChild(lineNode)
appendOrUpdateVisibleLineNodes: (visibleLines, startRow) ->
{lineHeight} = @props
newLines = null
newLinesHTML = null
@@ -108,9 +113,10 @@ LinesComponent = React.createClass
@lineNodesByLineId.hasOwnProperty(lineId)
buildLineHTML: (line, screenRow) ->
{editor, mini, showIndentGuide, lineHeight} = @props
{editor, mini, showIndentGuide, lineHeightInPixels} = @props
{tokens, text, lineEnding, fold, isSoftWrapped, indentLevel} = line
top = screenRow * lineHeight
top = screenRow * lineHeightInPixels
lineHTML = "<div class=\"line\" style=\"position: absolute; top: #{top}px;\" data-screen-row=\"#{screenRow}\">"
if text is ""
@@ -186,9 +192,9 @@ LinesComponent = React.createClass
updateLineNode: (line, screenRow) ->
unless @screenRowsByLineId[line.id] is screenRow
{lineHeight} = @props
{lineHeightInPixels} = @props
lineNode = @lineNodesByLineId[line.id]
lineNode.style.top = screenRow * lineHeight + 'px'
lineNode.style.top = screenRow * lineHeightInPixels + 'px'
lineNode.dataset.screenRow = screenRow
@screenRowsByLineId[line.id] = screenRow
@lineIdsByScreenRow[screenRow] = line.id
@@ -196,15 +202,26 @@ LinesComponent = React.createClass
lineNodeForScreenRow: (screenRow) ->
@lineNodesByLineId[@lineIdsByScreenRow[screenRow]]
measureLineHeightAndCharWidth: ->
measureLineHeightInPixelsAndCharWidthIfNeeded: (prevProps) ->
{visible} = @props
unless isEqualForProperties(prevProps, @props, 'fontSize', 'fontFamily', 'lineHeight')
if visible
@measureLineHeightInPixelsAndCharWidth()
else
@measureWhenShown = true
@measureLineHeightInPixelsAndCharWidth() if visible and not prevProps.visible and @measureWhenShown
measureLineHeightInPixelsAndCharWidth: ->
@measureWhenShown = false
node = @getDOMNode()
node.appendChild(DummyLineNode)
lineHeight = DummyLineNode.getBoundingClientRect().height
lineHeightInPixels = DummyLineNode.getBoundingClientRect().height
charWidth = DummyLineNode.firstChild.getBoundingClientRect().width
node.removeChild(DummyLineNode)
{editor} = @props
editor.setLineHeight(lineHeight)
editor.setLineHeightInPixels(lineHeightInPixels)
editor.setDefaultCharWidth(charWidth)
measureCharactersInNewLines: ->

View File

@@ -149,7 +149,7 @@ class PaneView extends View
hasFocus = @hasFocus()
item.on? 'title-changed', @activeItemTitleChanged
view = @viewForItem(item)
@itemViews.children().not(view).hide()
otherView.hide() for otherView in @itemViews.children().not(view).views()
@itemViews.append(view) unless view.parent().is(@itemViews)
view.show() if @attached
view.focus() if hasFocus

View File

@@ -1,5 +1,5 @@
{View, $} = require 'space-pen'
React = require 'react'
React = require 'react-atom-fork'
EditorComponent = require './editor-component'
{defaults} = require 'underscore-plus'
@@ -14,7 +14,7 @@ class ReactEditorView extends View
getEditor: -> @editor
Object.defineProperty @::, 'lineHeight', get: -> @editor.getLineHeight()
Object.defineProperty @::, 'lineHeight', get: -> @editor.getLineHeightInPixels()
Object.defineProperty @::, 'charWidth', get: -> @editor.getDefaultCharWidth()
scrollTop: (scrollTop) ->
@@ -82,3 +82,11 @@ class ReactEditorView extends View
@component.onFocus()
else
@focusOnAttach = true
hide: ->
super
@component.hide()
show: ->
super
@component.show()

View File

@@ -6,6 +6,8 @@
# the following events won't be handled by the ScrollView.
#
# ## Events
# * `core:move-up`
# * `core:move-down`
# * `core:page-up`
# * `core:page-down`
# * `core:move-to-top`
@@ -19,6 +21,8 @@
module.exports =
class ScrollView extends View
initialize: ->
@on 'core:move-up', => @scrollUp()
@on 'core:move-down', => @scrollDown()
@on 'core:page-up', => @pageUp()
@on 'core:page-down', => @pageDown()
@on 'core:move-to-top', => @scrollToTop()

View File

@@ -1,9 +1,11 @@
React = require 'react'
{div} = require 'reactionary'
React = require 'react-atom-fork'
{div} = require 'reactionary-atom-fork'
{extend, isEqualForProperties} = require 'underscore-plus'
module.exports =
ScrollbarComponent = React.createClass
displayName: 'ScrollbarComponent'
render: ->
{orientation, className, scrollHeight, scrollWidth, visible} = @props
{scrollableInOppositeDirection, horizontalScrollbarHeight, verticalScrollbarWidth} = @props

View File

@@ -1,8 +1,10 @@
React = require 'react'
{div} = require 'reactionary'
React = require 'react-atom-fork'
{div} = require 'reactionary-atom-fork'
module.exports =
ScrollbarComponent = React.createClass
ScrollbarCornerComponent = React.createClass
displayName: 'ScrollbarCornerComponent'
render: ->
{visible, measuringScrollbars, width, height} = @props

View File

@@ -1,12 +1,12 @@
React = require 'react'
{div} = require 'reactionary'
React = require 'react-atom-fork'
{div} = require 'reactionary-atom-fork'
module.exports =
SelectionComponent = React.createClass
displayName: 'SelectionComponent'
render: ->
{editor, screenRange, lineHeight} = @props
{editor, screenRange, lineHeightInPixels} = @props
{start, end} = screenRange
rowCount = end.row - start.row + 1
startPixelPosition = editor.pixelPositionForScreenPosition(start)
@@ -19,18 +19,18 @@ SelectionComponent = React.createClass
@renderMultiLineRegions(startPixelPosition, endPixelPosition, rowCount)
renderSingleLineRegions: (startPixelPosition, endPixelPosition) ->
{lineHeight} = @props
{lineHeightInPixels} = @props
[
div className: 'region', key: 0, style:
top: startPixelPosition.top
height: lineHeight
height: lineHeightInPixels
left: startPixelPosition.left
width: endPixelPosition.left - startPixelPosition.left
]
renderMultiLineRegions: (startPixelPosition, endPixelPosition, rowCount) ->
{lineHeight} = @props
{lineHeightInPixels} = @props
regions = []
index = 0
@@ -39,7 +39,7 @@ SelectionComponent = React.createClass
div className: 'region', key: index++, style:
top: startPixelPosition.top
left: startPixelPosition.left
height: lineHeight
height: lineHeightInPixels
right: 0
)
@@ -47,8 +47,8 @@ SelectionComponent = React.createClass
if rowCount > 2
regions.push(
div className: 'region', key: index++, style:
top: startPixelPosition.top + lineHeight
height: (rowCount - 2) * lineHeight
top: startPixelPosition.top + lineHeightInPixels
height: (rowCount - 2) * lineHeightInPixels
left: 0
right: 0
)
@@ -57,7 +57,7 @@ SelectionComponent = React.createClass
regions.push(
div className: 'region', key: index, style:
top: endPixelPosition.top
height: lineHeight
height: lineHeightInPixels
left: 0
width: endPixelPosition.left
)

View File

@@ -1,5 +1,5 @@
React = require 'react'
{div} = require 'reactionary'
React = require 'react-atom-fork'
{div} = require 'reactionary-atom-fork'
SelectionComponent = require './selection-component'
module.exports =
@@ -10,11 +10,11 @@ SelectionsComponent = React.createClass
div className: 'selections', @renderSelections()
renderSelections: ->
{editor, lineHeight} = @props
{editor, lineHeightInPixels} = @props
selectionComponents = []
for selectionId, screenRange of @selectionRanges
selectionComponents.push(SelectionComponent({key: selectionId, screenRange, editor, lineHeight}))
selectionComponents.push(SelectionComponent({key: selectionId, screenRange, editor, lineHeightInPixels}))
selectionComponents
componentWillMount: ->