Merge remote-tracking branch 'origin/master'

Conflicts:
	src/atom/cursor.coffee
	src/atom/editor.coffee
	src/atom/selection.coffee
This commit is contained in:
Nathan Sobo
2012-02-06 12:37:26 -07:00
16 changed files with 155 additions and 56 deletions

View File

@@ -291,9 +291,36 @@ describe "Editor", ->
expect(editor.getCursorPosition()).toEqual(row: 0, column: 0)
[pageX, pageY] = window.pixelPositionForPoint(editor, [0, 8])
editor.lines.trigger mousedownEvent({pageX, pageY, originalEvent: {detail: 1}})
$(document).trigger 'mouseup'
editor.lines.trigger mousedownEvent({pageX, pageY, originalEvent: {detail: 2}})
expect(editor.getSelectedText()).toBe "quicksort"
describe "when it is clicked more then twice (tripple, quadruple, etc...)", ->
it "selects the line under the cursor", ->
expect(editor.getCursorPosition()).toEqual(row: 0, column: 0)
# Triple click
[pageX, pageY] = window.pixelPositionForPoint(editor, [1, 8])
editor.lines.trigger mousedownEvent({pageX, pageY, originalEvent: {detail: 1}})
$(document).trigger 'mouseup'
editor.lines.trigger mousedownEvent({pageX, pageY, originalEvent: {detail: 2}})
$(document).trigger 'mouseup'
editor.lines.trigger mousedownEvent({pageX, pageY, originalEvent: {detail: 3}})
expect(editor.getSelectedText()).toBe " var sort = function(items) {"
$(document).trigger 'mouseup'
# Quad click
[pageX, pageY] = window.pixelPositionForPoint(editor, [2, 3])
editor.lines.trigger mousedownEvent({pageX, pageY, originalEvent: {detail: 1}})
$(document).trigger 'mouseup'
editor.lines.trigger mousedownEvent({pageX, pageY, originalEvent: {detail: 2}})
$(document).trigger 'mouseup'
editor.lines.trigger mousedownEvent({pageX, pageY, originalEvent: {detail: 3}})
$(document).trigger 'mouseup'
editor.lines.trigger mousedownEvent({pageX, pageY, originalEvent: {detail: 4}})
expect(editor.getSelectedText()).toBe " if (items.length <= 1) return items;"
$(document).trigger 'mouseup'
describe "selection", ->
selection = null
@@ -385,12 +412,12 @@ describe "Editor", ->
expect(range.end).toEqual({row: 5, column: 27})
expect(editor.getCursorPosition()).toEqual(row: 5, column: 27)
it "creates a selection from the initial double click to mouse cursor's location ", ->
it "creates a selection from word underneath double click to mouse cursor's location ", ->
editor.attachToDom()
editor.css(position: 'absolute', top: 10, left: 10)
# double click
[pageX, pageY] = window.pixelPositionForPoint(editor, [4, 10])
[pageX, pageY] = window.pixelPositionForPoint(editor, [4, 7])
editor.lines.trigger mousedownEvent({pageX, pageY, originalEvent: {detail: 1}})
$(document).trigger 'mouseup'
editor.lines.trigger mousedownEvent({pageX, pageY, originalEvent: {detail: 2}})
@@ -400,7 +427,7 @@ describe "Editor", ->
editor.lines.trigger mousemoveEvent({pageX, pageY})
range = editor.selection.getRange()
expect(range.start).toEqual({row: 4, column: 10})
expect(range.start).toEqual({row: 4, column: 4})
expect(range.end).toEqual({row: 5, column: 27})
expect(editor.getCursorPosition()).toEqual(row: 5, column: 27)
@@ -412,7 +439,41 @@ describe "Editor", ->
editor.lines.trigger mousemoveEvent({pageX, pageY})
range = editor.selection.getRange()
expect(range.start).toEqual({row: 4, column: 10})
expect(range.start).toEqual({row: 4, column: 4})
expect(range.end).toEqual({row: 5, column: 27})
expect(editor.getCursorPosition()).toEqual(row: 5, column: 27)
it "creates a selection from line underneath triple click to mouse cursor's location ", ->
editor.attachToDom()
editor.css(position: 'absolute', top: 10, left: 10)
# double click
[pageX, pageY] = window.pixelPositionForPoint(editor, [4, 7])
editor.lines.trigger mousedownEvent({pageX, pageY, originalEvent: {detail: 1}})
$(document).trigger 'mouseup'
editor.lines.trigger mousedownEvent({pageX, pageY, originalEvent: {detail: 2}})
$(document).trigger 'mouseup'
editor.lines.trigger mousedownEvent({pageX, pageY, originalEvent: {detail: 3}})
# moving changes selection
[pageX, pageY] = window.pixelPositionForPoint(editor, [5, 27])
editor.lines.trigger mousemoveEvent({pageX, pageY})
range = editor.selection.getRange()
expect(range.start).toEqual({row: 4, column: 0})
expect(range.end).toEqual({row: 5, column: 27})
expect(editor.getCursorPosition()).toEqual(row: 5, column: 27)
# mouse up may occur outside of editor, but still need to halt selection
$(document).trigger 'mouseup'
# moving after mouse up should not change selection
[pageX, pageY] = window.pixelPositionForPoint(editor, [8, 8])
editor.lines.trigger mousemoveEvent({pageX, pageY})
range = editor.selection.getRange()
expect(range.start).toEqual({row: 4, column: 0})
expect(range.end).toEqual({row: 5, column: 27})
expect(editor.getCursorPosition()).toEqual(row: 5, column: 27)
@@ -571,7 +632,7 @@ describe "Editor", ->
describe ".clipPosition(point)", ->
it "selects the nearest valid position to the given point", ->
expect(editor.clipPosition(row: 1000, column: 0)).toEqual(row: buffer.numLines() - 1, column: 0)
expect(editor.clipPosition(row: 1000, column: 0)).toEqual(row: buffer.lastRow(), column: buffer.getLine(buffer.lastRow()).length)
expect(editor.clipPosition(row: -5, column: 0)).toEqual(row: 0, column: 0)
expect(editor.clipPosition(row: 1, column: 10000)).toEqual(row: 1, column: buffer.getLine(1).length)
expect(editor.clipPosition(row: 1, column: -5)).toEqual(row: 1, column: 0)

