2012-01-05 23:13:55 +04:00
|
|
|
Buffer = require 'buffer'
|
2011-12-16 02:13:34 +04:00
|
|
|
Editor = require 'editor'
|
|
|
|
$ = require 'jquery'
|
2012-01-24 04:45:00 +04:00
|
|
|
_ = require 'underscore'
|
2011-12-17 02:42:38 +04:00
|
|
|
fs = require 'fs'
|
2011-12-16 02:13:34 +04:00
|
|
|
|
2012-01-24 02:37:03 +04:00
|
|
|
describe "Editor", ->
|
2012-01-17 05:17:36 +04:00
|
|
|
buffer = null
|
2011-12-17 04:25:33 +04:00
|
|
|
editor = null
|
2011-12-16 02:13:34 +04:00
|
|
|
|
|
|
|
beforeEach ->
|
2012-01-17 05:17:36 +04:00
|
|
|
buffer = new Buffer(require.resolve('fixtures/sample.js'))
|
2011-12-29 23:12:13 +04:00
|
|
|
editor = Editor.build()
|
2012-01-18 06:13:50 +04:00
|
|
|
editor.enableKeymap()
|
|
|
|
editor.setBuffer(buffer)
|
2011-12-16 02:13:34 +04:00
|
|
|
|
2012-01-17 05:17:36 +04:00
|
|
|
describe ".setBuffer", ->
|
2012-01-20 07:08:40 +04:00
|
|
|
it "creates a pre element for each line in the buffer, with the html-escaped text of the line", ->
|
2012-01-17 05:17:36 +04:00
|
|
|
expect(editor.lines.find('pre').length).toEqual(buffer.numLines())
|
2012-01-20 07:08:40 +04:00
|
|
|
expect(buffer.getLine(2)).toContain('<')
|
|
|
|
expect(editor.lines.find('pre:eq(2)').html()).toContain '<'
|
|
|
|
|
|
|
|
it "renders a non-breaking space for empty lines", ->
|
|
|
|
expect(buffer.getLine(10)).toBe ''
|
|
|
|
expect(editor.lines.find('pre:eq(10)').html()).toBe ' '
|
2012-01-11 07:16:46 +04:00
|
|
|
|
2012-01-17 05:17:36 +04:00
|
|
|
it "sets the cursor to the beginning of the file", ->
|
2012-01-26 00:20:58 +04:00
|
|
|
expect(editor.getPosition()).toEqual(row: 0, col: 0)
|
2012-01-11 07:16:46 +04:00
|
|
|
|
2012-01-18 06:13:50 +04:00
|
|
|
describe "cursor movement", ->
|
2012-01-26 00:20:58 +04:00
|
|
|
describe ".setPosition({row, col})", ->
|
|
|
|
it "moves the cursor to cover the character at the given row and column", ->
|
2012-01-25 02:21:43 +04:00
|
|
|
editor.attachToDom()
|
2012-01-26 00:20:58 +04:00
|
|
|
editor.setPosition(row: 2, col: 2)
|
2012-01-18 06:13:50 +04:00
|
|
|
|
2012-01-25 02:21:43 +04:00
|
|
|
expect(editor.cursor.position().top).toBe(2 * editor.lineHeight)
|
|
|
|
expect(editor.cursor.position().left).toBe(2 * editor.charWidth)
|
2012-01-18 06:13:50 +04:00
|
|
|
|
2012-01-25 02:21:43 +04:00
|
|
|
describe "when the arrow keys are pressed", ->
|
2012-01-26 00:20:58 +04:00
|
|
|
it "moves the cursor by a single row/column", ->
|
2012-01-25 02:21:43 +04:00
|
|
|
editor.trigger keydownEvent('right')
|
2012-01-26 00:20:58 +04:00
|
|
|
expect(editor.getPosition()).toEqual(row: 0, col: 1)
|
2012-01-18 06:13:50 +04:00
|
|
|
|
2012-01-25 02:21:43 +04:00
|
|
|
editor.trigger keydownEvent('down')
|
2012-01-26 00:20:58 +04:00
|
|
|
expect(editor.getPosition()).toEqual(row: 1, col: 1)
|
2012-01-25 02:21:43 +04:00
|
|
|
|
|
|
|
editor.trigger keydownEvent('left')
|
2012-01-26 00:20:58 +04:00
|
|
|
expect(editor.getPosition()).toEqual(row: 1, col: 0)
|
2012-01-25 02:21:43 +04:00
|
|
|
|
|
|
|
editor.trigger keydownEvent('up')
|
2012-01-26 00:20:58 +04:00
|
|
|
expect(editor.getPosition()).toEqual(row: 0, col: 0)
|
2012-01-18 06:13:50 +04:00
|
|
|
|
2012-01-24 02:56:30 +04:00
|
|
|
describe "vertical movement", ->
|
2012-01-25 02:21:43 +04:00
|
|
|
describe "auto-scrolling", ->
|
2012-01-24 05:15:11 +04:00
|
|
|
beforeEach ->
|
|
|
|
editor.attachToDom()
|
|
|
|
editor.focus()
|
|
|
|
editor.scrollMargin = 3
|
2012-01-24 04:45:00 +04:00
|
|
|
|
2012-01-24 05:15:11 +04:00
|
|
|
it "scrolls the buffer with the specified scroll margin when cursor approaches the end of the screen", ->
|
|
|
|
editor.height(editor.lineHeight * 10)
|
2012-01-24 04:45:00 +04:00
|
|
|
|
2012-01-24 05:15:11 +04:00
|
|
|
_.times 6, -> editor.moveDown()
|
|
|
|
expect(editor.scrollTop()).toBe(0)
|
2012-01-24 04:45:00 +04:00
|
|
|
|
2012-01-24 05:15:11 +04:00
|
|
|
editor.moveDown()
|
|
|
|
expect(editor.scrollTop()).toBe(editor.lineHeight)
|
|
|
|
editor.moveDown()
|
|
|
|
expect(editor.scrollTop()).toBe(editor.lineHeight * 2)
|
|
|
|
|
|
|
|
_.times 3, -> editor.moveUp()
|
|
|
|
expect(editor.scrollTop()).toBe(editor.lineHeight * 2)
|
|
|
|
|
|
|
|
editor.moveUp()
|
|
|
|
expect(editor.scrollTop()).toBe(editor.lineHeight)
|
|
|
|
|
|
|
|
editor.moveUp()
|
|
|
|
expect(editor.scrollTop()).toBe(0)
|
2012-01-24 04:45:00 +04:00
|
|
|
|
2012-01-25 02:21:43 +04:00
|
|
|
it "reduces scroll margins when there isn't enough height to maintain them and scroll smoothly", ->
|
2012-01-24 05:15:11 +04:00
|
|
|
editor.height(editor.lineHeight * 5)
|
2012-01-24 04:45:00 +04:00
|
|
|
|
2012-01-24 05:15:11 +04:00
|
|
|
_.times 3, -> editor.moveDown()
|
|
|
|
expect(editor.scrollTop()).toBe(editor.lineHeight)
|
2012-01-24 04:45:00 +04:00
|
|
|
|
2012-01-24 05:15:11 +04:00
|
|
|
editor.moveUp()
|
|
|
|
expect(editor.scrollTop()).toBe(0)
|
2012-01-24 04:45:00 +04:00
|
|
|
|
2012-01-26 00:20:58 +04:00
|
|
|
describe "goal column retention", ->
|
2012-01-24 02:56:30 +04:00
|
|
|
lineLengths = null
|
2012-01-24 01:58:26 +04:00
|
|
|
|
2012-01-24 02:56:30 +04:00
|
|
|
beforeEach ->
|
|
|
|
lineLengths = buffer.getLines().map (line) -> line.length
|
|
|
|
expect(lineLengths[3]).toBeGreaterThan(lineLengths[4])
|
|
|
|
expect(lineLengths[5]).toBeGreaterThan(lineLengths[4])
|
|
|
|
expect(lineLengths[6]).toBeGreaterThan(lineLengths[3])
|
2012-01-24 02:18:34 +04:00
|
|
|
|
2012-01-26 00:20:58 +04:00
|
|
|
it "retains the goal column when moving up", ->
|
2012-01-24 02:56:30 +04:00
|
|
|
expect(lineLengths[6]).toBeGreaterThan(32)
|
2012-01-26 00:20:58 +04:00
|
|
|
editor.setPosition(row: 6, col: 32)
|
2012-01-24 02:18:34 +04:00
|
|
|
|
2012-01-24 02:56:30 +04:00
|
|
|
editor.moveUp()
|
2012-01-26 00:20:58 +04:00
|
|
|
expect(editor.getPosition().col).toBe lineLengths[5]
|
2012-01-24 02:18:34 +04:00
|
|
|
|
2012-01-24 02:56:30 +04:00
|
|
|
editor.moveUp()
|
2012-01-26 00:20:58 +04:00
|
|
|
expect(editor.getPosition().col).toBe lineLengths[4]
|
2012-01-24 01:40:37 +04:00
|
|
|
|
2012-01-24 02:56:30 +04:00
|
|
|
editor.moveUp()
|
2012-01-26 00:20:58 +04:00
|
|
|
expect(editor.getPosition().col).toBe 32
|
2012-01-24 02:18:34 +04:00
|
|
|
|
2012-01-26 00:20:58 +04:00
|
|
|
it "retains the goal column when moving down", ->
|
|
|
|
editor.setPosition(row: 3, col: lineLengths[3])
|
2012-01-24 02:18:34 +04:00
|
|
|
|
2012-01-24 02:56:30 +04:00
|
|
|
editor.moveDown()
|
2012-01-26 00:20:58 +04:00
|
|
|
expect(editor.getPosition().col).toBe lineLengths[4]
|
2012-01-24 02:18:34 +04:00
|
|
|
|
2012-01-24 02:56:30 +04:00
|
|
|
editor.moveDown()
|
2012-01-26 00:20:58 +04:00
|
|
|
expect(editor.getPosition().col).toBe lineLengths[5]
|
2012-01-24 01:40:37 +04:00
|
|
|
|
|
|
|
editor.moveDown()
|
2012-01-26 00:20:58 +04:00
|
|
|
expect(editor.getPosition().col).toBe lineLengths[3]
|
2012-01-20 02:39:16 +04:00
|
|
|
|
2012-01-26 00:20:58 +04:00
|
|
|
it "clears the goal column when the cursor is set", ->
|
|
|
|
# set a goal column by moving down
|
|
|
|
editor.setPosition(row: 3, col: lineLengths[3])
|
2012-01-24 02:56:30 +04:00
|
|
|
editor.moveDown()
|
2012-01-26 00:20:58 +04:00
|
|
|
expect(editor.getPosition().col).not.toBe 6
|
2012-01-24 02:37:03 +04:00
|
|
|
|
2012-01-26 00:20:58 +04:00
|
|
|
# clear the goal column by explicitly setting the cursor position
|
|
|
|
editor.setColumn(6)
|
|
|
|
expect(editor.getPosition().col).toBe 6
|
2012-01-24 02:56:30 +04:00
|
|
|
|
|
|
|
editor.moveDown()
|
2012-01-26 00:20:58 +04:00
|
|
|
expect(editor.getPosition().col).toBe 6
|
2012-01-24 02:37:03 +04:00
|
|
|
|
2012-01-25 02:21:43 +04:00
|
|
|
describe "when up is pressed on the first line", ->
|
2012-01-26 00:20:58 +04:00
|
|
|
it "moves the cursor to the beginning of the line, but retains the goal column", ->
|
|
|
|
editor.setPosition(row: 0, col: 4)
|
2012-01-25 02:21:43 +04:00
|
|
|
editor.moveUp()
|
2012-01-26 00:20:58 +04:00
|
|
|
expect(editor.getPosition()).toEqual(row: 0, col: 0)
|
2012-01-20 02:39:16 +04:00
|
|
|
|
2012-01-25 02:21:43 +04:00
|
|
|
editor.moveDown()
|
2012-01-26 00:20:58 +04:00
|
|
|
expect(editor.getPosition()).toEqual(row: 1, col: 4)
|
2012-01-20 03:40:26 +04:00
|
|
|
|
2012-01-25 02:21:43 +04:00
|
|
|
describe "when down is pressed on the last line", ->
|
2012-01-26 00:20:58 +04:00
|
|
|
it "moves the cursor to the end of line, but retains the goal column", ->
|
2012-01-20 03:40:26 +04:00
|
|
|
lastLineIndex = buffer.getLines().length - 1
|
|
|
|
lastLine = buffer.getLine(lastLineIndex)
|
|
|
|
expect(lastLine.length).toBeGreaterThan(0)
|
|
|
|
|
2012-01-26 00:20:58 +04:00
|
|
|
editor.setPosition(row: lastLineIndex, col: 1)
|
2012-01-25 02:21:43 +04:00
|
|
|
editor.moveDown()
|
2012-01-26 00:20:58 +04:00
|
|
|
expect(editor.getPosition()).toEqual(row: lastLineIndex, col: lastLine.length)
|
2012-01-20 03:40:26 +04:00
|
|
|
|
2012-01-25 02:21:43 +04:00
|
|
|
editor.moveUp()
|
2012-01-26 00:20:58 +04:00
|
|
|
expect(editor.getPosition().col).toBe 1
|
2012-01-18 06:13:50 +04:00
|
|
|
|
2012-01-26 00:20:58 +04:00
|
|
|
it "retains a goal column of 0", ->
|
2012-01-25 02:21:43 +04:00
|
|
|
lastLineIndex = buffer.getLines().length - 1
|
|
|
|
lastLine = buffer.getLine(lastLineIndex)
|
|
|
|
expect(lastLine.length).toBeGreaterThan(0)
|
2012-01-17 07:23:27 +04:00
|
|
|
|
2012-01-26 00:20:58 +04:00
|
|
|
editor.setPosition(row: lastLineIndex, col: 0)
|
2012-01-25 02:21:43 +04:00
|
|
|
editor.moveDown()
|
|
|
|
editor.moveUp()
|
2012-01-26 00:20:58 +04:00
|
|
|
expect(editor.getPosition().col).toBe 0
|
2012-01-17 07:23:27 +04:00
|
|
|
|
2012-01-25 02:21:43 +04:00
|
|
|
describe "horizontal movement", ->
|
2012-01-26 00:20:58 +04:00
|
|
|
describe "when left is pressed on the first column", ->
|
2012-01-25 02:21:43 +04:00
|
|
|
describe "when there is a previous line", ->
|
|
|
|
it "wraps to the end of the previous line", ->
|
2012-01-26 00:20:58 +04:00
|
|
|
editor.setPosition(row: 1, col: 0)
|
2012-01-25 02:21:43 +04:00
|
|
|
editor.moveLeft()
|
2012-01-26 00:20:58 +04:00
|
|
|
expect(editor.getPosition()).toEqual(row: 0, col: buffer.getLine(0).length)
|
2012-01-25 02:21:43 +04:00
|
|
|
|
|
|
|
describe "when the cursor is on the first line", ->
|
|
|
|
it "remains in the same position (0,0)", ->
|
2012-01-26 00:20:58 +04:00
|
|
|
editor.setPosition(row: 0, col: 0)
|
2012-01-25 02:21:43 +04:00
|
|
|
editor.moveLeft()
|
2012-01-26 00:20:58 +04:00
|
|
|
expect(editor.getPosition()).toEqual(row: 0, col: 0)
|
2012-01-25 02:21:43 +04:00
|
|
|
|
2012-01-26 00:20:58 +04:00
|
|
|
describe "when right is pressed on the last column", ->
|
2012-01-25 02:21:43 +04:00
|
|
|
describe "when there is a subsequent line", ->
|
|
|
|
it "wraps to the beginning of the next line", ->
|
2012-01-26 00:20:58 +04:00
|
|
|
editor.setPosition(row: 0, col: buffer.getLine(0).length)
|
2012-01-25 02:21:43 +04:00
|
|
|
editor.moveRight()
|
2012-01-26 00:20:58 +04:00
|
|
|
expect(editor.getPosition()).toEqual(row: 1, col: 0)
|
2012-01-25 02:21:43 +04:00
|
|
|
|
|
|
|
describe "when the cursor is on the last line", ->
|
|
|
|
it "remains in the same position", ->
|
|
|
|
lastLineIndex = buffer.getLines().length - 1
|
|
|
|
lastLine = buffer.getLine(lastLineIndex)
|
|
|
|
expect(lastLine.length).toBeGreaterThan(0)
|
|
|
|
|
2012-01-26 00:20:58 +04:00
|
|
|
lastPosition = { row: lastLineIndex, col: lastLine.length }
|
2012-01-25 02:21:43 +04:00
|
|
|
editor.setPosition(lastPosition)
|
|
|
|
editor.moveRight()
|
|
|
|
|
|
|
|
expect(editor.getPosition()).toEqual(lastPosition)
|
2012-01-18 06:13:50 +04:00
|
|
|
|
|
|
|
describe "when the editor is attached to the dom", ->
|
|
|
|
it "updates the pixel position of the cursor", ->
|
2012-01-26 00:20:58 +04:00
|
|
|
editor.setPosition(row: 2, col: 2)
|
2012-01-18 06:13:50 +04:00
|
|
|
|
|
|
|
editor.attachToDom()
|
|
|
|
|
2012-01-24 00:50:07 +04:00
|
|
|
expect(editor.cursor.position().top).toBe(2 * editor.lineHeight)
|
|
|
|
expect(editor.cursor.position().left).toBe(2 * editor.charWidth)
|
2012-01-18 06:13:50 +04:00
|
|
|
|
2012-01-25 05:26:38 +04:00
|
|
|
it "is focused", ->
|
|
|
|
editor.attachToDom()
|
|
|
|
expect(editor).toMatchSelector ":has(:focus)"
|
|
|
|
|
2012-01-25 03:27:05 +04:00
|
|
|
describe "when the editor is focused", ->
|
|
|
|
it "focuses the hidden input", ->
|
|
|
|
editor.attachToDom()
|
|
|
|
editor.focus()
|
|
|
|
expect(editor).not.toMatchSelector ':focus'
|
|
|
|
expect(editor.hiddenInput).toMatchSelector ':focus'
|
|
|
|
|
2012-01-26 02:33:47 +04:00
|
|
|
describe "when text input events are triggered on the hidden input element", ->
|
2012-01-25 05:19:01 +04:00
|
|
|
it "inserts the typed character at the cursor position, both in the buffer and the pre element", ->
|
2012-01-26 00:20:58 +04:00
|
|
|
editor.setPosition(row: 1, col: 6)
|
2012-01-25 03:27:05 +04:00
|
|
|
|
2012-01-25 05:19:01 +04:00
|
|
|
expect(editor.getCurrentLine().charAt(6)).not.toBe 'q'
|
2012-01-25 03:27:05 +04:00
|
|
|
|
2012-01-25 05:19:01 +04:00
|
|
|
editor.hiddenInput.textInput 'q'
|
|
|
|
|
|
|
|
expect(editor.getCurrentLine().charAt(6)).toBe 'q'
|
2012-01-26 00:20:58 +04:00
|
|
|
expect(editor.getPosition()).toEqual(row: 1, col: 7)
|
2012-01-25 05:19:01 +04:00
|
|
|
expect(editor.lines.find('pre:eq(1)')).toHaveText editor.getCurrentLine()
|
2012-01-25 03:27:05 +04:00
|
|
|
|
2012-01-26 02:33:47 +04:00
|
|
|
describe "when return is pressed", ->
|
2012-01-26 01:36:32 +04:00
|
|
|
describe "when the cursor is at the beginning of a line", ->
|
|
|
|
it "inserts an empty line before it", ->
|
|
|
|
editor.setPosition(row: 1, col: 0)
|
|
|
|
|
|
|
|
editor.trigger keydownEvent('enter')
|
|
|
|
|
|
|
|
expect(editor.lines.find('pre:eq(1)')).toHaveHtml ' '
|
|
|
|
expect(editor.getPosition()).toEqual(row: 2, col: 0)
|
|
|
|
|
|
|
|
describe "when the cursor is in the middle of a line", ->
|
|
|
|
it "splits the current line to form a new line", ->
|
|
|
|
editor.setPosition(row: 1, col: 6)
|
|
|
|
|
|
|
|
originalLine = editor.lines.find('pre:eq(1)').text()
|
|
|
|
lineBelowOriginalLine = editor.lines.find('pre:eq(2)').text()
|
|
|
|
editor.trigger keydownEvent('enter')
|
|
|
|
|
|
|
|
expect(editor.lines.find('pre:eq(1)')).toHaveText originalLine[0...6]
|
|
|
|
expect(editor.lines.find('pre:eq(2)')).toHaveText originalLine[6..]
|
|
|
|
expect(editor.lines.find('pre:eq(3)')).toHaveText lineBelowOriginalLine
|
2012-01-26 05:59:15 +04:00
|
|
|
# expect(editor.getPosition()).toEqual(row: 2, col: 0)
|
2012-01-26 01:36:32 +04:00
|
|
|
|
|
|
|
describe "when the cursor is on the end of a line", ->
|
|
|
|
it "inserts an empty line after it", ->
|
|
|
|
editor.setPosition(row: 1, col: buffer.getLine(1).length)
|
|
|
|
|
|
|
|
editor.trigger keydownEvent('enter')
|
|
|
|
|
|
|
|
expect(editor.lines.find('pre:eq(2)')).toHaveHtml ' '
|
|
|
|
expect(editor.getPosition()).toEqual(row: 2, col: 0)
|
2012-01-26 04:07:04 +04:00
|
|
|
|
|
|
|
describe "when backspace is pressed", ->
|
|
|
|
describe "when the cursor is on the middle of the line", ->
|
|
|
|
it "removes the character before the cursor", ->
|
|
|
|
editor.setPosition(row: 1, col: 7)
|
|
|
|
spyOn(buffer, 'backspace').andCallThrough()
|
|
|
|
|
|
|
|
editor.trigger keydownEvent('backspace')
|
|
|
|
|
|
|
|
expect(buffer.backspace).toHaveBeenCalledWith(row: 1, col: 7)
|
|
|
|
expect(editor.lines.find('pre:eq(1)')).toHaveText buffer.getLine(1)
|
|
|
|
expect(editor.getPosition()).toEqual {row: 1, col: 6}
|
|
|
|
|