diff --git a/spec/app/edit-session-spec.coffee b/spec/app/edit-session-spec.coffee index 1ea895b21..e00e05718 100644 --- a/spec/app/edit-session-spec.coffee +++ b/spec/app/edit-session-spec.coffee @@ -10,7 +10,7 @@ describe "EditSession", -> tabText: ' ' buffer = new Buffer(require.resolve('fixtures/sample.js')) - editSession = new EditSession(fakeEditor, buffer) + editSession = new EditSession(editor: fakeEditor, buffer: buffer, autoIndent: false) lineLengths = buffer.getLines().map (line) -> line.length describe "cursor movement", -> @@ -404,4 +404,87 @@ describe "EditSession", -> editSession.setCursorScreenPosition([3, 3]) expect(selection.isEmpty()).toBeTruthy() + describe "buffer manipulation", -> + describe ".insertText(text)", -> + describe "when there are multiple empty selections", -> + it "inserts the given text at the location of each cursor and moves the cursors to the end of each cursor's inserted text", -> + editSession.setCursorScreenPosition([1, 2]) + editSession.addCursorAtScreenPosition([2, 4]) + + editSession.insertText('xxx') + + expect(buffer.lineForRow(1)).toBe ' xxxvar sort = function(items) {' + expect(buffer.lineForRow(2)).toBe ' xxxif (items.length <= 1) return items;' + [cursor1, cursor2] = editSession.getCursors() + + expect(cursor1.getBufferPosition()).toEqual [1, 5] + expect(cursor2.getBufferPosition()).toEqual [2, 7] + + describe "when there are multiple non-empty selections", -> + it "replaces each selection with the given text, clears the selections, and places the cursor at the end of each selection's inserted text", -> + editSession.setSelectedBufferRanges([[[1, 0], [1, 2]], [[2, 0], [2, 4]]]) + + editSession.insertText('xxx') + + expect(buffer.lineForRow(1)).toBe 'xxxvar sort = function(items) {' + expect(buffer.lineForRow(2)).toBe 'xxxif (items.length <= 1) return items;' + [selection1, selection2] = editSession.getSelections() + + expect(selection1.isEmpty()).toBeTruthy() + expect(selection1.cursor.getBufferPosition()).toEqual [1, 3] + expect(selection2.isEmpty()).toBeTruthy() + expect(selection2.cursor.getBufferPosition()).toEqual [2, 3] + + describe ".insertNewline()", -> + describe "when the cursor is at the beginning of a line", -> + it "inserts an empty line before it", -> + editSession.setCursorScreenPosition(row: 1, column: 0) + + editSession.insertNewline() + + expect(buffer.lineForRow(1)).toBe '' + expect(editSession.getCursorScreenPosition()).toEqual(row: 2, column: 0) + + describe "when the cursor is in the middle of a line", -> + it "splits the current line to form a new line", -> + editSession.setCursorScreenPosition(row: 1, column: 6) + originalLine = buffer.lineForRow(1) + lineBelowOriginalLine = buffer.lineForRow(2) + + editSession.insertNewline() + + expect(buffer.lineForRow(1)).toBe originalLine[0...6] + expect(buffer.lineForRow(2)).toBe originalLine[6..] + expect(buffer.lineForRow(3)).toBe lineBelowOriginalLine + expect(editSession.getCursorScreenPosition()).toEqual(row: 2, column: 0) + + describe "when the cursor is on the end of a line", -> + it "inserts an empty line after it", -> + editSession.setCursorScreenPosition(row: 1, column: buffer.lineForRow(1).length) + + editSession.insertNewline() + + expect(buffer.lineForRow(2)).toBe '' + expect(editSession.getCursorScreenPosition()).toEqual(row: 2, column: 0) + + describe ".insertNewlineBelow()", -> + it "inserts a newline below the cursor's current line, autoindents it, and moves the cursor to the end of the line", -> + editSession.setAutoIndent(true) + editSession.insertNewlineBelow() + expect(buffer.lineForRow(0)).toBe "var quicksort = function () {" + expect(buffer.lineForRow(1)).toBe " " + expect(editSession.getCursorBufferPosition()).toEqual [1, 2] + + describe "when the buffer is changed (via its direct api, rather than via than edit session)", -> + it "moves the cursor so it is in the same relative position of the buffer", -> + expect(editSession.getCursorScreenPosition()).toEqual [0, 0] + editSession.addCursorAtScreenPosition([0, 5]) + editSession.addCursorAtScreenPosition([1, 0]) + [cursor1, cursor2, cursor3] = editSession.getCursors() + + buffer.insert([0, 1], 'abc') + + expect(cursor1.getScreenPosition()).toEqual [0, 0] + expect(cursor2.getScreenPosition()).toEqual [0, 8] + expect(cursor3.getScreenPosition()).toEqual [1, 0] diff --git a/spec/app/editor-spec.coffee b/spec/app/editor-spec.coffee index 52213fa45..3fcf69ab6 100644 --- a/spec/app/editor-spec.coffee +++ b/spec/app/editor-spec.coffee @@ -31,7 +31,7 @@ describe "Editor", -> $('#jasmine-content').append(this) editor.lineOverdraw = 2 - editor.autoIndent = false + editor.setAutoIndent(false) editor.enableKeymap() editor.isFocused = true @@ -899,11 +899,6 @@ describe "Editor", -> it "moves the cursor to the character at the given row and column", -> expect(editor.find('.cursor').position()).toEqual(top: 2 * editor.lineHeight, left: 2 * editor.charWidth) - describe "if soft-wrap is enabled", -> - beforeEach -> - setEditorWidthInChars(editor, 20) - editor.setSoftWrap(true) - describe "when a mousedown event occurs in the editor", -> beforeEach -> editor.attachToDom() @@ -1161,7 +1156,7 @@ describe "Editor", -> describe "when editing a line that spans multiple screen lines", -> beforeEach -> editor.setSoftWrap(true, 50) - editor.autoIndent = true + editor.setAutoIndent(true) describe "when newline is inserted", -> it "indents cursor based on the indentation of previous buffer line", -> @@ -1736,63 +1731,6 @@ describe "Editor", -> expect(editor.getCursorScreenPosition()).toEqual(row: 1, column: 7) expect(editor.renderedLines.find('.line:eq(1)')).toHaveText buffer.lineForRow(1) - it "does not update the cursor position if the editor is not focused", -> - editor.isFocused = false - editor.buffer.insert([5, 0], 'blah') - expect(editor.getCursorScreenPosition()).toEqual [0, 0] - - describe "when there is a selection", -> - it "replaces the selected text with the typed text", -> - editor.setSelectionBufferRange(new Range([1, 6], [2, 4])) - editor.hiddenInput.textInput 'q' - expect(buffer.lineForRow(1)).toBe ' var qif (items.length <= 1) return items;' - - it "always places the cursor after the selection", -> - editor.setSelectionBufferRange(new Range([1, 6], [2, 4]), reverse: true) - editor.hiddenInput.textInput 'q' - expect(buffer.lineForRow(1)).toBe ' var qif (items.length <= 1) return items;' - expect(editor.getCursorScreenPosition()).toEqual [1, 7] - - describe "return", -> - describe "when the cursor is at the beginning of a line", -> - it "inserts an empty line before it", -> - editor.setCursorScreenPosition(row: 1, column: 0) - - editor.trigger keydownEvent('enter') - - expect(editor.renderedLines.find('.line:eq(1)')).toHaveHtml ' ' - expect(editor.getCursorScreenPosition()).toEqual(row: 2, column: 0) - - describe "when the cursor is in the middle of a line", -> - it "splits the current line to form a new line", -> - editor.setCursorScreenPosition(row: 1, column: 6) - - originalLine = editor.renderedLines.find('.line:eq(1)').text() - lineBelowOriginalLine = editor.renderedLines.find('.line:eq(2)').text() - editor.trigger keydownEvent('enter') - - expect(editor.renderedLines.find('.line:eq(1)')).toHaveText originalLine[0...6] - expect(editor.renderedLines.find('.line:eq(2)')).toHaveText originalLine[6..] - expect(editor.renderedLines.find('.line:eq(3)')).toHaveText lineBelowOriginalLine - expect(editor.getCursorScreenPosition()).toEqual(row: 2, column: 0) - - describe "when the cursor is on the end of a line", -> - it "inserts an empty line after it", -> - editor.setCursorScreenPosition(row: 1, column: buffer.lineForRow(1).length) - - editor.trigger keydownEvent('enter') - - expect(editor.renderedLines.find('.line:eq(2)')).toHaveHtml ' ' - expect(editor.getCursorScreenPosition()).toEqual(row: 2, column: 0) - - describe "insert-newline-below", -> - it "inserts a newline below the cursor, autoindents it, and moves the cursor to the end of the line", -> - editor.autoIndent = true - editor.trigger "newline-below" - expect(editor.buffer.lineForRow(0)).toBe "var quicksort = function () {" - expect(editor.buffer.lineForRow(1)).toBe " " - expect(editor.getCursorBufferPosition()).toEqual [1,2] - describe "backspace", -> describe "when the cursor is on the middle of the line", -> it "removes the character before the cursor", -> @@ -1954,7 +1892,7 @@ describe "Editor", -> describe "if editor.softTabs is false", -> it "inserts a tab character into the buffer", -> - editor.softTabs = false + editor.setSoftTabs(false) expect(buffer.lineForRow(0)).not.toMatch(/^\t/) editor.trigger 'tab' expect(buffer.lineForRow(0)).toMatch(/^\t/) diff --git a/spec/app/selection-spec.coffee b/spec/app/selection-spec.coffee index 21cdb6146..454989661 100644 --- a/spec/app/selection-spec.coffee +++ b/spec/app/selection-spec.coffee @@ -332,7 +332,7 @@ describe "Selection", -> describe "auto indent/outdent", -> beforeEach -> - editor.autoIndent = true + editor.setAutoIndent(true) describe "when editing a line that spans a single screen line", -> describe "when a newline is inserted", -> diff --git a/src/app/edit-session.coffee b/src/app/edit-session.coffee index 5731eed1e..b1c0906e4 100644 --- a/src/app/edit-session.coffee +++ b/src/app/edit-session.coffee @@ -12,7 +12,12 @@ class EditSession @deserialize: (state, editor, rootView) -> buffer = Buffer.deserialize(state.buffer, rootView.project) - session = new EditSession(editor, buffer) + session = new EditSession( + editor: editor + buffer: buffer + autoIndent: editor.autoIndent + softTabs: editor.softTabs + ) session.setScrollTop(state.scrollTop) session.setScrollLeft(state.scrollLeft) session.setCursorScreenPosition(state.cursorScreenPosition) @@ -23,8 +28,10 @@ class EditSession renderer: null cursors: null selections: null + autoIndent: true + softTabs: true - constructor: (@editor, @buffer) -> + constructor: ({@editor, @buffer, @autoIndent}) -> @id = @constructor.idCounter++ @tabText = @editor.tabText @renderer = new Renderer(@buffer, { softWrapColumn: @editor.calcSoftWrapColumn(), tabText: @editor.tabText }) @@ -66,8 +73,8 @@ class EditSession setScrollLeft: (@scrollLeft) -> getScrollLeft: -> @scrollLeft - autoIndentEnabled: -> - @editor.autoIndent + setAutoIndent: (@autoIndent) -> + setSoftTabs: (@softTabs) -> screenPositionForBufferPosition: (bufferPosition, options) -> @renderer.screenPositionForBufferPosition(bufferPosition, options) @@ -102,6 +109,22 @@ class EditSession insertText: (text) -> @mutateSelectedText (selection) -> selection.insertText(text) + insertNewline: -> + @insertText('\n') + + insertNewlineBelow: -> + @moveCursorToEndOfLine() + @insertNewline() + + insertTab: -> + if @getSelection().isEmpty() + if @softTabs + @insertText(@tabText) + else + @insertText('\t') + else + @activeEditSession.indentSelectedRows() + backspace: -> @mutateSelectedText (selection) -> selection.backspace() diff --git a/src/app/editor.coffee b/src/app/editor.coffee index 8fbb3ae40..0e0922297 100644 --- a/src/app/editor.coffee +++ b/src/app/editor.coffee @@ -40,7 +40,7 @@ class Editor extends View selectionViews: null buffer: null renderer: null - autoIndent: null + autoIndent: true lineCache: null isFocused: false softTabs: true @@ -63,7 +63,6 @@ class Editor extends View @id = Editor.idCounter++ @lineCache = [] @bindKeys() - @autoIndent = true @handleEvents() @cursorViews = [] @selectionViews = [] @@ -315,6 +314,12 @@ class Editor extends View else element.removeClass('selected') + setAutoIndent: (@autoIndent) -> + @activeEditSession.setAutoIndent(@autoIndent) + + setSoftTabs: (@softTabs) -> + @activeEditSession.setSoftTabs(@softTabs) + getScreenLines: -> @renderer.getLines() @@ -346,7 +351,7 @@ class Editor extends View index = @editSessionIndexForBuffer(buffer) unless index? index = @editSessions.length - @editSessions.push(new EditSession(this, buffer)) + @editSessions.push(new EditSession(editor: this, buffer: buffer, autoIndent: @autoIndent, softTabs: @softTabs)) @setActiveEditSessionIndex(index) @@ -726,6 +731,12 @@ class Editor extends View delete: -> @activeEditSession.delete() deleteToEndOfWord: -> @activeEditSession.deleteToEndOfWord() cutToEndOfLine: -> @activeEditSession.cutToEndOfLine() + insertText: (text) -> @activeEditSession.insertText(text) + insertNewline: -> @activeEditSession.insertNewline() + insertNewlineBelow: -> @activeEditSession.insertNewlineBelow() + insertTab: -> @activeEditSession.insertTab() + indentSelectedRows: -> @activeEditSession.indentSelectedRows() + outdentSelectedRows: -> @activeEditSession.outdentSelectedRows() setText: (text) -> @buffer.setText(text) getText: -> @buffer.getText() @@ -738,27 +749,6 @@ class Editor extends View scanInRange: (args...) -> @buffer.scanInRange(args...) backwardsScanInRange: (args...) -> @buffer.backwardsScanInRange(args...) - insertText: (text) -> - @activeEditSession.insertText(text) - - insertNewline: -> - @insertText('\n') - - insertNewlineBelow: -> - @moveCursorToEndOfLine() - @insertNewline() - - insertTab: -> - if @getSelection().isEmpty() - if @softTabs - @insertText(@tabText) - else - @insertText('\t') - else - @activeEditSession.indentSelectedRows() - - indentSelectedRows: -> @activeEditSession.indentSelectedRows() - outdentSelectedRows: -> @activeEditSession.outdentSelectedRows() cutSelection: -> @activeEditSession.cut() copySelection: -> @activeEditSession.copy() diff --git a/src/app/selection.coffee b/src/app/selection.coffee index 4fd40dee6..fe2d16abe 100644 --- a/src/app/selection.coffee +++ b/src/app/selection.coffee @@ -188,7 +188,7 @@ class Selection @cursor.setBufferPosition([range.end.row + 1, 0]) autoIndentText: (text) -> - if @editSession.autoIndentEnabled() + if @editSession.autoIndent mode = @editSession.getCurrentMode() row = @cursor.getCurrentScreenRow() state = @editSession.stateForScreenRow(row)