View File

@@ -184,7 +184,8 @@ describe "Selection", ->
selection.selectWord()
expect(selection.getText()).toBe ''
describe ".selectLine(row)", ->
it "selects the entire line at given row", ->
editor.setCursorPosition [0,2]
selection.selectLine(1)
expect(selection.getText()).toBe " var sort = function(items) {"

View File

@@ -1,7 +1,7 @@
Editor = require 'editor'
VimMode = require 'vim-mode'
describe "VimMode", ->
fdescribe "VimMode", ->
editor = null
beforeEach ->
@@ -37,13 +37,20 @@ describe "VimMode", ->
describe "the x keybinding", ->
it "deletes a charachter", ->
editor.buffer.setText("12345")
editor.setCursorPosition([0, 1])
editor.buffer.setText("012345")
editor.setCursorPosition([0, 4])
editor.trigger keydownEvent('x')
expect(editor.buffer.getText()).toBe '01235'
expect(editor.getCursorPosition()).toEqual([0, 4])
expect(editor.buffer.getText()).toBe '1345'
expect(editor.getCursorPosition()).toEqual([0, 1])
editor.trigger keydownEvent('x')
expect(editor.buffer.getText()).toBe '0123'
expect(editor.getCursorPosition()).toEqual([0, 3])
editor.trigger keydownEvent('x')
expect(editor.buffer.getText()).toBe '012'
expect(editor.getCursorPosition()).toEqual([0, 2])
describe "the d keybinding", ->
describe "when followed by a d", ->
@@ -53,11 +60,18 @@ describe "VimMode", ->
editor.trigger keydownEvent('d')
editor.trigger keydownEvent('d')
expect(editor.buffer.getText()).toBe "12345\nABCDE"
expect(editor.getCursorPosition()).toEqual([1,0])
describe "when the second d is prefixed by a count", ->
it "deletes the last line", ->
editor.buffer.setText("12345\nabcde\nABCDE")
editor.setCursorPosition([2,1])
editor.trigger keydownEvent('d')
editor.trigger keydownEvent('d')
expect(editor.buffer.getText()).toBe "12345\nabcde"
expect(editor.getCursorPosition()).toEqual([1,0])
xdescribe "when the second d is prefixed by a count", ->
it "deletes n lines, starting from the current", ->
editor.buffer.setText("12345\nabcde\nABCDE\nQWERT")
editor.setCursorPosition([1,1])
@@ -135,11 +149,11 @@ describe "VimMode", ->
describe "the l keybinding", ->
it "moves the cursor right, but not to the next line", ->
editor.setCursorPosition([1,4])
editor.setCursorPosition([1,3])
editor.trigger keydownEvent('l')
expect(editor.getCursorPosition()).toEqual([1,5])
expect(editor.getCursorPosition()).toEqual([1,4])
editor.trigger keydownEvent('l')
expect(editor.getCursorPosition()).toEqual([1,5])
expect(editor.getCursorPosition()).toEqual([1,4])
describe "the w keybinding", ->
it "moves the cursor to the beginning of the next word", ->

