From e442dfff11eeb5d641cf0ba6ee73d08290be4939 Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Thu, 4 Apr 2013 11:05:11 -0700 Subject: [PATCH] Support joining editor lines with ctrl-J This can be used with or without a selection to join one or more lines with the line below it separated by a space. Refs #134 --- spec/app/edit-session-spec.coffee | 37 +++++++++++++++++++++++++++++++ src/app/edit-session.coffee | 3 +++ src/app/editor.coffee | 2 ++ src/app/keymaps/editor.cson | 1 + src/app/selection.coffee | 25 +++++++++++++++++++++ 5 files changed, 68 insertions(+) diff --git a/spec/app/edit-session-spec.coffee b/spec/app/edit-session-spec.coffee index 523564cc4..bd4537617 100644 --- a/spec/app/edit-session-spec.coffee +++ b/spec/app/edit-session-spec.coffee @@ -2159,3 +2159,40 @@ describe "EditSession", -> expect(buffer.getMarkerCount()).toBeGreaterThan 0 editSession.destroy() expect(buffer.getMarkerCount()).toBe 0 + + describe ".joinLine()", -> + describe "when no text is selected", -> + describe "when the line below isn't empty", -> + it "joins the line below with the current line separated by a space and moves the cursor to the start of line that was moved up", -> + editSession.joinLine() + expect(editSession.lineForBufferRow(0)).toBe 'var quicksort = function () { var sort = function(items) {' + expect(editSession.getCursorBufferPosition()).toEqual [0, 30] + + describe "when the line below is empty", -> + it "deletes the line below and moves the cursor to the end of the line", -> + editSession.setCursorBufferPosition([9]) + editSession.joinLine() + expect(editSession.lineForBufferRow(9)).toBe ' };' + expect(editSession.lineForBufferRow(10)).toBe ' return sort(Array.apply(this, arguments));' + expect(editSession.getCursorBufferPosition()).toEqual [9, 4] + + describe "when the cursor is on the last row", -> + it "does nothing", -> + editSession.setCursorBufferPosition([Infinity, Infinity]) + editSession.joinLine() + expect(editSession.lineForBufferRow(12)).toBe '};' + + describe "when text is selected", -> + describe "when the selection does not span multiple lines", -> + it "joins the line below with the current line separated by a space and retains the selected text", -> + editSession.setSelectedBufferRange([[0, 1], [0, 3]]) + editSession.joinLine() + expect(editSession.lineForBufferRow(0)).toBe 'var quicksort = function () { var sort = function(items) {' + expect(editSession.getSelectedBufferRange()).toEqual [[0, 1], [0, 3]] + + describe "when the selection spans multiple lines", -> + it "joins all selected lines separated by a space and retains the selected text", -> + editSession.setSelectedBufferRange([[9, 3], [12, 1]]) + editSession.joinLine() + expect(editSession.lineForBufferRow(9)).toBe ' }; return sort(Array.apply(this, arguments)); };' + expect(editSession.getSelectedBufferRange()).toEqual [[9, 3], [9, 49]] diff --git a/src/app/edit-session.coffee b/src/app/edit-session.coffee index c72fc5302..a17c914f0 100644 --- a/src/app/edit-session.coffee +++ b/src/app/edit-session.coffee @@ -778,6 +778,9 @@ class EditSession lowerCase: -> @replaceSelectedText selectWordIfEmpty:true, (text) => text.toLowerCase() + joinLine: -> + @mutateSelectedText (selection) -> selection.joinLine() + expandLastSelectionOverLine: -> @getLastSelection().expandOverLine() diff --git a/src/app/editor.coffee b/src/app/editor.coffee index 02ad2a73e..db183a383 100644 --- a/src/app/editor.coffee +++ b/src/app/editor.coffee @@ -155,6 +155,7 @@ class Editor extends View 'editor:move-line-up': @moveLineUp 'editor:move-line-down': @moveLineDown 'editor:duplicate-line': @duplicateLine + 'editor:join-line': @joinLine 'editor:toggle-indent-guide': => config.set('editor.showIndentGuide', !config.get('editor.showIndentGuide')) 'editor:save-debug-snapshot': @saveDebugSnapshot 'editor:toggle-line-numbers': => config.set('editor.showLineNumbers', !config.get('editor.showLineNumbers')) @@ -183,6 +184,7 @@ class Editor extends View moveLineDown: -> @activeEditSession.moveLineDown() setCursorScreenPosition: (position, options) -> @activeEditSession.setCursorScreenPosition(position, options) duplicateLine: -> @activeEditSession.duplicateLine() + joinLine: -> @activeEditSession.joinLine() getCursorScreenPosition: -> @activeEditSession.getCursorScreenPosition() getCursorScreenRow: -> @activeEditSession.getCursorScreenRow() setCursorBufferPosition: (position, options) -> @activeEditSession.setCursorBufferPosition(position, options) diff --git a/src/app/keymaps/editor.cson b/src/app/keymaps/editor.cson index f9675e6c1..52522ce73 100644 --- a/src/app/keymaps/editor.cson +++ b/src/app/keymaps/editor.cson @@ -24,6 +24,7 @@ 'ctrl-meta-up': 'editor:move-line-up' 'ctrl-meta-down': 'editor:move-line-down' 'meta-D': 'editor:duplicate-line' + 'ctrl-J': 'editor:join-line' '.editor.mini': 'enter': 'core:confirm', diff --git a/src/app/selection.coffee b/src/app/selection.coffee index b4ed0f293..817769281 100644 --- a/src/app/selection.coffee +++ b/src/app/selection.coffee @@ -286,6 +286,31 @@ class Selection end-- @editSession.buffer.deleteRows(start, end) + joinLine: -> + selectedRange = @getBufferRange() + if selectedRange.isEmpty() + return if selectedRange.start.row is @editSession.buffer.getLastRow() + else + joinMarker = @editSession.markBufferRange(selectedRange, invalidationStrategy: 'never') + + rowCount = Math.max(1, selectedRange.getRowCount() - 1) + for row in [0...rowCount] + @cursor.setBufferPosition([selectedRange.start.row]) + @cursor.moveToEndOfLine() + nextRow = selectedRange.start.row + 1 + if nextRow <= @editSession.buffer.getLastRow() and @editSession.buffer.lineLengthForRow(nextRow) > 0 + @insertText(' ') + @cursor.moveToEndOfLine() + @modifySelection => + @cursor.moveRight() + @cursor.moveToFirstCharacterOfLine() + @deleteSelectedText() + + if joinMarker? + newSelectedRange = @editSession.getMarkerBufferRange(joinMarker) + @setBufferRange(newSelectedRange) + @editSession.destroyMarker(joinMarker) + outdentSelectedRows: -> [start, end] = @getBufferRowRange() buffer = @editSession.buffer