diff --git a/spec/editor-component-spec.coffee b/spec/editor-component-spec.coffee index b11d523d1..d7409fc64 100644 --- a/spec/editor-component-spec.coffee +++ b/spec/editor-component-spec.coffee @@ -1017,6 +1017,30 @@ describe "EditorComponent", -> linesNode.dispatchEvent(buildMouseEvent('mousedown', clientCoordinatesForScreenPosition([4, 8]), {target})) expect(editor.isFoldedAtBufferRow 4).toBe false + describe "mouse interactions on the gutter", -> + gutterNode = null + + beforeEach -> + gutterNode = node.querySelector('.gutter') + + describe "when the gutter is clicked", -> + it "moves the cursor to the beginning of the clicked row", -> + gutterNode.dispatchEvent(buildMouseEvent('mousedown', clientCoordinatesForScreenRowInGutter(4))) + expect(editor.getCursorScreenPosition()).toEqual [4, 0] + + describe "when the gutter is shift-clicked", -> + beforeEach -> + editor.setSelectedScreenRange([[3, 4], [4, 5]]) + + describe "when the clicked row is before the current selection's tail", -> + it "selects to the beginning of the clicked row", -> + gutterNode.dispatchEvent(buildMouseEvent('mousedown', clientCoordinatesForScreenRowInGutter(1), shiftKey: true)) + expect(editor.getSelectedScreenRange()).toEqual [[1, 0], [3, 4]] + + describe "when the clicked row is after the current selection's tail", -> + it "selects to the beginning of the row following the clicked row", -> + gutterNode.dispatchEvent(buildMouseEvent('mousedown', clientCoordinatesForScreenRowInGutter(6), shiftKey: true)) + expect(editor.getSelectedScreenRange()).toEqual [[3, 4], [7, 0]] describe "focus handling", -> inputNode = null @@ -1445,3 +1469,9 @@ describe "EditorComponent", -> clientY = scrollViewClientRect.top + positionOffset.top - editor.getScrollTop() {clientX, clientY} + clientCoordinatesForScreenRowInGutter = (screenRow) -> + positionOffset = editor.pixelPositionForScreenPosition([screenRow, 1]) + gutterClientRect = node.querySelector('.gutter').getBoundingClientRect() + clientX = gutterClientRect.left + positionOffset.left - editor.getScrollLeft() + clientY = gutterClientRect.top + positionOffset.top - editor.getScrollTop() + {clientX, clientY} diff --git a/src/editor-component.coffee b/src/editor-component.coffee index d520ad1dc..1be090377 100644 --- a/src/editor-component.coffee +++ b/src/editor-component.coffee @@ -79,8 +79,8 @@ EditorComponent = React.createClass div className: className, style: {fontSize, lineHeight, fontFamily}, tabIndex: -1, GutterComponent { - ref: 'gutter', onWidthChanged: @onGutterWidthChanged, lineDecorations, defaultCharWidth, - editor, renderedRowRange, maxLineNumberDigits, scrollViewHeight, + ref: 'gutter', onMouseDown: @onGutterMouseDown, onWidthChanged: @onGutterWidthChanged, + lineDecorations, defaultCharWidth, editor, renderedRowRange, maxLineNumberDigits, scrollViewHeight, scrollTop, scrollHeight, lineHeightInPixels, @pendingChanges, mouseWheelScreenRow } @@ -505,6 +505,21 @@ EditorComponent = React.createClass when 3 then editor.selectLine() @selectToMousePositionUntilMouseUp(event) + onGutterMouseDown: (event) -> + return unless event.button is 0 # only handle the left mouse button + + {editor} = @props + {shiftKey, metaKey} = event + clickedRow = @screenPositionForMouseEvent(event).row + + if shiftKey + tailRow = editor.getSelection().getTailScreenPosition().row + if clickedRow < tailRow + editor.selectToScreenPosition([clickedRow, 0]) + else + editor.selectToScreenPosition([clickedRow + 1, 0]) + else + editor.setCursorScreenPosition([clickedRow, 0]) onStylesheetsChanged: (stylesheet) -> @refreshScrollbars() if @containsScrollbarSelector(stylesheet) diff --git a/src/gutter-component.coffee b/src/gutter-component.coffee index 0f9a55c75..5fc1a1730 100644 --- a/src/gutter-component.coffee +++ b/src/gutter-component.coffee @@ -15,9 +15,9 @@ GutterComponent = React.createClass measuredWidth: null render: -> - {scrollHeight, scrollViewHeight, scrollTop} = @props + {scrollHeight, scrollViewHeight, scrollTop, onMouseDown} = @props - div className: 'gutter', onClick: @onClick, + 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: diff --git a/src/selection.coffee b/src/selection.coffee index c09ed1f53..438a60348 100644 --- a/src/selection.coffee +++ b/src/selection.coffee @@ -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())