View File

@@ -22,8 +22,8 @@ jasmine.Env.prototype.equals_ = _.isEqual
emitObject = jasmine.StringPrettyPrinter.prototype.emitObject
jasmine.StringPrettyPrinter.prototype.emitObject = (obj) ->
if obj.toString
@append obj.toString()
if obj.inspect
@append obj.inspect()
else
emitObject.call(this, obj)

View File

@@ -41,6 +41,9 @@ class Buffer
getLine: (row) ->
@lines[row]
getLineLength: (row) ->
@lines[row].length
numLines: ->
@getLines().length
@@ -50,6 +53,15 @@ class Buffer
lastLine: ->
@getLine(@lastRow())
deleteRow: (row) ->
range = null
if row == @lastRow()
range = new Range([row - 1, @getLineLength(row - 1)], [row, @getLineLength(row)])
else
range = new Range([row, 0], [row + 1, 0])
@change(range, '')
insert: (point, text) ->
@change(new Range(point, point), text)

View File

@@ -28,13 +28,13 @@ class Cursor extends View
getPosition: -> _.clone(@point)
getColumn: ->
@getPosition().column
setColumn: (column) ->
{ row } = @getPosition()
@setPosition {row, column}
getColumn: ->
@getPosition().column
getRow: ->
@getPosition().row

View File

@@ -44,8 +44,8 @@ class Editor extends View
'shift-up': 'select-up'
'shift-down': 'select-down'
enter: 'newline'
backspace: 'delete-left'
delete: 'delete-right'
backspace: 'backspace'
delete: 'delete'
'meta-x': 'cut'
'meta-c': 'copy'
'meta-v': 'paste'
@@ -59,8 +59,8 @@ class Editor extends View
@on 'select-up', => @selectUp()
@on 'select-down', => @selectDown()
@on 'newline', => @insertNewline()
@on 'delete-left', => @deleteLeft()
@on 'delete-right', => @deleteRight()
@on 'backspace', => @backspace()
@on 'delete', => @delete()
@on 'cut', => @cutSelection()
@on 'copy', => @copySelection()
@on 'paste', => @paste()
@@ -82,10 +82,12 @@ class Editor extends View
if clickCount == 1
@setCursorPosition @pointFromMouseEvent(e)
@selectTextOnMouseMovement()
else if clickCount == 2
@selection.selectWord()
@selectTextOnMouseMovement()
else if clickCount >= 3
@selection.selectLine(@getCursorRow())
@selectTextOnMouseMovement()
@hiddenInput.on "textInput", (e) =>
@insertText(e.originalEvent.data)
@@ -158,8 +160,13 @@ class Editor extends View
@lines.find("pre.line:eq(#{row})")
clipPosition: ({row, column}) ->
row = Math.min(Math.max(0, row), @buffer.numLines() - 1)
column = Math.min(Math.max(0, column), @buffer.getLine(row).length)
if row > @buffer.lastRow()
row = @buffer.lastRow()
column = @buffer.getLine(row).length
else
row = Math.min(Math.max(0, row), @buffer.numLines() - 1)
column = Math.min(Math.max(0, column), @buffer.getLine(row).length)
new Point(row, column)
pixelPositionFromPoint: ({row, column}) ->
@@ -223,11 +230,11 @@ class Editor extends View
copySelection: -> @selection.copy()
paste: -> @selection.insertText(atom.native.readFromPasteboard())
deleteLeft: ->
backspace: ->
@selectLeft() if @selection.isEmpty()
@selection.delete()
deleteRight: ->
delete: ->
@selectRight() if @selection.isEmpty()
@selection.delete()

