mirror of
https://github.com/atom/atom.git
synced 2026-01-24 06:18:03 -05:00
Merge pull request #16192 from atom/wl-async-context-menu
Make ContextMenu async
This commit is contained in:
@@ -2831,431 +2831,435 @@ describe('TextEditorComponent', () => {
|
||||
|
||||
describe('mouse input', () => {
|
||||
describe('on the lines', () => {
|
||||
it('positions the cursor on single-click', async () => {
|
||||
const {component, element, editor} = buildComponent()
|
||||
const {lineHeight} = component.measurements
|
||||
it('positions the cursor on single-click or when middle/right-clicking', async () => {
|
||||
for (const button of [0, 1, 2]) {
|
||||
const {component, element, editor} = buildComponent()
|
||||
const {lineHeight} = component.measurements
|
||||
|
||||
editor.setCursorScreenPosition([Infinity, Infinity], {autoscroll: false})
|
||||
component.didMouseDownOnContent({
|
||||
detail: 1,
|
||||
button: 0,
|
||||
clientX: clientLeftForCharacter(component, 0, 0) - 1,
|
||||
clientY: clientTopForLine(component, 0) - 1
|
||||
})
|
||||
expect(editor.getCursorScreenPosition()).toEqual([0, 0])
|
||||
editor.setCursorScreenPosition([Infinity, Infinity], {autoscroll: false})
|
||||
component.didMouseDownOnContent({
|
||||
detail: 1,
|
||||
button,
|
||||
clientX: clientLeftForCharacter(component, 0, 0) - 1,
|
||||
clientY: clientTopForLine(component, 0) - 1
|
||||
})
|
||||
expect(editor.getCursorScreenPosition()).toEqual([0, 0])
|
||||
|
||||
const maxRow = editor.getLastScreenRow()
|
||||
editor.setCursorScreenPosition([Infinity, Infinity], {autoscroll: false})
|
||||
component.didMouseDownOnContent({
|
||||
detail: 1,
|
||||
button: 0,
|
||||
clientX: clientLeftForCharacter(component, maxRow, editor.lineLengthForScreenRow(maxRow)) + 1,
|
||||
clientY: clientTopForLine(component, maxRow) + 1
|
||||
})
|
||||
expect(editor.getCursorScreenPosition()).toEqual([maxRow, editor.lineLengthForScreenRow(maxRow)])
|
||||
const maxRow = editor.getLastScreenRow()
|
||||
editor.setCursorScreenPosition([Infinity, Infinity], {autoscroll: false})
|
||||
component.didMouseDownOnContent({
|
||||
detail: 1,
|
||||
button,
|
||||
clientX: clientLeftForCharacter(component, maxRow, editor.lineLengthForScreenRow(maxRow)) + 1,
|
||||
clientY: clientTopForLine(component, maxRow) + 1
|
||||
})
|
||||
expect(editor.getCursorScreenPosition()).toEqual([maxRow, editor.lineLengthForScreenRow(maxRow)])
|
||||
|
||||
component.didMouseDownOnContent({
|
||||
detail: 1,
|
||||
button: 0,
|
||||
clientX: clientLeftForCharacter(component, 0, editor.lineLengthForScreenRow(0)) + 1,
|
||||
clientY: clientTopForLine(component, 0) + lineHeight / 2
|
||||
})
|
||||
expect(editor.getCursorScreenPosition()).toEqual([0, editor.lineLengthForScreenRow(0)])
|
||||
component.didMouseDownOnContent({
|
||||
detail: 1,
|
||||
button,
|
||||
clientX: clientLeftForCharacter(component, 0, editor.lineLengthForScreenRow(0)) + 1,
|
||||
clientY: clientTopForLine(component, 0) + lineHeight / 2
|
||||
})
|
||||
expect(editor.getCursorScreenPosition()).toEqual([0, editor.lineLengthForScreenRow(0)])
|
||||
|
||||
component.didMouseDownOnContent({
|
||||
detail: 1,
|
||||
button: 0,
|
||||
clientX: (clientLeftForCharacter(component, 3, 0) + clientLeftForCharacter(component, 3, 1)) / 2,
|
||||
clientY: clientTopForLine(component, 1) + lineHeight / 2
|
||||
})
|
||||
expect(editor.getCursorScreenPosition()).toEqual([1, 0])
|
||||
component.didMouseDownOnContent({
|
||||
detail: 1,
|
||||
button,
|
||||
clientX: (clientLeftForCharacter(component, 3, 0) + clientLeftForCharacter(component, 3, 1)) / 2,
|
||||
clientY: clientTopForLine(component, 1) + lineHeight / 2
|
||||
})
|
||||
expect(editor.getCursorScreenPosition()).toEqual([1, 0])
|
||||
|
||||
component.didMouseDownOnContent({
|
||||
detail: 1,
|
||||
button: 0,
|
||||
clientX: (clientLeftForCharacter(component, 3, 14) + clientLeftForCharacter(component, 3, 15)) / 2,
|
||||
clientY: clientTopForLine(component, 3) + lineHeight / 2
|
||||
})
|
||||
expect(editor.getCursorScreenPosition()).toEqual([3, 14])
|
||||
component.didMouseDownOnContent({
|
||||
detail: 1,
|
||||
button,
|
||||
clientX: (clientLeftForCharacter(component, 3, 14) + clientLeftForCharacter(component, 3, 15)) / 2,
|
||||
clientY: clientTopForLine(component, 3) + lineHeight / 2
|
||||
})
|
||||
expect(editor.getCursorScreenPosition()).toEqual([3, 14])
|
||||
|
||||
component.didMouseDownOnContent({
|
||||
detail: 1,
|
||||
button: 0,
|
||||
clientX: (clientLeftForCharacter(component, 3, 14) + clientLeftForCharacter(component, 3, 15)) / 2 + 1,
|
||||
clientY: clientTopForLine(component, 3) + lineHeight / 2
|
||||
})
|
||||
expect(editor.getCursorScreenPosition()).toEqual([3, 15])
|
||||
component.didMouseDownOnContent({
|
||||
detail: 1,
|
||||
button,
|
||||
clientX: (clientLeftForCharacter(component, 3, 14) + clientLeftForCharacter(component, 3, 15)) / 2 + 1,
|
||||
clientY: clientTopForLine(component, 3) + lineHeight / 2
|
||||
})
|
||||
expect(editor.getCursorScreenPosition()).toEqual([3, 15])
|
||||
|
||||
editor.getBuffer().setTextInRange([[3, 14], [3, 15]], '🐣')
|
||||
await component.getNextUpdatePromise()
|
||||
editor.getBuffer().setTextInRange([[3, 14], [3, 15]], '🐣')
|
||||
await component.getNextUpdatePromise()
|
||||
|
||||
component.didMouseDownOnContent({
|
||||
detail: 1,
|
||||
button: 0,
|
||||
clientX: (clientLeftForCharacter(component, 3, 14) + clientLeftForCharacter(component, 3, 16)) / 2,
|
||||
clientY: clientTopForLine(component, 3) + lineHeight / 2
|
||||
})
|
||||
expect(editor.getCursorScreenPosition()).toEqual([3, 14])
|
||||
component.didMouseDownOnContent({
|
||||
detail: 1,
|
||||
button,
|
||||
clientX: (clientLeftForCharacter(component, 3, 14) + clientLeftForCharacter(component, 3, 16)) / 2,
|
||||
clientY: clientTopForLine(component, 3) + lineHeight / 2
|
||||
})
|
||||
expect(editor.getCursorScreenPosition()).toEqual([3, 14])
|
||||
|
||||
component.didMouseDownOnContent({
|
||||
detail: 1,
|
||||
button: 0,
|
||||
clientX: (clientLeftForCharacter(component, 3, 14) + clientLeftForCharacter(component, 3, 16)) / 2 + 1,
|
||||
clientY: clientTopForLine(component, 3) + lineHeight / 2
|
||||
})
|
||||
expect(editor.getCursorScreenPosition()).toEqual([3, 16])
|
||||
component.didMouseDownOnContent({
|
||||
detail: 1,
|
||||
button,
|
||||
clientX: (clientLeftForCharacter(component, 3, 14) + clientLeftForCharacter(component, 3, 16)) / 2 + 1,
|
||||
clientY: clientTopForLine(component, 3) + lineHeight / 2
|
||||
})
|
||||
expect(editor.getCursorScreenPosition()).toEqual([3, 16])
|
||||
|
||||
expect(editor.testAutoscrollRequests).toEqual([])
|
||||
expect(editor.testAutoscrollRequests).toEqual([])
|
||||
}
|
||||
})
|
||||
|
||||
it('selects words on double-click', () => {
|
||||
const {component, editor} = buildComponent()
|
||||
const {clientX, clientY} = clientPositionForCharacter(component, 1, 16)
|
||||
component.didMouseDownOnContent({detail: 1, button: 0, clientX, clientY})
|
||||
component.didMouseDownOnContent({detail: 2, button: 0, clientX, clientY})
|
||||
expect(editor.getSelectedScreenRange()).toEqual([[1, 13], [1, 21]])
|
||||
expect(editor.testAutoscrollRequests).toEqual([])
|
||||
})
|
||||
describe('when the input is for the primary mouse button', () => {
|
||||
it('selects words on double-click', () => {
|
||||
const {component, editor} = buildComponent()
|
||||
const {clientX, clientY} = clientPositionForCharacter(component, 1, 16)
|
||||
component.didMouseDownOnContent({detail: 1, button: 0, clientX, clientY})
|
||||
component.didMouseDownOnContent({detail: 2, button: 0, clientX, clientY})
|
||||
expect(editor.getSelectedScreenRange()).toEqual([[1, 13], [1, 21]])
|
||||
expect(editor.testAutoscrollRequests).toEqual([])
|
||||
})
|
||||
|
||||
it('selects lines on triple-click', () => {
|
||||
const {component, editor} = buildComponent()
|
||||
const {clientX, clientY} = clientPositionForCharacter(component, 1, 16)
|
||||
component.didMouseDownOnContent({detail: 1, button: 0, clientX, clientY})
|
||||
component.didMouseDownOnContent({detail: 2, button: 0, clientX, clientY})
|
||||
component.didMouseDownOnContent({detail: 3, button: 0, clientX, clientY})
|
||||
expect(editor.getSelectedScreenRange()).toEqual([[1, 0], [2, 0]])
|
||||
expect(editor.testAutoscrollRequests).toEqual([])
|
||||
})
|
||||
it('selects lines on triple-click', () => {
|
||||
const {component, editor} = buildComponent()
|
||||
const {clientX, clientY} = clientPositionForCharacter(component, 1, 16)
|
||||
component.didMouseDownOnContent({detail: 1, button: 0, clientX, clientY})
|
||||
component.didMouseDownOnContent({detail: 2, button: 0, clientX, clientY})
|
||||
component.didMouseDownOnContent({detail: 3, button: 0, clientX, clientY})
|
||||
expect(editor.getSelectedScreenRange()).toEqual([[1, 0], [2, 0]])
|
||||
expect(editor.testAutoscrollRequests).toEqual([])
|
||||
})
|
||||
|
||||
it('adds or removes cursors when holding cmd or ctrl when single-clicking', () => {
|
||||
const {component, editor} = buildComponent({platform: 'darwin'})
|
||||
expect(editor.getCursorScreenPositions()).toEqual([[0, 0]])
|
||||
it('adds or removes cursors when holding cmd or ctrl when single-clicking', () => {
|
||||
const {component, editor} = buildComponent({platform: 'darwin'})
|
||||
expect(editor.getCursorScreenPositions()).toEqual([[0, 0]])
|
||||
|
||||
// add cursor at 1, 16
|
||||
component.didMouseDownOnContent(
|
||||
Object.assign(clientPositionForCharacter(component, 1, 16), {
|
||||
// add cursor at 1, 16
|
||||
component.didMouseDownOnContent(
|
||||
Object.assign(clientPositionForCharacter(component, 1, 16), {
|
||||
detail: 1,
|
||||
button: 0,
|
||||
metaKey: true
|
||||
})
|
||||
)
|
||||
expect(editor.getCursorScreenPositions()).toEqual([[0, 0], [1, 16]])
|
||||
|
||||
// remove cursor at 0, 0
|
||||
component.didMouseDownOnContent(
|
||||
Object.assign(clientPositionForCharacter(component, 0, 0), {
|
||||
detail: 1,
|
||||
button: 0,
|
||||
metaKey: true
|
||||
})
|
||||
)
|
||||
expect(editor.getCursorScreenPositions()).toEqual([[1, 16]])
|
||||
|
||||
// cmd-click cursor at 1, 16 but don't remove it because it's the last one
|
||||
component.didMouseDownOnContent(
|
||||
Object.assign(clientPositionForCharacter(component, 1, 16), {
|
||||
detail: 1,
|
||||
button: 0,
|
||||
metaKey: true
|
||||
})
|
||||
)
|
||||
expect(editor.getCursorScreenPositions()).toEqual([[1, 16]])
|
||||
|
||||
// cmd-clicking within a selection destroys it
|
||||
editor.addSelectionForScreenRange([[2, 10], [2, 15]], {autoscroll: false})
|
||||
expect(editor.getSelectedScreenRanges()).toEqual([
|
||||
[[1, 16], [1, 16]],
|
||||
[[2, 10], [2, 15]]
|
||||
])
|
||||
component.didMouseDownOnContent(
|
||||
Object.assign(clientPositionForCharacter(component, 2, 13), {
|
||||
detail: 1,
|
||||
button: 0,
|
||||
metaKey: true
|
||||
})
|
||||
)
|
||||
expect(editor.getSelectedScreenRanges()).toEqual([
|
||||
[[1, 16], [1, 16]]
|
||||
])
|
||||
|
||||
// ctrl-click does not add cursors on macOS, but it *does* move the cursor
|
||||
component.didMouseDownOnContent(
|
||||
Object.assign(clientPositionForCharacter(component, 1, 4), {
|
||||
detail: 1,
|
||||
button: 0,
|
||||
ctrlKey: true
|
||||
})
|
||||
)
|
||||
expect(editor.getSelectedScreenRanges()).toEqual([
|
||||
[[1, 4], [1, 4]]
|
||||
])
|
||||
|
||||
// ctrl-click adds cursors on platforms *other* than macOS
|
||||
component.props.platform = 'win32'
|
||||
editor.setCursorScreenPosition([1, 4], {autoscroll: false})
|
||||
component.didMouseDownOnContent(
|
||||
Object.assign(clientPositionForCharacter(component, 1, 16), {
|
||||
detail: 1,
|
||||
button: 0,
|
||||
ctrlKey: true
|
||||
})
|
||||
)
|
||||
expect(editor.getCursorScreenPositions()).toEqual([[1, 4], [1, 16]])
|
||||
|
||||
expect(editor.testAutoscrollRequests).toEqual([])
|
||||
})
|
||||
|
||||
it('adds word selections when holding cmd or ctrl when double-clicking', () => {
|
||||
const {component, editor} = buildComponent()
|
||||
editor.addCursorAtScreenPosition([1, 16], {autoscroll: false})
|
||||
expect(editor.getCursorScreenPositions()).toEqual([[0, 0], [1, 16]])
|
||||
|
||||
component.didMouseDownOnContent(
|
||||
Object.assign(clientPositionForCharacter(component, 1, 16), {
|
||||
detail: 1,
|
||||
button: 0,
|
||||
metaKey: true
|
||||
})
|
||||
)
|
||||
component.didMouseDownOnContent(
|
||||
Object.assign(clientPositionForCharacter(component, 1, 16), {
|
||||
detail: 2,
|
||||
button: 0,
|
||||
metaKey: true
|
||||
})
|
||||
)
|
||||
expect(editor.getSelectedScreenRanges()).toEqual([
|
||||
[[0, 0], [0, 0]],
|
||||
[[1, 13], [1, 21]]
|
||||
])
|
||||
expect(editor.testAutoscrollRequests).toEqual([])
|
||||
})
|
||||
|
||||
it('adds line selections when holding cmd or ctrl when triple-clicking', () => {
|
||||
const {component, editor} = buildComponent()
|
||||
editor.addCursorAtScreenPosition([1, 16], {autoscroll: false})
|
||||
expect(editor.getCursorScreenPositions()).toEqual([[0, 0], [1, 16]])
|
||||
|
||||
const {clientX, clientY} = clientPositionForCharacter(component, 1, 16)
|
||||
component.didMouseDownOnContent({detail: 1, button: 0, metaKey: true, clientX, clientY})
|
||||
component.didMouseDownOnContent({detail: 2, button: 0, metaKey: true, clientX, clientY})
|
||||
component.didMouseDownOnContent({detail: 3, button: 0, metaKey: true, clientX, clientY})
|
||||
|
||||
expect(editor.getSelectedScreenRanges()).toEqual([
|
||||
[[0, 0], [0, 0]],
|
||||
[[1, 0], [2, 0]]
|
||||
])
|
||||
expect(editor.testAutoscrollRequests).toEqual([])
|
||||
})
|
||||
|
||||
it('expands the last selection on shift-click', () => {
|
||||
const {component, element, editor} = buildComponent()
|
||||
|
||||
editor.setCursorScreenPosition([2, 18], {autoscroll: false})
|
||||
component.didMouseDownOnContent(Object.assign({
|
||||
detail: 1,
|
||||
button: 0,
|
||||
metaKey: true
|
||||
})
|
||||
)
|
||||
expect(editor.getCursorScreenPositions()).toEqual([[0, 0], [1, 16]])
|
||||
shiftKey: true
|
||||
}, clientPositionForCharacter(component, 1, 4)))
|
||||
expect(editor.getSelectedScreenRange()).toEqual([[1, 4], [2, 18]])
|
||||
|
||||
// remove cursor at 0, 0
|
||||
component.didMouseDownOnContent(
|
||||
Object.assign(clientPositionForCharacter(component, 0, 0), {
|
||||
component.didMouseDownOnContent(Object.assign({
|
||||
detail: 1,
|
||||
button: 0,
|
||||
metaKey: true
|
||||
})
|
||||
)
|
||||
expect(editor.getCursorScreenPositions()).toEqual([[1, 16]])
|
||||
shiftKey: true
|
||||
}, clientPositionForCharacter(component, 4, 4)))
|
||||
expect(editor.getSelectedScreenRange()).toEqual([[2, 18], [4, 4]])
|
||||
|
||||
// cmd-click cursor at 1, 16 but don't remove it because it's the last one
|
||||
component.didMouseDownOnContent(
|
||||
Object.assign(clientPositionForCharacter(component, 1, 16), {
|
||||
// reorients word-wise selections to keep the word selected regardless of
|
||||
// where the subsequent shift-click occurs
|
||||
editor.setCursorScreenPosition([2, 18], {autoscroll: false})
|
||||
editor.getLastSelection().selectWord({autoscroll: false})
|
||||
component.didMouseDownOnContent(Object.assign({
|
||||
detail: 1,
|
||||
button: 0,
|
||||
metaKey: true
|
||||
})
|
||||
)
|
||||
expect(editor.getCursorScreenPositions()).toEqual([[1, 16]])
|
||||
shiftKey: true
|
||||
}, clientPositionForCharacter(component, 1, 4)))
|
||||
expect(editor.getSelectedScreenRange()).toEqual([[1, 2], [2, 20]])
|
||||
|
||||
// cmd-clicking within a selection destroys it
|
||||
editor.addSelectionForScreenRange([[2, 10], [2, 15]], {autoscroll: false})
|
||||
expect(editor.getSelectedScreenRanges()).toEqual([
|
||||
[[1, 16], [1, 16]],
|
||||
[[2, 10], [2, 15]]
|
||||
])
|
||||
component.didMouseDownOnContent(
|
||||
Object.assign(clientPositionForCharacter(component, 2, 13), {
|
||||
component.didMouseDownOnContent(Object.assign({
|
||||
detail: 1,
|
||||
button: 0,
|
||||
metaKey: true
|
||||
})
|
||||
)
|
||||
expect(editor.getSelectedScreenRanges()).toEqual([
|
||||
[[1, 16], [1, 16]]
|
||||
])
|
||||
shiftKey: true
|
||||
}, clientPositionForCharacter(component, 3, 11)))
|
||||
expect(editor.getSelectedScreenRange()).toEqual([[2, 14], [3, 13]])
|
||||
|
||||
// ctrl-click does not add cursors on macOS
|
||||
component.didMouseDownOnContent(
|
||||
Object.assign(clientPositionForCharacter(component, 1, 4), {
|
||||
// reorients line-wise selections to keep the line selected regardless of
|
||||
// where the subsequent shift-click occurs
|
||||
editor.setCursorScreenPosition([2, 18], {autoscroll: false})
|
||||
editor.getLastSelection().selectLine(null, {autoscroll: false})
|
||||
component.didMouseDownOnContent(Object.assign({
|
||||
detail: 1,
|
||||
button: 0,
|
||||
ctrlKey: true
|
||||
})
|
||||
)
|
||||
expect(editor.getSelectedScreenRanges()).toEqual([
|
||||
[[1, 16], [1, 16]]
|
||||
])
|
||||
shiftKey: true
|
||||
}, clientPositionForCharacter(component, 1, 4)))
|
||||
expect(editor.getSelectedScreenRange()).toEqual([[1, 0], [3, 0]])
|
||||
|
||||
// ctrl-click adds cursors on platforms *other* than macOS
|
||||
component.props.platform = 'win32'
|
||||
editor.setCursorScreenPosition([1, 4], {autoscroll: false})
|
||||
component.didMouseDownOnContent(
|
||||
Object.assign(clientPositionForCharacter(component, 1, 16), {
|
||||
component.didMouseDownOnContent(Object.assign({
|
||||
detail: 1,
|
||||
button: 0,
|
||||
ctrlKey: true
|
||||
})
|
||||
)
|
||||
expect(editor.getCursorScreenPositions()).toEqual([[1, 4], [1, 16]])
|
||||
shiftKey: true
|
||||
}, clientPositionForCharacter(component, 3, 11)))
|
||||
expect(editor.getSelectedScreenRange()).toEqual([[2, 0], [4, 0]])
|
||||
|
||||
expect(editor.testAutoscrollRequests).toEqual([])
|
||||
})
|
||||
expect(editor.testAutoscrollRequests).toEqual([])
|
||||
})
|
||||
|
||||
it('adds word selections when holding cmd or ctrl when double-clicking', () => {
|
||||
const {component, editor} = buildComponent()
|
||||
editor.addCursorAtScreenPosition([1, 16], {autoscroll: false})
|
||||
expect(editor.getCursorScreenPositions()).toEqual([[0, 0], [1, 16]])
|
||||
it('expands the last selection on drag', () => {
|
||||
const {component, editor} = buildComponent()
|
||||
spyOn(component, 'handleMouseDragUntilMouseUp')
|
||||
|
||||
component.didMouseDownOnContent(
|
||||
Object.assign(clientPositionForCharacter(component, 1, 16), {
|
||||
component.didMouseDownOnContent(Object.assign({
|
||||
detail: 1,
|
||||
button: 0,
|
||||
metaKey: true
|
||||
})
|
||||
)
|
||||
component.didMouseDownOnContent(
|
||||
Object.assign(clientPositionForCharacter(component, 1, 16), {
|
||||
}, clientPositionForCharacter(component, 1, 4)))
|
||||
|
||||
{
|
||||
const {didDrag, didStopDragging} = component.handleMouseDragUntilMouseUp.argsForCall[0][0]
|
||||
didDrag(clientPositionForCharacter(component, 8, 8))
|
||||
expect(editor.getSelectedScreenRange()).toEqual([[1, 4], [8, 8]])
|
||||
didDrag(clientPositionForCharacter(component, 4, 8))
|
||||
expect(editor.getSelectedScreenRange()).toEqual([[1, 4], [4, 8]])
|
||||
didStopDragging()
|
||||
expect(editor.getSelectedScreenRange()).toEqual([[1, 4], [4, 8]])
|
||||
}
|
||||
|
||||
// Click-drag a second selection... selections are not merged until the
|
||||
// drag stops.
|
||||
component.didMouseDownOnContent(Object.assign({
|
||||
detail: 1,
|
||||
button: 0,
|
||||
metaKey: 1,
|
||||
}, clientPositionForCharacter(component, 8, 8)))
|
||||
{
|
||||
const {didDrag, didStopDragging} = component.handleMouseDragUntilMouseUp.argsForCall[1][0]
|
||||
didDrag(clientPositionForCharacter(component, 2, 8))
|
||||
expect(editor.getSelectedScreenRanges()).toEqual([
|
||||
[[1, 4], [4, 8]],
|
||||
[[2, 8], [8, 8]]
|
||||
])
|
||||
didDrag(clientPositionForCharacter(component, 6, 8))
|
||||
expect(editor.getSelectedScreenRanges()).toEqual([
|
||||
[[1, 4], [4, 8]],
|
||||
[[6, 8], [8, 8]]
|
||||
])
|
||||
didDrag(clientPositionForCharacter(component, 2, 8))
|
||||
expect(editor.getSelectedScreenRanges()).toEqual([
|
||||
[[1, 4], [4, 8]],
|
||||
[[2, 8], [8, 8]]
|
||||
])
|
||||
didStopDragging()
|
||||
expect(editor.getSelectedScreenRanges()).toEqual([
|
||||
[[1, 4], [8, 8]]
|
||||
])
|
||||
}
|
||||
})
|
||||
|
||||
it('expands the selection word-wise on double-click-drag', () => {
|
||||
const {component, editor} = buildComponent()
|
||||
spyOn(component, 'handleMouseDragUntilMouseUp')
|
||||
|
||||
component.didMouseDownOnContent(Object.assign({
|
||||
detail: 1,
|
||||
button: 0,
|
||||
}, clientPositionForCharacter(component, 1, 4)))
|
||||
component.didMouseDownOnContent(Object.assign({
|
||||
detail: 2,
|
||||
button: 0,
|
||||
metaKey: true
|
||||
})
|
||||
)
|
||||
expect(editor.getSelectedScreenRanges()).toEqual([
|
||||
[[0, 0], [0, 0]],
|
||||
[[1, 13], [1, 21]]
|
||||
])
|
||||
expect(editor.testAutoscrollRequests).toEqual([])
|
||||
})
|
||||
}, clientPositionForCharacter(component, 1, 4)))
|
||||
|
||||
it('adds line selections when holding cmd or ctrl when triple-clicking', () => {
|
||||
const {component, editor} = buildComponent()
|
||||
editor.addCursorAtScreenPosition([1, 16], {autoscroll: false})
|
||||
expect(editor.getCursorScreenPositions()).toEqual([[0, 0], [1, 16]])
|
||||
|
||||
const {clientX, clientY} = clientPositionForCharacter(component, 1, 16)
|
||||
component.didMouseDownOnContent({detail: 1, button: 0, metaKey: true, clientX, clientY})
|
||||
component.didMouseDownOnContent({detail: 2, button: 0, metaKey: true, clientX, clientY})
|
||||
component.didMouseDownOnContent({detail: 3, button: 0, metaKey: true, clientX, clientY})
|
||||
|
||||
expect(editor.getSelectedScreenRanges()).toEqual([
|
||||
[[0, 0], [0, 0]],
|
||||
[[1, 0], [2, 0]]
|
||||
])
|
||||
expect(editor.testAutoscrollRequests).toEqual([])
|
||||
})
|
||||
|
||||
it('expands the last selection on shift-click', () => {
|
||||
const {component, element, editor} = buildComponent()
|
||||
|
||||
editor.setCursorScreenPosition([2, 18], {autoscroll: false})
|
||||
component.didMouseDownOnContent(Object.assign({
|
||||
detail: 1,
|
||||
button: 0,
|
||||
shiftKey: true
|
||||
}, clientPositionForCharacter(component, 1, 4)))
|
||||
expect(editor.getSelectedScreenRange()).toEqual([[1, 4], [2, 18]])
|
||||
|
||||
component.didMouseDownOnContent(Object.assign({
|
||||
detail: 1,
|
||||
button: 0,
|
||||
shiftKey: true
|
||||
}, clientPositionForCharacter(component, 4, 4)))
|
||||
expect(editor.getSelectedScreenRange()).toEqual([[2, 18], [4, 4]])
|
||||
|
||||
// reorients word-wise selections to keep the word selected regardless of
|
||||
// where the subsequent shift-click occurs
|
||||
editor.setCursorScreenPosition([2, 18], {autoscroll: false})
|
||||
editor.getLastSelection().selectWord({autoscroll: false})
|
||||
component.didMouseDownOnContent(Object.assign({
|
||||
detail: 1,
|
||||
button: 0,
|
||||
shiftKey: true
|
||||
}, clientPositionForCharacter(component, 1, 4)))
|
||||
expect(editor.getSelectedScreenRange()).toEqual([[1, 2], [2, 20]])
|
||||
|
||||
component.didMouseDownOnContent(Object.assign({
|
||||
detail: 1,
|
||||
button: 0,
|
||||
shiftKey: true
|
||||
}, clientPositionForCharacter(component, 3, 11)))
|
||||
expect(editor.getSelectedScreenRange()).toEqual([[2, 14], [3, 13]])
|
||||
|
||||
// reorients line-wise selections to keep the word selected regardless of
|
||||
// where the subsequent shift-click occurs
|
||||
editor.setCursorScreenPosition([2, 18], {autoscroll: false})
|
||||
editor.getLastSelection().selectLine(null, {autoscroll: false})
|
||||
component.didMouseDownOnContent(Object.assign({
|
||||
detail: 1,
|
||||
button: 0,
|
||||
shiftKey: true
|
||||
}, clientPositionForCharacter(component, 1, 4)))
|
||||
expect(editor.getSelectedScreenRange()).toEqual([[1, 0], [3, 0]])
|
||||
|
||||
component.didMouseDownOnContent(Object.assign({
|
||||
detail: 1,
|
||||
button: 0,
|
||||
shiftKey: true
|
||||
}, clientPositionForCharacter(component, 3, 11)))
|
||||
expect(editor.getSelectedScreenRange()).toEqual([[2, 0], [4, 0]])
|
||||
|
||||
expect(editor.testAutoscrollRequests).toEqual([])
|
||||
})
|
||||
|
||||
it('expands the last selection on drag', () => {
|
||||
const {component, editor} = buildComponent()
|
||||
spyOn(component, 'handleMouseDragUntilMouseUp')
|
||||
|
||||
component.didMouseDownOnContent(Object.assign({
|
||||
detail: 1,
|
||||
button: 0,
|
||||
}, clientPositionForCharacter(component, 1, 4)))
|
||||
|
||||
{
|
||||
const {didDrag, didStopDragging} = component.handleMouseDragUntilMouseUp.argsForCall[0][0]
|
||||
didDrag(clientPositionForCharacter(component, 8, 8))
|
||||
expect(editor.getSelectedScreenRange()).toEqual([[1, 4], [8, 8]])
|
||||
didDrag(clientPositionForCharacter(component, 4, 8))
|
||||
expect(editor.getSelectedScreenRange()).toEqual([[1, 4], [4, 8]])
|
||||
didStopDragging()
|
||||
expect(editor.getSelectedScreenRange()).toEqual([[1, 4], [4, 8]])
|
||||
}
|
||||
|
||||
// Click-drag a second selection... selections are not merged until the
|
||||
// drag stops.
|
||||
component.didMouseDownOnContent(Object.assign({
|
||||
detail: 1,
|
||||
button: 0,
|
||||
metaKey: 1,
|
||||
}, clientPositionForCharacter(component, 8, 8)))
|
||||
{
|
||||
const {didDrag, didStopDragging} = component.handleMouseDragUntilMouseUp.argsForCall[1][0]
|
||||
didDrag(clientPositionForCharacter(component, 2, 8))
|
||||
expect(editor.getSelectedScreenRanges()).toEqual([
|
||||
[[1, 4], [4, 8]],
|
||||
[[2, 8], [8, 8]]
|
||||
])
|
||||
didDrag(clientPositionForCharacter(component, 6, 8))
|
||||
expect(editor.getSelectedScreenRanges()).toEqual([
|
||||
[[1, 4], [4, 8]],
|
||||
[[6, 8], [8, 8]]
|
||||
])
|
||||
didDrag(clientPositionForCharacter(component, 2, 8))
|
||||
expect(editor.getSelectedScreenRanges()).toEqual([
|
||||
[[1, 4], [4, 8]],
|
||||
[[2, 8], [8, 8]]
|
||||
])
|
||||
didStopDragging()
|
||||
expect(editor.getSelectedScreenRanges()).toEqual([
|
||||
[[1, 4], [8, 8]]
|
||||
])
|
||||
}
|
||||
})
|
||||
didDrag(clientPositionForCharacter(component, 0, 8))
|
||||
expect(editor.getSelectedScreenRange()).toEqual([[0, 4], [1, 5]])
|
||||
didDrag(clientPositionForCharacter(component, 2, 10))
|
||||
expect(editor.getSelectedScreenRange()).toEqual([[1, 2], [2, 13]])
|
||||
})
|
||||
|
||||
it('expands the selection word-wise on double-click-drag', () => {
|
||||
const {component, editor} = buildComponent()
|
||||
spyOn(component, 'handleMouseDragUntilMouseUp')
|
||||
it('expands the selection line-wise on triple-click-drag', () => {
|
||||
const {component, editor} = buildComponent()
|
||||
spyOn(component, 'handleMouseDragUntilMouseUp')
|
||||
|
||||
component.didMouseDownOnContent(Object.assign({
|
||||
detail: 1,
|
||||
button: 0,
|
||||
}, clientPositionForCharacter(component, 1, 4)))
|
||||
component.didMouseDownOnContent(Object.assign({
|
||||
detail: 2,
|
||||
button: 0,
|
||||
}, clientPositionForCharacter(component, 1, 4)))
|
||||
const tripleClickPosition = clientPositionForCharacter(component, 2, 8)
|
||||
component.didMouseDownOnContent(Object.assign({detail: 1, button: 0}, tripleClickPosition))
|
||||
component.didMouseDownOnContent(Object.assign({detail: 2, button: 0}, tripleClickPosition))
|
||||
component.didMouseDownOnContent(Object.assign({detail: 3, button: 0}, tripleClickPosition))
|
||||
|
||||
const {didDrag, didStopDragging} = component.handleMouseDragUntilMouseUp.argsForCall[1][0]
|
||||
didDrag(clientPositionForCharacter(component, 0, 8))
|
||||
expect(editor.getSelectedScreenRange()).toEqual([[0, 4], [1, 5]])
|
||||
didDrag(clientPositionForCharacter(component, 2, 10))
|
||||
expect(editor.getSelectedScreenRange()).toEqual([[1, 2], [2, 13]])
|
||||
})
|
||||
const {didDrag, didStopDragging} = component.handleMouseDragUntilMouseUp.argsForCall[2][0]
|
||||
didDrag(clientPositionForCharacter(component, 1, 8))
|
||||
expect(editor.getSelectedScreenRange()).toEqual([[1, 0], [3, 0]])
|
||||
didDrag(clientPositionForCharacter(component, 4, 10))
|
||||
expect(editor.getSelectedScreenRange()).toEqual([[2, 0], [5, 0]])
|
||||
})
|
||||
|
||||
it('expands the selection line-wise on triple-click-drag', () => {
|
||||
const {component, editor} = buildComponent()
|
||||
spyOn(component, 'handleMouseDragUntilMouseUp')
|
||||
it('destroys folds when clicking on their fold markers', async () => {
|
||||
const {component, element, editor} = buildComponent()
|
||||
editor.foldBufferRow(1)
|
||||
await component.getNextUpdatePromise()
|
||||
|
||||
const tripleClickPosition = clientPositionForCharacter(component, 2, 8)
|
||||
component.didMouseDownOnContent(Object.assign({detail: 1, button: 0}, tripleClickPosition))
|
||||
component.didMouseDownOnContent(Object.assign({detail: 2, button: 0}, tripleClickPosition))
|
||||
component.didMouseDownOnContent(Object.assign({detail: 3, button: 0}, tripleClickPosition))
|
||||
const target = element.querySelector('.fold-marker')
|
||||
const {clientX, clientY} = clientPositionForCharacter(component, 1, editor.lineLengthForScreenRow(1))
|
||||
component.didMouseDownOnContent({detail: 1, button: 0, target, clientX, clientY})
|
||||
expect(editor.isFoldedAtBufferRow(1)).toBe(false)
|
||||
expect(editor.getCursorScreenPosition()).toEqual([0, 0])
|
||||
})
|
||||
|
||||
const {didDrag, didStopDragging} = component.handleMouseDragUntilMouseUp.argsForCall[2][0]
|
||||
didDrag(clientPositionForCharacter(component, 1, 8))
|
||||
expect(editor.getSelectedScreenRange()).toEqual([[1, 0], [3, 0]])
|
||||
didDrag(clientPositionForCharacter(component, 4, 10))
|
||||
expect(editor.getSelectedScreenRange()).toEqual([[2, 0], [5, 0]])
|
||||
})
|
||||
it('autoscrolls the content when dragging near the edge of the scroll container', async () => {
|
||||
const {component, element, editor} = buildComponent({width: 200, height: 200})
|
||||
spyOn(component, 'handleMouseDragUntilMouseUp')
|
||||
|
||||
it('destroys folds when clicking on their fold markers', async () => {
|
||||
const {component, element, editor} = buildComponent()
|
||||
editor.foldBufferRow(1)
|
||||
await component.getNextUpdatePromise()
|
||||
let previousScrollTop = 0
|
||||
let previousScrollLeft = 0
|
||||
function assertScrolledDownAndRight () {
|
||||
expect(component.getScrollTop()).toBeGreaterThan(previousScrollTop)
|
||||
previousScrollTop = component.getScrollTop()
|
||||
expect(component.getScrollLeft()).toBeGreaterThan(previousScrollLeft)
|
||||
previousScrollLeft = component.getScrollLeft()
|
||||
}
|
||||
|
||||
const target = element.querySelector('.fold-marker')
|
||||
const {clientX, clientY} = clientPositionForCharacter(component, 1, editor.lineLengthForScreenRow(1))
|
||||
component.didMouseDownOnContent({detail: 1, button: 0, target, clientX, clientY})
|
||||
expect(editor.isFoldedAtBufferRow(1)).toBe(false)
|
||||
expect(editor.getCursorScreenPosition()).toEqual([0, 0])
|
||||
})
|
||||
function assertScrolledUpAndLeft () {
|
||||
expect(component.getScrollTop()).toBeLessThan(previousScrollTop)
|
||||
previousScrollTop = component.getScrollTop()
|
||||
expect(component.getScrollLeft()).toBeLessThan(previousScrollLeft)
|
||||
previousScrollLeft = component.getScrollLeft()
|
||||
}
|
||||
|
||||
it('autoscrolls the content when dragging near the edge of the scroll container', async () => {
|
||||
const {component, element, editor} = buildComponent({width: 200, height: 200})
|
||||
spyOn(component, 'handleMouseDragUntilMouseUp')
|
||||
component.didMouseDownOnContent({detail: 1, button: 0, clientX: 100, clientY: 100})
|
||||
const {didDrag, didStopDragging} = component.handleMouseDragUntilMouseUp.argsForCall[0][0]
|
||||
|
||||
let previousScrollTop = 0
|
||||
let previousScrollLeft = 0
|
||||
function assertScrolledDownAndRight () {
|
||||
expect(component.getScrollTop()).toBeGreaterThan(previousScrollTop)
|
||||
previousScrollTop = component.getScrollTop()
|
||||
expect(component.getScrollLeft()).toBeGreaterThan(previousScrollLeft)
|
||||
previousScrollLeft = component.getScrollLeft()
|
||||
}
|
||||
didDrag({clientX: 199, clientY: 199})
|
||||
assertScrolledDownAndRight()
|
||||
didDrag({clientX: 199, clientY: 199})
|
||||
assertScrolledDownAndRight()
|
||||
didDrag({clientX: 199, clientY: 199})
|
||||
assertScrolledDownAndRight()
|
||||
didDrag({clientX: component.getGutterContainerWidth() + 1, clientY: 1})
|
||||
assertScrolledUpAndLeft()
|
||||
didDrag({clientX: component.getGutterContainerWidth() + 1, clientY: 1})
|
||||
assertScrolledUpAndLeft()
|
||||
didDrag({clientX: component.getGutterContainerWidth() + 1, clientY: 1})
|
||||
assertScrolledUpAndLeft()
|
||||
|
||||
function assertScrolledUpAndLeft () {
|
||||
expect(component.getScrollTop()).toBeLessThan(previousScrollTop)
|
||||
previousScrollTop = component.getScrollTop()
|
||||
expect(component.getScrollLeft()).toBeLessThan(previousScrollLeft)
|
||||
previousScrollLeft = component.getScrollLeft()
|
||||
}
|
||||
// Don't artificially update scroll position beyond possible values
|
||||
expect(component.getScrollTop()).toBe(0)
|
||||
expect(component.getScrollLeft()).toBe(0)
|
||||
didDrag({clientX: component.getGutterContainerWidth() + 1, clientY: 1})
|
||||
expect(component.getScrollTop()).toBe(0)
|
||||
expect(component.getScrollLeft()).toBe(0)
|
||||
|
||||
component.didMouseDownOnContent({detail: 1, button: 0, clientX: 100, clientY: 100})
|
||||
const {didDrag, didStopDragging} = component.handleMouseDragUntilMouseUp.argsForCall[0][0]
|
||||
const maxScrollTop = component.getMaxScrollTop()
|
||||
const maxScrollLeft = component.getMaxScrollLeft()
|
||||
setScrollTop(component, maxScrollTop)
|
||||
await setScrollLeft(component, maxScrollLeft)
|
||||
|
||||
didDrag({clientX: 199, clientY: 199})
|
||||
assertScrolledDownAndRight()
|
||||
didDrag({clientX: 199, clientY: 199})
|
||||
assertScrolledDownAndRight()
|
||||
didDrag({clientX: 199, clientY: 199})
|
||||
assertScrolledDownAndRight()
|
||||
didDrag({clientX: component.getGutterContainerWidth() + 1, clientY: 1})
|
||||
assertScrolledUpAndLeft()
|
||||
didDrag({clientX: component.getGutterContainerWidth() + 1, clientY: 1})
|
||||
assertScrolledUpAndLeft()
|
||||
didDrag({clientX: component.getGutterContainerWidth() + 1, clientY: 1})
|
||||
assertScrolledUpAndLeft()
|
||||
|
||||
// Don't artificially update scroll position beyond possible values
|
||||
expect(component.getScrollTop()).toBe(0)
|
||||
expect(component.getScrollLeft()).toBe(0)
|
||||
didDrag({clientX: component.getGutterContainerWidth() + 1, clientY: 1})
|
||||
expect(component.getScrollTop()).toBe(0)
|
||||
expect(component.getScrollLeft()).toBe(0)
|
||||
|
||||
const maxScrollTop = component.getMaxScrollTop()
|
||||
const maxScrollLeft = component.getMaxScrollLeft()
|
||||
setScrollTop(component, maxScrollTop)
|
||||
await setScrollLeft(component, maxScrollLeft)
|
||||
|
||||
didDrag({clientX: 199, clientY: 199})
|
||||
didDrag({clientX: 199, clientY: 199})
|
||||
didDrag({clientX: 199, clientY: 199})
|
||||
expect(component.getScrollTop()).toBe(maxScrollTop)
|
||||
expect(component.getScrollLeft()).toBe(maxScrollLeft)
|
||||
didDrag({clientX: 199, clientY: 199})
|
||||
didDrag({clientX: 199, clientY: 199})
|
||||
didDrag({clientX: 199, clientY: 199})
|
||||
expect(component.getScrollTop()).toBe(maxScrollTop)
|
||||
expect(component.getScrollLeft()).toBe(maxScrollLeft)
|
||||
})
|
||||
})
|
||||
|
||||
it('pastes the previously selected text when clicking the middle mouse button on Linux', async () => {
|
||||
|
||||
@@ -5,7 +5,7 @@ class ContextMenu
|
||||
constructor: (template, @atomWindow) ->
|
||||
template = @createClickHandlers(template)
|
||||
menu = Menu.buildFromTemplate(template)
|
||||
menu.popup(@atomWindow.browserWindow)
|
||||
menu.popup(@atomWindow.browserWindow, {async: true})
|
||||
|
||||
# It's necessary to build the event handlers in this process, otherwise
|
||||
# closures are dragged across processes and failed to be garbage collected
|
||||
|
||||
@@ -1756,33 +1756,28 @@ class TextEditorComponent {
|
||||
}
|
||||
}
|
||||
|
||||
// On Linux, position the cursor on middle mouse button click. A
|
||||
// textInput event with the contents of the selection clipboard will be
|
||||
// dispatched by the browser automatically on mouseup.
|
||||
if (platform === 'linux' && button === 1) {
|
||||
const selection = clipboard.readText('selection')
|
||||
const screenPosition = this.screenPositionForMouseEvent(event)
|
||||
const screenPosition = this.screenPositionForMouseEvent(event)
|
||||
|
||||
// All clicks should set the cursor position, but only left-clicks should
|
||||
// have additional logic.
|
||||
// On macOS, ctrl-click brings up the context menu so also handle that case.
|
||||
if (button !== 0 || (platform === 'darwin' && ctrlKey)) {
|
||||
model.setCursorScreenPosition(screenPosition, {autoscroll: false})
|
||||
model.insertText(selection)
|
||||
|
||||
// On Linux, pasting happens on middle click. A textInput event with the
|
||||
// contents of the selection clipboard will be dispatched by the browser
|
||||
// automatically on mouseup.
|
||||
if (platform === 'linux' && button === 1) model.insertText(clipboard.readText('selection'))
|
||||
return
|
||||
}
|
||||
|
||||
// Only handle mousedown events for left mouse button (or the middle mouse
|
||||
// button on Linux where it pastes the selection clipboard).
|
||||
if (button !== 0) return
|
||||
|
||||
// Ctrl-click brings up the context menu on macOS
|
||||
if (platform === 'darwin' && ctrlKey) return
|
||||
|
||||
const screenPosition = this.screenPositionForMouseEvent(event)
|
||||
|
||||
if (target && target.matches('.fold-marker')) {
|
||||
const bufferPosition = model.bufferPositionForScreenPosition(screenPosition)
|
||||
model.destroyFoldsContainingBufferPositions([bufferPosition], false)
|
||||
return
|
||||
}
|
||||
|
||||
const addOrRemoveSelection = metaKey || (ctrlKey && platform !== 'darwin')
|
||||
const addOrRemoveSelection = metaKey || ctrlKey
|
||||
|
||||
switch (detail) {
|
||||
case 1:
|
||||
|
||||
Reference in New Issue
Block a user