View File

@@ -19,7 +19,7 @@ class Point
else
@row == other.row and @column == other.column
toString: ->
inspect: ->
"(#{@row}, #{@column})"
compare: (other) ->

View File

@@ -17,7 +17,7 @@ class Range
copy: (range) ->
new Range(_.clone(@start), _.clone(@end))
toString: ->
inpsect: ->
"[#{@start.toString()} - #{@end.toString()}]"
isEmpty: ->

View File

@@ -113,6 +113,10 @@ class Selection extends View
range = new Range([row, column + startOffset], [row, column + endOffset])
@setRange range
selectLine: (row) ->
rowLength = @editor.buffer.getLine(row).length
@setRange new Range([row, 0], [row, rowLength])
selectRight: ->
@modifySelection =>
@cursor.moveRight()

View File

@@ -10,6 +10,8 @@ class VimMode
opStack: null
constructor: (@editor) ->
requireStylesheet 'vim-mode.css'
@opStack = []
@editor.addClass('command-mode')
@@ -76,14 +78,15 @@ class VimMode
@pushOperator(new operators.NumericPrefix(num))
delete: () ->
if @isDeletePending()
@pushOperator(new motions.SelectLines(@editor))
if deleteOperation = @isDeletePending()
deleteOperation.complete = true
@processOpStack()
else
@pushOperator(new operators.Delete(@editor))
isDeletePending: () ->
for op in @opStack
return true if op instanceof operators.Delete
return op if op instanceof operators.Delete
false
pushOperator: (op) ->

View File

@@ -4,7 +4,10 @@ class Command
class DeleteRight extends Command
execute: ->
@editor.deleteRight()
@editor.delete()
isOnEOL = @editor.getCursorColumn() == @editor.getCurrentLine().length
if isOnEOL
@editor.setCursorColumn(@editor.getCursorColumn() - 1)
module.exports = { DeleteRight }

View File

@@ -17,8 +17,8 @@ class MoveLeft extends Motion
class MoveRight extends Motion
execute: ->
{column, row} = @editor.getCursorPosition()
currentLineLength = @editor.buffer.getLine(row).length
@editor.moveCursorRight() if column < currentLineLength
isOnLastCharachter = @editor.getCursorColumn() == @editor.getCurrentLine().length - 1
@editor.moveCursorRight() unless isOnLastCharachter
class MoveUp extends Motion
execute: ->
@@ -55,16 +55,4 @@ class MoveToNextWord extends Motion
column = nextLineMatch?.index or 0
{ row, column }
class SelectLines extends Motion
count: null
constructor: (@editor) ->
@count = 1
setCount: (@count) ->
select: ->
@editor.setCursorPosition(column: 0, row: @editor.getCursorRow())
@editor.selectToPosition(column: 0, row: @editor.getCursorRow() + @count)
module.exports = { MoveLeft, MoveRight, MoveUp, MoveDown, MoveToNextWord, SelectLines }
module.exports = { MoveLeft, MoveRight, MoveUp, MoveDown, MoveToNextWord }

View File

@@ -39,7 +39,8 @@ class Delete
@motion.select()
@editor.getSelection().delete()
else
@editor.deleteLine()
@editor.buffer.deleteRow(@editor.getCursorRow())
@editor.setCursorPosition([@editor.getCursorRow(), 0])
compose: (motion) ->
@motion = motion

View File

@@ -8,6 +8,7 @@
overflow-y: scroll;
overflow-x: auto;
cursor: default;
-webkit-user-select: none;
}
.editor pre {

4
static/vim-mode.css Normal file
View File

@@ -0,0 +1,4 @@
.editor.command-mode .cursor {
border-left: 0;
background-color: #9dff9d;
}